查看NSArray.h中的NSArray创建方法块。
返回id的方法是否有正当理由不返回instancetype?
Apple甚至努力添加内联注释,让我们知道id
在这种情况下返回NSArray。
@interface NSArray (NSArrayCreation)
+ (instancetype)array;
+ (instancetype)arrayWithObject:(id)anObject;
+ (instancetype)arrayWithObjects:(const id [])objects count:(NSUInteger)cnt;
+ (instancetype)arrayWithObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION;
+ (instancetype)arrayWithArray:(NSArray *)array;
- (instancetype)init; /* designated initializer */
- (instancetype)initWithObjects:(const id [])objects count:(NSUInteger)cnt; /* designated initializer */
- (instancetype)initWithObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION;
- (instancetype)initWithArray:(NSArray *)array;
- (instancetype)initWithArray:(NSArray *)array copyItems:(BOOL)flag;
+ (id /* NSArray * */)arrayWithContentsOfFile:(NSString *)path;
+ (id /* NSArray * */)arrayWithContentsOfURL:(NSURL *)url;
- (id /* NSArray * */)initWithContentsOfFile:(NSString *)path;
- (id /* NSArray * */)initWithContentsOfURL:(NSURL *)url;
@end
我唯一可以提出这些特定方法的是Apple的指导
"由aURL标识的位置处的数组表示必须仅包含属性列表>对象(NSString,NSData,NSArray或NSDictionary对象)。这个>数组包含的对象是不可变的,即使数组是可变的。"
但是,对我来说这仍然没有解释id over instancetype的用法,因为它们仍然允许NSArray子类返回它们自己的instancetype
NSDictionary遵循完全相同的模式,其中创建包含文件或URL内容的字典使用id
,所有其他创建方法使用instancetype
- (instancetype)initWithObjectsAndKeys:(id)firstObject, ... NS_REQUIRES_NIL_TERMINATION;
- (instancetype)initWithDictionary:(NSDictionary *)otherDictionary;
- (instancetype)initWithDictionary:(NSDictionary *)otherDictionary copyItems:(BOOL)flag;
- (instancetype)initWithObjects:(NSArray *)objects forKeys:(NSArray *)keys;
+ (id /* NSDictionary * */)dictionaryWithContentsOfFile:(NSString *)path;
+ (id /* NSDictionary * */)dictionaryWithContentsOfURL:(NSURL *)url;
- (id /* NSDictionary * */)initWithContentsOfFile:(NSString *)path;
- (id /* NSDictionary * */)initWithContentsOfURL:(NSURL *)url;
我知道Apple正在努力将基础类中的id
替换为instancetype
但是在单个类中使用它的模式不一致是我们自己使用的指导,或者是只是没有去完成他们开始工作的课程?
扩展一点我想在NSMutableDictionary上调用dictionaryWithContentsOfFile
的返回类型
NSString * plistPath = [[NSBundle mainBundle] pathForResource:@"myFile" ofType:@"plist"];
NSMutableDictionary *myDictionary = [NSMutableDictionary dictionaryWithContentsOfFile:plistPath];
if ([ myDictionary isKindOfClass:[NSMutableDictionary class]])
{
NSLog(@"This is a mutable dictionary why id and not instancetype?");
[myDictionary setObject:@"I can mutate the dictionary" forKey:@"newKey"];
}
NSLog (@"%@", myDictionary[@"newKey"]);
return YES;
}
以下内容输出到我的控制台:
这是一个可变字典,为什么id而不是instancetype?
我可以改变字典
因此,我可以向字典中添加新的键和对象。
答案 0 :(得分:5)
好的,所以要回答这个问题,首先我们需要知道什么是类集群设计模式?
来自Apple的文档:
类集群是Foundation框架的设计模式 广泛使用。类簇集合了许多私有 公共抽象超类下的具体子类。分组 以这种方式的类简化了公开可见的体系结构 面向对象的框架,不会降低其功能丰富性。 类集群基于抽象工厂设计模式。
因此超级类将决定我们将为新创建的对象提供什么类型
现在因为这些方法在NSArray
和NSMutableArray
之间共享,结果可能不同,然后返回id
,因为我们不知道将返回哪个对象。( mutableArray或immutableArray)。
+ (id /* NSArray * */)arrayWithContentsOfFile:(NSString *)path;
+ (id /* NSArray * */)arrayWithContentsOfURL:(NSURL *)url;
- (id /* NSArray * */)initWithContentsOfFile:(NSString *)path;
- (id /* NSArray * */)initWithContentsOfURL:(NSURL *)url;
如果邮件已发送到NSArray
,则这些方法仅返回NSArray
,如果将方法发送到NSMutableArray
,则{}返回NSMutableArray
。这就是为什么他们返回instancetype
+ (instancetype)arrayWithObjects:(id)firstObj, ... NS_REQUIRES_NIL_TERMINATION;
+ (instancetype)arrayWithArray:(NSArray *)array;
- (instancetype)init;
好的,所以我们说上面的方法只返回接收者的实例类型。但是,如果我们希望arrayWithArray
方法始终返回immutableArray
而不管接收者是谁?
这意味着NSMutableArray
将获得与instanceType不同的类型,因为NSArray不是NSMutableArray类型,在这种情况下我们会将方法更改为:
// from
+ (instancetype)arrayWithArray:(NSArray *)array;
// to
+ (id)arrayWithArray:(NSArray *)array;
我们说现在返回id,尽管对象的类型。
更新:
与您的代码类似的示例
NSString *filePath = [[NSBundle mainBundle]pathForResource:@"myFile" ofType:@"plist"];
NSMutableDictionary *dict = [NSMutableDictionary dictionaryWithContentsOfFile:filePath];
NSMutableDictionary *dict2 = [[NSMutableDictionary alloc] init];
NSLog(@"%@", NSStringFromClass([dict class])); // prints __NSCFDictionary // converted to immutable
NSLog(@"%@", NSStringFromClass([dict2 class])); // prints __NSDictionaryM, its mutable
[dict setObject:@"obj" forKey:@"key"]; // this will do nothing, because its immutable, we can't add new object
以下是Apple关于使用isKindOfClass
:关于检查类集群可变性的说法
在类所代表的对象上使用此方法时要小心 簇。由于类簇的性质,你得到的对象 返回可能并不总是您期望的类型。如果你打电话给方法 返回一个类集群,该方法返回的确切类型是 您可以使用该对象执行的最佳指示。例如, 如果方法返回指向NSArray对象的指针,则不应使用 此方法查看数组是否可变,如下所示 代码:
// DO NOT DO THIS!
if ([myArray isKindOfClass:[NSMutableArray class]])
{
// Modify the object
}
答案 1 :(得分:1)
类集群可能会返回除您创建它们的类以外的类。 对于Foundation类来说,这通常是正确的,因为在许多情况下它们会创建某种优化类。该类仍将从isKindOfClass返回YES:
此外,一些免费的桥接类返回一个在Foundation和Core Foundation之间共享的类。一个例子是NSCFString。