iOS Objective-C 中的 self 与 super
- 为什么要alloc, init
alloc 中主要是完成对象内存的分配, init 则是完成初始化.
不 init 可不可以.
可以, 但是对象还没有完成初始化, 内存里面除了 isa 指针指向类对象之外, 其他地方都是空的. 但是调用简单的方法还是可以的, 例如:
@interface MyClass:NSObject
@end
@implementation MyClass
-(void) say {
NSLog(@"hello, world");
}
@end
...
MyClass *obj = [MyClass alloc];
[obj say]; // hello, world
...
- init 方法里面为什么要
self = [super init]
通常的初始化方法是这样的:
-(instancetype)init
{
self = [super init];
if (self) {
// 初始化
}
return self;
}
我觉得有两点原因, 1. 通过调用 super init 方法, 可以由继承链完成子类到祖先类的初始化. 2. 如果某个父类初始化失败, 可以保证一致性, 不会出现父类初始化失败了, 子类还能初始化成功引发某些奇怪的错误.
- super 和 self 是什么?
self 比较简单, 就是自己, 当前接收消息的对象, 的指针.
super 是什么呢?
这个得要从 oc 的message send 说起. 对于self 或是一个普通的对象, 调用某个方法, 例如:
@interface Father:NSObject
@end
@implementation Father
-(void) say {
NSLog(@"hello, i'm father");
}
@end
@interface Son:Father
@end
@implementation Son
-(void) say {
NSLog(@"hello, i'm son");
}
@end
如果在 Son 中调用 [self say]
, 将会转换为伪代码 msg_send(self, @selector(say))
, 这将会从当前 类的方法列表中开始查找 say 方法, 如果找不到则往上找, 这里会输出hello, i'm son
如果在 Son 调用 [super say]
, 将会转换为伪代码 objc_msgSendSuper(self, @selector(say))
, 这将会从父类 类的方法列表中开始查找 say 方法, 如果找不到则往继续往上找, 这里输出hello, i'm father
可以看到, super 和 self 唯一的区别是查找方法的起始位置不同. 但是最终接收消息的都是 self. 我们来验证一下.
改造一下这两个类, 分别加一个 name 方法, 然后在 say 中输出.
@interface Father:NSObject
@end
@implementation Father
-(NSString *)name {
return @"Tom";
}
-(void) say {
NSLog(@"hello, i'm father, my name is %@", self.name);
}
@end
@interface Son:NSObject
@end
@implementation Son
-(NSString *)name {
return @"Tomson";
}
-(void) say {
NSLog(@"hello, i'm son, my name is %@", self.name);
}
@end
如果在 Son 中调用 [self say]
, [super say]
, 会输出什么呢?
是不是很奇怪.
结果中可以看出来, 你是不是期待输出这样的结果.
hello, i'm son, my name is Tom
hello, i'm father, my name is Tomson
失望吧!
虽然看起来不对劲, 但从 say 方法来讲, self 调用的是 Son 的方法, super 调用的是 Father 的方法, 这点还是没问题的.
重点在 say 里面的 self.name
, 为啥都是调用的子类的方法?
敲黑板~~~~
之前说过, super 只是寻找方法的起点是父类, 真正接收消息的还是子类, 而 super 中的 self 则是指向的当前接收消息的对象.
所以看到 [super say]
是调用的父类的,因为这个方法是从父类开始找的, 自然就是调用父类的方法.
self.name
是调用的子类的, 因为真正接收消息的还是子类的对象.
同理, 经典问题, 期末必考的那种, 再次敲黑板~~~~
NSLog(@"%@", NSStringFromClass([self class]));
NSLog(@"%@", NSStringFromClass([super class]));
为啥都是输出 Son? 是不是有点懂了.不懂?
这是由于 class 这个方法, 子类和父类都是没有实现的. 真正实现的是 NSObject, 所以不管是用 self 从当前类的方法列表中开始查找还是用 super 从父类的方法列表中开始查找都没有区别.
最后到 NSObject 里面, 例如如下伪代码
-(Class)class {
return object_getClass(self);
}
接受消息的是 self 都是 Son 的对象, 所以打印出来的也都是 Son
ps:菜鸟一枚, 如果有哪里说错的, 还望赐教.