類別
不需要通過增加子類而增加現有類的方法
通過類別可以將一個類的方法進行劃分,便于維護
不能向類別添加實例變量,只能通過定義子類的方式添加實例變量
類別中的方法比原始類方法具有更高優先級
類別即分類,主要作用就是在不修改原來類的基礎上,為一個類擴展方法,常用的就是給系統自帶的類擴展方法。如下圖所示,使用分類給UIImage添加了originalImageNamed
方法,在需要的地方引入#import "UIImage+HPCategory.h"
即可使用其中的擴展方法。
如果類別和原來類中有重復的方法,會優先調用類別中的方法。
類別可以訪問原來類中的非私有成員變量。
類別只能添加方法,不能添加成員變量。
通常在一個類中用@property聲明屬性,編譯器會自動幫我們生成_成員變量、setter和getter方法。類別不能添加成員變量,是因為在分類中是不會自動生成_成員變量、setter和getter方法的,如果仍要添加一個成員變量,編譯能成功,但是運行時會崩潰。解決辦法就是手動添加setter和getter方法或者通過runtime中objc_getAssociatedObject / objc_setAssociatedObject
來訪問和生成關聯對象。
下面展示兩種方法,通過類別給UIView添加屬性:
我給UIView添加一個類別,寫了兩個屬性。如果在.m中不寫x和name的set/get方法,會給出警告Property 'x' requires method 'x' to be defined - use @dynamic or provide a method implementation in this category
和Property 'x' requires method 'setX:' to be defined - use @dynamic or provide a method implementation in this category
,忽視警告的話,意味著后面用到x、name屬性,會導致程序崩潰。
#import <UIKit/UIKit.h>
@interface UIView (XDViewCate)
@property (nonatomic, assign) CGFloat x;
@property (nonatomic, strong) NSString *name;
@end
- 自己寫set和get方法
@implementation UIView (XDViewCate)
// x屬性是自定義set和get方法
- (void)setX:(CGFloat)x {
CGRect frame = self.frame;
frame.origin.x = x;
self.frame = frame;
}
- (CGFloat)x {
return self.frame.origin.x;
}
- 用runtime中的方法
下面的nameSetAndGetKey是一個固定的鍵值標記static NSString *nameSetAndGetKey = @"nameKey";
// name屬性是使用runtime訪問、關聯對象
- (void)setName:(NSString *)name {
objc_setAssociatedObject(self, &nameSetAndGetKey, name, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (NSString *)name {
return objc_getAssociatedObject(self, &nameSetAndGetKey);
}
這樣就可以使用x、name屬性了。舉個例子,XDDemoView是一個繼承自UIView的一個類,在XDDemoView.m中#import "UIView+XDViewCate.h"
,我就可以在XDDemoView中使用self.x
,self.name
。
擴展
能為類附加額外的屬性,成員變量,方法聲明
一般的類擴展寫到.m文件中
一般的私有屬性寫到類擴展
添加擴展只能得到一個.h文件,在頭文件中可以添加屬性和方法,但都是私有的,只能被這個類所擁有和訪問。擴展的新方法必須要在.m中實現。擴展對系統自帶的類意義不大,因為我們訪問不到系統類的.m文件。
通過新建擴展的方式,給UIView添加一個擴展類,如下:
#import <UIKit/UIKit.h>
@interface UIView ()
@property (nonatomic, copy) NSString *time;
- (void)printTime;
@end
這個擴展類沒有.m,我無法自己去定義set、get方法,也不能實現printTime方法。在XDDemoView.m(一個繼承自UIView的一個類)中,調用self.time或者調用printTime方法會導致崩潰。
通常的類的.m文件中的@interface,算是擴展的一種特殊情況。如下圖,橙色框中就是這種情況,這其中的屬性都是私有的,只能在這個類中使用。
參考:https://www.cnblogs.com/yajunLi/p/6373728.html
http://www.lxweimin.com/p/18d48e7f2aad
https://www.cnblogs.com/yajunLi/p/6373292.html