如果我有一个已经分配的对象,那么执行object.class
会返回一个非零值。到现在为止还挺好。但是,如果尚未分配对象,则访问object.class
会返回nil
。
我想动态地根据其类型分配对象,例如:
@property NSArray *myArray;
...
// myArray is nil so far
self.myArray = [_myArray.class new];
但是,我不能这样做因为_myArray.class
返回nil。那么我如何确定一个nil实例的类类型呢?
更新 事实上这是可能的。查看下面的answer。
答案 0 :(得分:4)
您无法确定nil
实例的类,因为它没有实例:从字面上看,它可以是从变量类型派生的任何类型。例如,NSMutableArray
与NSArray
完全兼容:
NSArray *myArray = [NSArray new]; // OK
NSArray *myArray = [NSMutableArray new]; // Also OK
由于不同子类的运行时功能可能会有很大差异,因此您的程序始终可以决定它想要的对象类型。
答案 1 :(得分:3)
Objective-C是一种鸭式语言。这意味着你可以做或不可以做几件事,而你不能做的事情之一是静态地获得对变量类型的引用。
具体来说,在你的表达中:
[_myArray.class new]
首先,评估_myArray.class
,然后向结果发送new
消息。由于_myArray
开始为nil
,_myArray.class
也会返回nil
,new
消息也将返回nil
,因为发送任何内容消息到nil
返回nil
(或返回类型的最接近的表示为零)。这就是为什么它不起作用。
我怀疑你来自像C#这样的强类型语言;你现在正在做的是相当于Foo foo = (Foo)Activator.CreateInstance(foo.GetType())
,它肯定会失败,因为foo.GetType()
将不会编译或抛出异常(取决于它是一个类字段还是局部变量),因为它从未被赋予价值。在Objective-C中,它编译但不起作用。你想要的是Activator.CreateInstance(typeof(Foo))
,但请注意Foo
现在也是硬编码的,所以你也可以创建一个new Foo()
。
你说编译器“知道对象的类型”。这不完全正确。首先,NSArray
和NSMutableArray
是NSArray
类群集的根类。这意味着两者都是抽象的,[NSArray alloc]
和[NSMutableArray alloc]
上次检查时返回子类的实例(NSCFArray
,可能还有别的东西;我记得看到_NSArrayM
) 。也许[NSArray new]
有效,但它没有给你一个简单的NSArray
。
其次,未强制执行类型安全。请考虑以下代码:
id foo = @"foo";
NSArray* bar = foo; // no warning!
因此即使编译器认为bar
是NSArray
,它实际上也是NSString
。如果我们插入您的代码:
id foo = @"foo";
NSArray* bar = foo; // no warning!
NSArray* baz = [bar.class new];
baz
现在也是NSString
。由于您要求bar
的运行时类,编译器与操作无关。
正是由于这种行为,您可能应该使用您知道的类来实例化您的对象,使用[NSArray new]
而不是信任_myArray
为非nil
,并且是你认为的。
答案 2 :(得分:1)
你必须初始化属性,否则它将为nil,向nil对象发送消息,它将返回nil,因此,你必须首先启动数组,如_array = [[NSArray alloc] init];
答案 3 :(得分:0)
所以,对于任何想知道这是否可能的人来说,它是:
objc_property_t property = class_getProperty(self.class, "myArray");
const char * const attrString = property_getAttributes(property);
const char *typeString = attrString + 1;
const char *next = NSGetSizeAndAlignment(typeString, NULL, NULL);
const char *className = typeString + 2;
next = strchr(className, '"');
size_t classNameLength = next - className;
char trimmedName[classNameLength + 1];
strncpy(trimmedName, className, classNameLength);
trimmedName[classNameLength] = '\0';
Class objectClass = objc_getClass(trimmedName);
NSLog(@"%@", objectClass);
输出:
的NSArray
在extobjc的帮助下完成。
答案 4 :(得分:-1)
在Objective-C中,实例变量的实际类仅在运行时确定。所以,你无法知道一个零对象的类。
在您的情况下,这不是问题,因为您只需要这样做:
NSArray *myArray = [NSArray new];
或者
NSArray *myArray = [[NSArray alloc] init];
(尽可能多)
Objective-C是一种面向运行时的语言,这意味着它就是它 可能它会推迟决定实际执行的内容 编译&将实际执行的时间链接到运行时。
这为您提供了很多灵活性,可以重定向消息 根据需要使用适当的物体,或者您甚至可以故意使用 交换方法实现等。
这需要使用运行时 它可以反省物体,看看它们做了什么。不要回应 和适当的派遣方法。如果我们将其与语言进行对比 像C.在C中你开始使用main()方法,然后从那里开始 它几乎是一个遵循你的逻辑和自上而下的设计 在编写代码时执行函数。 C结构不能 转发请求以执行其他目标的功能。