objective c“你忘记了嵌套alloc和init吗?”

时间:2012-01-22 17:35:01

标签: objective-c macos

我刚刚开始攀登Objective C学习曲线(使用Nerd Ranch iOS编程书)。

基于我从其他语言中了解的关于在一行中“嵌套”多次执行的内容,我认为我可以改变:

NSString* descriptionString = [[NSString alloc] initWithFormat:@"%@", possesionName] 

有两行版本:

NSString* descriptionString = [NSString alloc];
[descriptionString initWithFormat:@"%@", possesionName] 

但似乎第二次尝试引发了异常

2012-01-22 18:25:09.753 RandomPossessions[4183:707] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -length only defined for abstract class.  Define -[NSPlaceholderString length]!'

有人可以帮我理解我在这里做错了什么吗?非常感谢。

PS。如果这是Objective C消息的工作方式,你必须让alloc和init在一行中让我知道 - 我假设这只是一组函数,可以一次执行,也可以一个接一个地执行。

3 个答案:

答案 0 :(得分:10)

两个版本之间的一个重要区别(它们并不完全相同)是在第一个版本中,您使用initWithFormat的结果作为变量descriptionString,而使用{{1}的结果}} 在第二。如果您将代码更改为

alloc
一切都应该好了。指定NSString* descriptionString = [NSString alloc]; descriptionString = [descriptionString initWithFormat:@"%@", possesionName] 返回的对象在调用某个alloc方法并且init可能返回其他内容之前不应被视为已初始化且有效。

答案 1 :(得分:3)

alloc方法将为新对象分配内存。但init方法可能会丢弃该内存并返回一个完全不同的对象。或者它可能会返回nil。这就是为什么在覆盖self = [super init]方法时必须始终init

NSString是一个一直在做这种事情的类。

我不确定为什么会发生这种异常,但我相信它可能是ARC在你的两行代码之间注入代码或类似的代码。无论它是什么,有些东西试图对从未初始化的分配对象采取行动,这是一个巨大的问题,可能导致各种问题。认为自己很幸运,它会抛出异常,有时它不会。

NSString类实际上可能不是真正的类。它可能几乎没有方法,几乎​​没有变量。它所拥有的是一堆工厂方法来创建其他类的“真实”字符串对象,这是使用initWithFormat:之类的方法完成的。因此,通过长期约定,alloc / init必须始终在一个语句中完成,并且有一些地方,通常出于性能原因,某些地方将依赖于使用此约定。

基本上,objective-c是一种语言,您不需要知道完全对象内部发生了什么。您只需要知道可以将哪些消息发送到对象,以及它将如何响应。其他任何事情都是未定义的行为,即使您了解它是如何工作的,也可能随时更改,恕不另行通知。有时行为会根据完全不合逻辑的情况而改变,例如,您可能希望“复制”方法为您提供发送给它的对象的副本,虽然这是默认行为,但在很多情况下它都是实际上只会返回具有略微不同的内存管理标志的同一对象。这是因为类的内部逻辑知道返回相同的对象比返回实际的副本更快更有效。

我的理解是copy发送给NSString可能会返回一个新对象,或者它可能会返回自己。它取决于实际使用的NSString子类,甚至没有任何子类存在的文档,更不用说它们是如何实现的。您需要知道的是,copy将返回一个指向对象的指针,该对象非常安全地被视为副本,即使它可能不是。

在像Objective-C这样的“适当的”面向对象语言中,对象是“黑盒子”,可以随时出于任何原因智能地改变其内部行为,但它们的外部行为始终保持不变。

关于避免嵌套... Objective-C的编码风格通常需要大量嵌套,否则当只需要1时,你将编写10行代码。方括号语法特别适合嵌套而不会使代码混乱。

根据经验,我打开Xcode的“列指南页面”功能,并将其设置为120个字符。如果代码行超过该宽度,那么我会考虑将其分成多行。但通常比三条短线更长的路线更清晰。

务实。 :)

答案 2 :(得分:0)

来自Apple的图书馆参考initWithFormat

  

返回通过使用给定编码将给定数据转换为Unicode字符而初始化的NSString对象。

所以你可以使用这两行代码:

NSString* descriptionString = [NSString alloc];
descriptionString = [descriptionString initWithFormat:@"%@", possesionName];

欲了解更多信息,请访问: https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Classes/NSString_Class/Reference/NSString.html#//apple_ref/occ/instm/NSString/initWithFormat