2011-08-26 149 views
0

我来自C#背景,我正在学习Objective-C。我想知道我是否可以对语法做一些澄清。在此先感谢您的帮助。objective c 2.0 - 关键字铸造与非关键字铸造

下面显示的代码行之间有什么区别?鉴于我肯定知道,在 “tempItem” 字典类型是(的NSString *)类型和newsItem.pictureUrl也是(的NSString *):

方案1:

newsItem.pictureUrl = [tempItem objectForKey:@"picture"]; 

方案2:

newsItem.pictureUrl = (NSString *)[tempItem objectForKey:@"picture"]; 

回答

3

我知道你的意思。我也开始喜欢投,因为它清楚地表明你在做什么。但过了一段时间,它变得非常乏味,你学会忽略它。

事实上,没有泛型,容器只存储对象,这有点令人失望,特别是如果你来自泛型语言。这意味着你不断地,明确地在对象和简单类型(例如NSNumber和int之间)之间进行转换,并且除了查询[object class]外,没有办法确保只获得NSString或可以处理的异常。

但演员阵容不会有任何区别。如果返回的对象不是NSString,并且将其转换为一个,则不会产生任何影响。演员没有隐式类型检查,也没有转换。它只是重新解释了返回值。

0

Objective-C实例的类型实际上仅用于确定为创建实例以及静态分析(代码完成,编译等)而分配的适当内存量。在运行时,实例全部由ID的表示,并且对象的实际类型意味着更少。这种动态行为是通过设计的,并且在设计ObjC应用程序时可以提供很大的灵活性。

在典型的ObjC程序中,您将看到很少的类型转换。

1

对象类型间的转换基本上可以只影响两件事情:

  1. 什么警告编译器发出(如“此变量的类没有出现有你想调用的方法” )

  2. 的对象有哪些属性以及它们如何工作(如self.awesome相当于吸气可能是[self awesome][self isAwesome]

它强调不会影响你得到什么样的对象。编译时的静态类型只是编译器的提示。如果你将一个对象转换成它不是的类型,那么你只是对编译器说谎。

在这种特殊情况下,它根本没有任何效果。有些人会这样写代码,但是AFAIK仅仅是因为他们觉得很安慰,就像他们使用静态类型语言一样(即使Objective-C不是)。

0

只有当您希望让编译器了解某个调用的类型时,铸造才是真正必要的,以便它不会给出“可能不会回应”的警告。

1

这两行代码之间没有区别;它纯粹是文体。

这里的方法objectForKey:返回一个类型为id的对象,它是一个通用对象指针。在Objective-C中,id可以隐式转换为任何Objective-C对象类型而无需强制转换。下面的两行是等效的:

id someId = ...; 
NSString *someString = someId; // #1 
NSString *someString = (NSString *)someId; // #2 

这类似于如何在C,void*类型的指针可以隐式转换的指针的任何其它类型不进行强制转换(即也目标C的真,但在Objective-C中不鼓励使用void*指针;即在C++中为而不是为真)。

就类型安全而言,两者都相当不安全。如果该对象的运行时类型实际上是您要将其转换为的类型(不管该类型是明确的还是隐式的)或其子类,那么一切都将按预期工作。如果运行时类型是而不是您期待的内容,那么最有可能的是NSException将与普通的object does not response to selector错误一起抛出,这是由于调用了该类型不存在的函数。由于访问不存在或具有意想不到的值的ivar(因为该对象实际上不是该类型),您可能会因分段错误而崩溃。

如果你不确定该对象的运行时类型的,应检查其运行时类型与-class-isKindOfClass: methods, and then only take action if it's a particular type. Prefer using -isKindOfClass:`,因为这仍与子类的工作,而不是为准确平等类与特定的比较类。例如:

id someId = ...; 
if ([someId isKindOfClass:[NSString class]) 
{ 
    // It's an NSString 
    NSString *someString = someId; 
    // Do stuff with someString... 
} 
+0

非常感谢您的详细说明。 –