【iOS Sharing #04】2019-04-13

404 阅读3分钟

iOS Sharing 系列

目录

1、请用一句话概述分类的概念,并阐述分类的优点。

2、多个同宿主分类中的都重写了一个同名方法,哪个分类的同名方法会生效?为什么?

3、@property(copy)NSMutableArray *array这样声明属性会出现什么问题?

4、说一说KVO在重写NSKVONotifying对象的setter方法中,添加了哪两个关键方法?

5、如何实现一个完整的单例?


1、请用一句话概述分类的概念,并阐述分类的优点。

答:

概述:Objective-C中的分类是修饰模式的一种具体实现,主要作用是在不改变原有类的基础上,动态的为类扩展功能(添加方法)。

分类的优点

  • 声明私有方法
  • 分解庞大的类文件
  • 将Framework私有方法公开化
  • 模拟多继承

2、多个同宿主分类中的都重写了一个同名方法,哪个分类的同名方法会生效?为什么?

答:

运行时在处理分类时会倒序遍历分类数组,最先访问最后编译的类,最后编译的类的同名方法最终生效。

下面我们来看看源码解析:

int mcount = 0; // 记录方法的数量
int propcount = 0; // 记录属性的数量
int protocount = 0; // 记录协议的数量
int i = cats->count; // 获取分类个数
bool fromBundle = NO; // 记录是否是从 bundle 中取的

while (i--) { // 从后往前遍历,保证先取最后编译的类
    auto&; 
    entry = cats->list[i]; // 分类,locstamped_category_t 类型
    
    // 取出分类中的方法列表;如果是元类,取得的是类方法列表;否则取得的是实例方法列表
    method_list_t *mlist = entry.cat->methodsForMeta(isMeta);
    if (mlist) {
        mlists[mcount++] = mlist; // 将方法列表放入 mlists 方法列表数组中
        fromBundle |= entry.hi->isBundle(); // 分类的头部信息中存储了是否是 bundle,将其记住
    }

    // 取出分类中的属性列表,如果是元类,取得是nil
    property_list_t *proplist = entry.cat->propertiesForMeta(isMeta);
    if (proplist) {
        proplists[propcount++] = proplist; // 将属性列表放入 proplists 属性列表数组中
    }

    // 取出分类中遵循的协议列表
    protocol_list_t *protolist = entry.cat->protocols;
    if (protolist) {
        protolists[protocount++] = protolist; // 将协议列表放入 protolists 协议列表数组中
    }
} 

3、@property(copy)NSMutableArray *array这样声明属性会出现什么问题?

答:
  • NSMutableArray经过copy修饰后是NSArray(不可变数组)。如果对经copy修饰后的可变数组进行增删改的操作,实际上是在操作不可变数组,从而会引起程序异常,引起Crash。
  • 不写原子性修饰词默认使用atomic,而atomic性能比nonatomic差很多。

扩展:

浅拷贝:指针拷贝,不生成新对象

  • 不可变对象的不可变拷贝
NSArray *array = [NSArray array];

//相同地址        
NSLog(@"%p",array);
NSLog(@"%p",[array copy]);

// __NSArray0 (不可变数组)      
NSLog(@"%@",NSStringFromClass([[array copy] class]));

输出:

在这里插入图片描述


深拷贝:生成一个新对象,对象内容相同( 除浅拷贝那种情况,其他都是深拷贝)

  • 可变对象的可变拷贝
NSMutableArray *mutArray = [NSMutableArray array];

//输出不同地址   
NSLog(@"%p",mutArray);
NSLog(@"%p",[mutArray mutableCopy]);

// __NSArrayM (可变数组)
NSLog(@"%@",NSStringFromClass([[mutArray mutableCopy] class]));

输出:

在这里插入图片描述

  • 可变对象的不可变拷贝
NSMutableArray *mutArray = [NSMutableArray array];
//不同地址      
NSLog(@"%p",mutArray);
NSLog(@"%p",[mutArray copy]);

// __NSArray0
NSLog(@"%@",NSStringFromClass([[mutArray copy] class]));

输出:

在这里插入图片描述

  • 不可变对象的可变拷贝
NSArray *array = [NSArray array];

//不同对象  
NSLog(@"%p",array);
NSLog(@"%p",[array mutableCopy]);
// __NSArrayM    
NSLog(@"%@",NSStringFromClass([[array mutableCopy] class]));

输出:

在这里插入图片描述


总结:

除不可变对象的不可变拷贝为浅拷贝,其余都是深拷贝

在这里插入图片描述


4、说一说KVO在重写NSKVONotifying对象的setter方法中,添加了哪两个关键方法?

答:
-(void)willChangeValueForKey:(NSString *)key;
-(void)didChangeValueForKey:(NSString *)key;

5、如何实现一个完整的单例?

答:
#import "SingletonSample.h"

@interface SingletonSample()<NSCopying>

@end

@implementation SingletonSample
+(instancetype)sharedInstance
{
    static SingletonSample *instance = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        instance = [[super allocWithZone:NULL] init];
    });
    
    return instance;
}

+(instancetype)allocWithZone:(struct _NSZone *)zone
{
    return [self sharedInstance];
}

-(id)copyWithZone:(NSZone *)zone
{
    return self;
}

@end

仓库

本篇相关代码


联系方式

邮箱: adrenine@163.com

邮箱: holaux@gmail.com

邮箱: ledahapple@icloud.com