MG--iOS基础知识复习(持续更新中……)
-
@synthesize与@dynamic
-
@property有两个对应的词,一个是 @synthesize,一个是 @dynamic。如果 @synthesize和 @dynamic都没写,那么默认的就是@syntheszie var = _var;
-
1.@dynamic关键字。
这个关键字有两个作用:
1、让编译器不要创建实现属性所用的实例变量;
2、让编译器不要创建该属性的getter和setter方法。
@dynamic 告诉编译器:属性的 setter 与 getter 方法由用户自己实现,不自动生成。(当然对于 readonly 的属性只需提供 getter 即可)。假如一个属性被声明为 @dynamic var,然后你没有提供 @setter方法和 @getter 方法,编译的时候没问题,但是当程序运行到 instance.var = someVar,由于缺 setter 方法会导致程序崩溃;或者当运行到 someVar = var 时,由于缺 getter 方法同样会导致崩溃。编译时没问题,运行时才执行相应的方法,这就是所谓的动态绑定.
2.@ synthesize关键字。
这个关键字有两个作用:
1、让编译器创建实现属性所用的实例变量;
2、让编译器创建该属性的getter和setter方法。
当你同时重写了 setter 和 getter 时,系统就不会生成 ivar(实例变量/成员变量)。这时候有两种选择:
1、要么如第21行:手动创建 ivar
2、要么如第29行:使用@synthesize name = _name; ,关@property 与 ivar。
image.png总结下 @synthesize 合成实例变量的规则,有以下几点:
如果指定了成员变量的名称,会生成一个指定的名称的成员变量,
如果这个成员已经存在了就不再生成了.
如果是 @synthesize foo; 还会生成一个名称为foo的成员变量,也就是说:
如果没有指定成员变量的名称会自动生成一个属性同名的成员变量,
如果是 @synthesize foo = _foo; 就不会生成成员变量了.
假如 property 名为 foo,存在一个名为 _foo 的实例变量,那么还会自动合成新变量么? 不会。如下图:
image.png
@dynamic与@synthesize的区别:
- 区别在于:使用@synthesize,编译器会确实的产生getter和setter方法,而@dynamic仅仅是告诉编译器这两个方法在运行期会有的,无需产生警告(让编译器不要创建该属性的getter和setter方法)。
使用场景:
1、同时重写了 setter 和 getter 时
2、重写了只读属性的 getter 时
3、使用了 @dynamic 时
4、在 @protocol 中定义的所有属性
5、在 category 中定义的所有属性
6、重载的属性(C继承A,B继承A)
深拷贝和浅拷贝
这里分享一篇写的非常不错的博客:https://blog.csdn.net/Mazy_ma/article/details/51899397
表格总结
延伸问题:在声明NSString属性时,到底是选择strong还是copy?
答案:
https://blog.csdn.net/qq_18425655/article/details/51373611
解释为何NSString一般用copy修饰
但是文中的一句话:“所有系统容器类的 copy 和 mutableCopy 都是浅拷贝;其次,拷贝是针对容器类而言的,字符串不是容器类,何谈拷贝?”是错误的,不要相信这句话即可
自我总结:一般不可变的用copy修饰,可变的用strong修饰。一般我们将对象声明为NSString时,都不希望它改变,所以大多数情况下,我们建议用copy,以免因可变字符串的修改导致的一些非预期问题,保证安全性。NSArray也是同理。
OC中load,initialize的区别
1.对于load方法,只要文件被引用就会被调用。load方法调用顺序是父类的load方法优先调用于子类的load方法,而本类的load方法优先于category调用。
2.文件被引用并不代表initialize就会被调用,只有类或者子类中第一次有函数调用时,都会调用initialize。initialize是线程安全的,我们不能在initialize方法中加锁,这有可能导致死锁。我们也不应该在函数中实现复杂的代码。initialize只会被调用一次。
3.+load和+initialize共同点:在不考虑开发者主动使用的情况下,系统最多会调用一次如果父类和子类都被调用,父类的调用一定在子类之前这两个方法不适合做复杂的操作,应该是足够简单在使用时都不要过重地依赖于这两个方法,除非真正必要。在使用时一定要注意防止死锁!都不需要调用[super load]、[super initialize]
+load和+initialize不同点:load方法没有自动释放池,如果做数据处理,需要释放内存,则开发者得自己添加autoreleasepool来管理内存的释放; initialize与load不同,即使子类不实现initialize方法,也会把父类的实现继承过来调用一遍。注意的是在此之前,父类的方法已经被执行过一次了,同样不需要super调用。扩展延伸:iOS中的runtime的交换方法为什么一般都写在load方法,而不是在initialize方法?
1、父类实现了load方法,里面用了runtime交换方法的话 但是子类如果不实现load方法也不会调用父类的;
2、父类实现了initialize方法,里面用了runtime交换方法的话 但是子类如果不实现initialize方法就会调用父类的,而且分类的initialize会覆盖本类的initialize方法,导致本类的initialize的函数不调用
子类如果不实现load方法也不会调用父类的
子类如果不实现initialize方法就会调用父类的,分类的initialize会覆盖本类的initialize方法