本篇为翻译稿,原文链接:Objective-C Class Properties
随着所有关于新的Swift 3语言功能的兴奋,很容易忽略Objective-C仍然发生的一些小改进。 虽然现在苹果做了很多从 Objective-C转向Swift工作,但是这些小改变对于需要使用Objective-C来开发的人来说,仍然受到欢迎。
在这篇文章中,我们来看看给Objective-C 类的成员变量添加 class 属性。
Objective-C Class Properties
Xcode 8的发行版本说明如下:
Objective-C now supports class properties, which interoperate with Swift type properties. They are declared as: @property (class) NSString *someStringProperty;. They are never synthesized. (23891898)
大意就是说Objective-C现在支持与Swift类型属性进行交互转换的类属性,这些属性永远不会synthesized
让我们进行如下的一个实验,我们创建一个具有类属性的Objective-C类:User;如下:
@interface User : NSObject
@property (class, nonatomic, assign, readonly) NSInteger userCount;
@property (class, nonatomic, copy) NSUUID *identifier;
+ (void)resetIdentifier;
@end
为了说明的目的,我有两个属性,第一个是只读整数,第二个是可复制的带读写属性NSUUID类。 注意属性声明中的class属性。
实现很简单,首先我们需要存储identifier和userCount类属性。 由于这些是 class 级别而不是实例变量,我们将它们声明为静态的:
@implementation User
static NSUUID *_identifier = nil;
static NSInteger _userCount = 0;
现在我们为这两个类属性创建setter和getter方法;就像上面引用的苹果的文档一样,这两个属性永远不会synthesized,因此如果我们不显示添加setter和getter方法,XCode就会提示警告信息使用@dynamic或者是提供setter和getter方法; 首先,只读userCount属性只需要一个getter,它只返回计数的值。 注意在getter方法前面使用 + 让其成为一个类的方法:
+ (NSInteger)userCount {
return _userCount;
}
identifier 属性需要一个setter和一个getter方法;在getter方法中如果改属性为nil,我们就创建一个identifier,如下:
+ (NSUUID *)identifier {
if (_identifier == nil) {
_identifier = [[NSUUID alloc] init];
}
return _identifier;
}
+ (void)setIdentifier:(NSUUID *)newIdentifier {
if (newIdentifier != _identifier) {
_identifier = [newIdentifier copy];
}
}
同时我们创建一个基本的初始化方法,在这个初始化方法里我们将更新userCount属性;
- (instancetype)init
{
self = [super init];
if (self) {
_userCount += 1;
}
return self;
}
+ (void)resetIdentifier
是一个方便用来创建新的identifier的方法;
+ (void)resetIdentifier {
_identifier = [[NSUUID alloc] init];
}
@end
您可以使用类名上的普通点语法访问类属性:
User.userCount;
User.identifier;
用法如下示例:
for (int i = 0; i < 3; i++) {
self.user = [[User alloc] init];
NSLog(@"User count: %ld",(long)User.userCount);
NSLog(@"Identifier = %@",User.identifier);
}
[User resetIdentifier];
NSLog(@"Identifier = %@",User.identifier);
输出如下:
// User count: 1
// Identifier = 4B98B7FD-F8DC-484A-92B2-B2BB20BCB709
// User count: 2
// Identifier = 4B98B7FD-F8DC-484A-92B2-B2BB20BCB709
// User count: 3
// Identifier = 4B98B7FD-F8DC-484A-92B2-B2BB20BCB709
// Identifier = A0519681-1E08-4DF2-B2D1-D077CF2BDEFF
请注意,由于这是Xcode 8中的LLVM编译器的一项功能,因此它可以在低于iOS 10的环境下使用
Generated Swift interface
似乎Objective-C获得的唯一增强功能是提高与Swift的互通性。 向Objective-C添加 class 属性映射到Swift中使用类变量。 这是为我们的User类生成的Swift代码:
public class User : NSObject {
public class var userCount: Int { get }
public class var identifier: UUID!
public class func resetIdentifier()
}
请注意,我们的identifier属性是一个隐式拆包可选意思,我们从来没有希望它为零。 为了允许它为零,我们需要在Objective-C属性声明中添加一个nullable的声明,这样Swift变量将是一个可选的。 有关更多详细信息,请参阅Using nullable to annotate Objective-C。
Further Reading
WWDC 2016 Session 405 What’s New in LLVM