您的位置:首页 > 移动开发 > Objective-C

Objective-C语法之self

2017-07-26 16:46 134 查看
在实现Objective-C类的方法时, 我们可以在方法内部用self关键字来引用当前对象或者当前类, 使对象或类自己作为消息的接收者.

用代码来说明, 定义一个类ClassA:

@interface ClassA : NSObject

- (void)instanceMethodA;
- (void)instanceMethodB;
+ (void)classMethodA;
+ (void)classMethodB;

@end


我们来实现它的方法:

- (void)instanceMethodA {

}

- (void)instanceMethodB {
// 调用实例方法, 此时self代表"当前对象"或"当前实例"
[self instanceMethodA];
}

+ (void)classMethodA {

}

+ (void)classMethodB {
// 调用类方法, 此时self代表"当前类"
[self classMethodA];
// 效果等同于[ClassA classMethodA];
}


可以看到, 在实现instanceMethodB时, 给self发送了instanceMethodA消息, 此时, self就引用着”当前对象”, 因为instanceMethodA是个对象方法, 它的接收者必须是一个对象.

同理, 在classMethodB中, 给self发送了classMethodA消息, 由于classMethodA是个类方法, 其接收者必须是一个类, 所以此时self就引用着”当前类”, 即ClassA.

总结起来就是一句话: self引用着当前消息的接收者.

延伸:

我们经常会给一个类设计一个或多个构造方法, 来快速地创建对象. 在构造方法内部, 我们也应该尽量使用self关键字, 而不是直接使用类名, 这是为了构造方法在子类中也能返回正确的子类对象, 而不是父类.

用代码来说明, 在ClassA中定义一个构造方法:

@interface ClassA : NSObject

+ (instancetype)anObject; // 构造方法

@end


实现构造方法, 先看第一种方式(不推荐):

+ (instancetype)anObject {
// 直接使用类名调用alloc
return [[ClassA alloc] init];
}


创建一个ClassB, 继承自ClassA. 看如下的测试代码:

id obj1 = [ClassA anObject];
NSLog(@"%@", NSStringFromClass([obj1 class]));
// 输出ClassA

id obj2 = [ClassB anObject];
NSLog(@"%@", NSStringFromClass([obj2 class]));
// 输出ClassA


我们用ClassB调用anObject方法, 返回的对象依然是ClassA类型, 这显然就达不到我们本来的目的了.

再看第二种实现方式(推荐写法):

+ (instancetype)anObject {
// 使用self调用alloc
return [[self alloc] init];
}


此时, 再次运行:

id obj2 = [ClassB anObject];
NSLog(@"%@", NSStringFromClass([obj2 class]));
// 输出ClassB


这就达到我们预期的效果了.

另外, 在很多地方还能看到第三种实现方式, 用[self class]代替self:

+ (instancetype)anObject {
return [[[self class] alloc] init];
}


这其实和第二种方式是等效的, 因为无论是self或者[self class], 此时代表的东西是一样的, 都是”当前类”.

最后建议, 在设计初始化方法或者构造方法时, 应该用instancetype作为返回类型, 这有助于类型安全, 详情可参阅我的这篇博文.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息