一面褐、關(guān)于類方法和實例方法:
1、類方法:Class Method 有時被稱為靜態(tài)方法充择,類方法可以獨立于實例對象而執(zhí)行德玫。在使用類方法時要注意以下幾點:
- 類方法以
+
開頭,相當(dāng)于static椎麦,不能被類的實例調(diào)用宰僧,只能由類對象調(diào)用。 - 類方法使用
self
時观挎,self
代表類本身即Class
琴儿,所以類方內(nèi)可以直接調(diào)用類方法(別調(diào)用自己!死循環(huán)`医荨)造成,不能直接調(diào)用實例方法,但是可以通過創(chuàng)建實例對象來調(diào)用實例方法雄嚣。 - 類方法中不能訪問屬性和實例變量晒屎,只能訪問類對象,但是可以通過創(chuàng)建實例對象來訪問屬性缓升,有點雞肋~鼓鲁。
@interface JRSecondViewController ()
{
UIImageView * _imageView;
}
@property(strong,nonatomic)UIButton *btn;
@end
@implementation JRSecondViewController
+(void)creatSomeObject
{
_imageView = [[UIImageView alloc] init];
self.btn = [UIButton new];
[self creatMethod];
[self creatInstance];
}
+(void)creatMethod{ }
-(void)creatInstance{ }
@end
2、實例方法:必須由類的實例對象調(diào)用港谊,可以訪問屬性骇吭,實例變量,同樣可以訪問類對象歧寺,使用限制相對于類方法較少燥狰。
一棘脐、關(guān)于self和super
?總的來說:self
會優(yōu)先調(diào)用本類中的方法,super
會優(yōu)先調(diào)用父類方法龙致。但是荆残,self
是指向本類的指針,是類的隱藏參數(shù)净当,指向當(dāng)前調(diào)用方法的對象(類對象或者實例對象),super
卻不是指向父類的指針蕴潦,只是一個編譯器標(biāo)識符像啼,其在運行時中與self相同,指向同一個消息接受者潭苞,只是self
會優(yōu)先在當(dāng)前類的methodLists中查找方法忽冻,而super
則是優(yōu)先從父類中查找, 向super發(fā)送消息是一種調(diào)用繼承鏈上的超類定義的 方法實現(xiàn)的方法此疹。
// 基類:
@interface BaseViewController : UIViewController
- (id)returnSomething;
@end
@implementation BaseViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor whiteColor];
NSLog(@"super -- %@ , self -- %@", [super class], [self class]);
}
- (id)returnSomething
{
return [UIView new];
}
@end
// 子類:
@interface JRSecondViewController : BaseViewController
@end
@implementation JRSecondViewController
- (instancetype)init
{
self = [super init];
if (self) {
NSLog(@"self == %@", [self class]);
NSLog(@"super == %@", [super class]);
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// 會從當(dāng)前類的方法列表中開始找,如果沒有,就從父類中再找;
NSLog(@"viewDidLoad -> self == %@", [self returnSomething]);
// 如果父類中只用方法定義而未實現(xiàn)則此處會報錯
NSLog(@"viewDidLoad -> super == %@", [super returnSomething]);
}
-(id)returnSomething
{
return [UIImageView new];
}
@end
// 外部調(diào)用
JRSecondViewController * secondVC = [JRSecondViewController new];
[self presentViewController:baseNavVC animated:YES completion:^{
}];
// 打印結(jié)果:
17:38:30.721835+0800 self == JRSecondViewController
17:38:30.722161+0800 super == JRSecondViewController
17:38:30.738893+0800 super -- JRSecondViewController , self -- JRSecondViewController
17:38:30.740765+0800 viewDidLoad -> self == <UIImageView: 0x7f9e5e507f30; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <CALayer: 0x600000029c00>>
17:38:30.741180+0800 viewDidLoad -> super == <UIView: 0x7f9e5e650520; frame = (0 0; 0 0); layer = <CALayer: 0x600000030be0>>
結(jié)果分析:
- 可以看到首先調(diào)用
JRSecondViewController
的init
方法僧诚,但是在其中[self class]
和[super class]
均打印的是JRSecondViewController
類!原因:- 無論
[self class]
還是[super class]
蝗碎,其接受消息的對象都是當(dāng)前JRSecondViewController
的實例對象湖笨。而不同的是,super
是告訴編譯器蹦骑,調(diào)用 class 這個方法時,要去父類的方法,而不是本類里的慈省。
- 無論
- 然后到
viewDidLoad
方法中首先調(diào)用了[super viewDidLoad];
去執(zhí)行父類的viewDidLoad
方法,但是這里在父類的方法中打印的[self class]
和[super class]
同樣指向了JRSecondViewController
類C吖健1甙堋!原因:- 還是上面的原因捎废,調(diào)用
[super viewDidLoad];
方法笑窜,其接收消息的對象依然是JRSecondViewController
的是實例對象,但是現(xiàn)在父類中查找viewDidLoad
方法登疗。同理在上面代碼的基礎(chǔ)上排截,在父類的returnSomething
方法中打印[self class]
和[super class]
會是什么結(jié)果呢???
- 還是上面的原因捎废,調(diào)用
經(jīng)過上面的例子再回來看self和super的實現(xiàn)原理可能更加好理解:
self 調(diào)用方法事實際上是通過
objc_msgSend(id _Nullable self, SEL _Nonnull op, ...)
函數(shù)進(jìn)行消息的發(fā)送谜叹,其中第一個參數(shù)是消息接收者匾寝,第二個參數(shù)op
是調(diào)用的具體類的方法的selector,后面是 selector 方法的可變參數(shù)荷腊。如上例所示[self returnSomething]
實際上是id _Nullable objc_msgSend(self, @selector(returnSomething))
而returnSomething
方法會從[self class]
類中查找艳悔。super調(diào)用方法事實際上是通過
id _Nullable objc_msgSendSuper(struct objc_super * _Nonnull super, SEL _Nonnull op, ...)
函數(shù)進(jìn)行消息的發(fā)送,但是第一個參數(shù)是一個objc_super
結(jié)構(gòu)體女仰。
struct objc_super {
__unsafe_unretained _Nonnull id receiver;
__unsafe_unretained _Nonnull Class super_class;
};
此時這個結(jié)構(gòu)體的第一個成員變量receiver就是子類猜年,和
objc_msgSend
中的self相同抡锈。而第二個成員變量super_class就是指父類,調(diào)用objc_msgSendSuper
的方法時會將這個結(jié)構(gòu)體和returnSomething
的selector傳遞過去乔外。在結(jié)構(gòu)體函數(shù)里面做的事情類似這樣:從objc_super結(jié)構(gòu)體指向的super_class的方法列表開始找
returnSomething
的selector床三,找到后再用objc_super->receiver去調(diào)用這個selector。找不到就會報錯杨幼。
這樣結(jié)合上述例子和self和super的原理就會很容易明白為什么[self class]
和[super class]
輸出結(jié)果會是一樣的,同時在BaseViewController
的viewDidLoad
中[self class]
和[super class]
輸出都是子類類對象了撇簿。