gpt4 book ai didi

ios - 为什么 Apple 在类构造函数中对 instancetype 的使用不一致?

转载 作者:技术小花猫 更新时间:2023-10-29 10:26:55 26 4
gpt4 key购买 nike

查看 NSArray.h 中的 NSArray 创建方法 block 。

返回 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 的指南

"The array representation at the location identified by aURL must contain only property list >objects (NSString, NSData, NSArray, or NSDictionary objects). The objects contained by this >array are immutable, even if the array is mutable."

然而,这对我来说仍然不能解释 id 在 instancetype 上的使用,因为它们仍然允许 NSArray 子类返回它们自己的 instancetype

NSDictionary 遵循完全相同的模式,其中使用 id 创建包含文件或 URL 内容的字典,所有其他创建方法使用 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,但它在单个类中使用中的模式不一致是否可以作为我们的指导自己的用法,还是他们只是没有时间完成他们开始学习的类(class)?

为了扩展一点,我想探索在 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;
}

我的控制台输出了以下内容:

This is a mutable dictionary why id and not instancetype?

I can mutate the dictionary

因此,我可以向字典中添加新的键和对象。

最佳答案

好的,那么要回答这个问题,首先我们需要知道什么是类集群设计模式

来自 Apple 的文档:

Class clusters are a design pattern that the Foundation framework makes extensive use of. Class clusters group a number of private concrete subclasses under a public abstract superclass. The grouping of classes in this way simplifies the publicly visible architecture of an object-oriented framework without reducing its functional richness. Class clusters are based on the Abstract Factory design pattern.

因此父类(super class)将决定我们新创建的对象的类型

现在因为这些方法在 NSArrayNSMutableArray 之间共享,结果可能不同,然后它们返回 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 的说法:检查类簇的可变性

Be careful when using this method on objects represented by a class cluster. Because of the nature of class clusters, the object you get back may not always be the type you expected. If you call a method that returns a class cluster, the exact type returned by the method is the best indicator of what you can do with that object. For example, if a method returns a pointer to an NSArray object, you should not use this method to see if the array is mutable, as shown in the following code:

// DO NOT DO THIS! 
if ([myArray isKindOfClass:[NSMutableArray class]])
{
// Modify the object
}

链接:https://developer.apple.com/library/ios/documentation/cocoa/reference/foundation/Protocols/NSObject_Protocol/Reference/NSObject.html#//apple_ref/occ/intfm/NSObject/isKindOfClass :

关于ios - 为什么 Apple 在类构造函数中对 instancetype 的使用不一致?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22095621/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com