self 和 super 指向同一個對象,唯一區別在方法查找起點| 調用方式 | 方法查找起點 | 典型用途 |
|---|---|---|
[self method] | 當前類 → 父類 → ... → NSObject | 正常調用,支持多態 |
[super method] | 父類 → 祖父類 → ... → NSObject | 調用父類實現,通常在重寫方法中 |
#import
@class Student; // 前向聲明,減少頭文件依賴
@interface Person : NSObject {
int age;
NSString *name;
Student *student;
}
- (NSString *)getName;
- (void)setName:(NSString *)name;
- (int)getAge;
- (void)setAge:(int)age;
@end
#import "Person.h"
#import "Student.h" // 實現文件引入完整定義
@implementation Person
- (id)init {
if (self = [super init]) { // 必須調用父類初始化
student = [[Student alloc] init];
NSLog(@"student: %@", student);
}
return self;
}
- (void)setName:(NSString *)name {
_name = name;
[self setAge:14]; // self 調用本類方法(多態入口)
NSLog(@"setAge called");
NSLog(@"self class: %@", [self class]); // 實際類型
NSLog(@"super class: %@", [super superclass]); // 父類類型
}
- (NSString *)getName { return _name; }
- (int)getAge { return _age; }
- (void)setAge:(int)age { _age = age; }
@end
- (id)init {
if (self = [super init]) { // 1. 父類初始化
// 2. 子類自身初始化
_name = @"Default";
}
return self; // 必須返回初始化後的 self
}
若 [super init] 返回 nil,必須直接返回 nil,不執行後續代碼。
- (void)setName:(NSString *)name {
[super setName:name]; // 先執行父類邏輯(如驗證、日誌)
_name = name; // 再執行子類邏輯
}
// 父類
- (void)foo { NSLog(@"Parent foo"); }
- (void)bar { [self foo]; } // 調用 self 的 foo
// 子類重寫 foo
- (void)foo { NSLog(@"Child foo"); }
// 調用
Child *c = [[Child alloc] init];
[c bar]; // 輸出 "Child foo"!因為 self 是 Child 實例
// 子類
- (void)bar {
[super foo]; // 總是調用 Parent 的 foo,無論 self 實際類型
}
[self method] → objc_msgSend(self, @selector(method))[super method] → objc_msgSendSuper(&super_struct, @selector(method))super_struct 包含 receiver (self) 和 super_class (父類類對象)[super init] → 父類成員未初始化if (self = [super init]) 寫成 if (self == [super init]) → 邏輯錯誤self 指向類對象,super 指向元類父類super 是指針可賦值傳遞 → 編譯錯誤self 是動態的、多態的、面向對象的核心;super 是靜態的、顯式的、用於協作繼承的工具。理解二者查找差異,是掌握 Objective-C 運行時機制的關鍵。