iOS基础
-
分类(Category)和类扩展(Class Extension)
分类(Category)
Category,是表示一个指向分类的结构体的指针,其定义如下: typedef struct objc_category *Category; struct objc_category { char *category_name OBJC2_UNAVAILABLE; // 分类名 char *class_name OBJC2_UNAVAILABLE; // 分类所属的类名 struct objc_method_list *instance_methods OBJC2_UNAVAILABLE; // 实例方法列表 struct objc_method_list *class_methods OBJC2_UNAVAILABLE; // 类方法列表 struct objc_protocol_list *protocols OBJC2_UNAVAILABLE; // 分类所实现的协议列表 } 分类的结构体成员:分类名、分类所属的类名、实例方法列表、类方法列表、分类所实现的协议列表。 发现,该结构体包含了分类定义的实例方法与类方法,但结构体里没有属性列表。 注:(Category局限性上) 1.Category,原则上只能添加方法,不能添加属性,实际上可以通过其他方式添加属性; 2.分类中可以写 @property,但不会声明及实现setter/getter; 3.分类的优先级最高,如果方法名与原有类同名,则会优先调用分类中的方法,优先级顺序 分类>本类>父类; 延伸问题: 为什么在分类中声明属性时运行不会报错? or 为什么分类中使用@property仍然可以编译通过? 答:一个类中使用@property声明属性,编译器会自动生成 _成员变量和setter/getter。 但分类结构体中没有属性列表,所以不会自动生成 _成员变量 和 setter/getter。 因此使用@property编译和运行都不会报错,一旦使用 _成员变量 或 setter/getter,就会报错。 可不可以手动实现setter/getter方法来避免崩溃? 答:可以的,OC是动态语言,可以通过runtime添加 setter/getter方法。 objc_setAssociatedObject(),动态实现setter方法,objc_getAssociatedObject(),动态实现getter方法。
类扩展(Class Extension)
Extension 是 Category 的一个特例。格式: @interface XXX () //私有属性 //私有方法(如果不实现,编译时会报警,Method definition for 'XXX' not found) @end
分类和类扩展的区别
1.Category原则上只能增加方法(可通过runtime解决增加属性的问题); 2.Extention可增加方法和属性,只是该属性是@private类型,作用范围是自身; 3.Category是运行时添加到类中,Extension是编译时添加到类中。
-
atomic 和 nonatomic
使用@property声明属性时,会使用atomic/nonatomic关键字 atomic 和 nonatomic 区别在于系统自动生成setter/getter方法不一样 atomic 系统自动生成的setter/getter方法会进行加锁操作; nonatomic 系统自动生成的setter/getter方法不会进行加锁操作。
atomic
系统生成的setter/getter方法进行加锁操作,但这个锁,仅仅保证了setter/getter存取方法的线程安全。 因加锁的缘故,其他线程要读取这个属性时,会先执行完当前操作。 延伸问题: atmoic是线程安全吗? 答:atomic只是对属性的setter/getter方法进行加锁操作,仅仅是set/get的读取安全,并非真正的线程安全,线程安全还有读取之外的其 他操作。 (比如:当一个线程正在setter/getter时,有另一个线程 同时进行release操作,这时可能导致crash)
nonatomic
系统生成的setter/getter方法没有进行加锁操作,读取时不安全,但速度更快,当多个线程同时访问同一属性时,会出现无法预料的结果。
atomic和nonatomic的使用选择
atomic能够保证setter/getter操作的安全性,但是相对nonatomic更耗费资源,且速度更慢,因此如果没有多线程之间通信操作的情况下,使用nonatomic更好。
-
Objective-C是一门动态语言
动态,不需要再编译时确定所有的东西,在运行时可以动态添加变量、属性、方法、类。Objective-C可以通过runtime,在运行时动态的添加变量、属性、方法、类,所以说Objective-C是一门动态语言。 动态性体现: 1.动态类型。如id类型。静态类型因固定性和可预知性而使用广泛。静态类型是强类型,而动态类型是弱类型,运行时决定接收者; 2.动态绑定。让代码在运行时判断需要调用的方法,而不是在编译时。与其他面向对象语言一样,方法调用和代码并不是在编译时连接在一起,而是在消息发送时连接,运行时决定调用哪个方法; 3.动态载入。程序在运行时添加代码模块及资源。用户可根据需要加载可执行代码和资源,而不是启动时家在所有组件。可执行代码中可以含有和程序运行时整合的新类。
-
weak、strong、assign
由ARC引入 weak相当于OC中的assign,但是weak只能修饰OC对象,而assign可用于非OC对象,但是它们都不会造成引用计数+1; strong相当于OC中都retain,会造成引用计数+1。 ARC,引用计数机制,OC的内存管理机制。其原理:还要还有一个变量指向对象,对象就会保持在内存中。 当指针指向新值,或者指针不存在时,相关联的对象就会自动释放。
strong
strong指针是强引用,能够保持对象的生命,一个对象只要有strong指针指向它就不会被释放; 相反,如果没有一个strong指针指向它,那么它将自动释放。 默认所有实例变量和局部变量都是strong指针。
weak
weak指针是弱指针,同样可以指向一个对象,但是不是该对象的拥有者。即当对象销毁时,weak指针自动指向nil(空指针)。 这样避免了指针继续指向已释放对象,进而避免了野指针的出现。 延伸问题: IBOutlet连出来的视图属性为什么用weak修饰?那些控件对象不会自动释放吗? 如:@property (nonatomic, weak) IBOutlet UIButton *button; 答:xib创建或放置控件时,存在该引用关系: UIViewController->UIView->subviews->UIButton UIView持有了subviews(强引用),所以这里可以使用weak来修饰。 为什么代理要用weak修饰? 答:防止循环引用。 如:控制器的view强引用这UITableView,而tableview的delegate又是控制器。 如果不用weak,Controller->View->delegate-> Controller,就造成了循环引用。
assign
assign主要用于修饰基本数据类型,如NSInteger,CGFloat等,存储在栈中,内存不用程序员管理。
待更...