关于Objective-C,Cocoa和Xcode的一些问题

时间:2009-07-26 19:46:44

标签: objective-c cocoa xcode

  1. 使用object初始化NSMutableArray数组时,为什么将nil放在最后?

    e.g。

    NSMutableArray *fruits = [[NSMutableArray alloc] initWithObjects:apple,
                                                                     watemelon,
                                                                     nil];
    
  2. 在Xcode中,使用auto complete填写函数变量时。什么是跳转到下一个变量的捷径?

    例如:

    Fruit *fruit3 = [[Song alloc] initWithName:(NSString *)n
                                   description:(NSString *)d    
    

    我正在输入initWithName功能并自动完成。所以,我立即按Tab键前往n,完成后,我如何到达d

  3. 如果我有一个带有水果对象的水果数组,如问题1,水果对象是NSObject子类。为什么在我的Fruit类的@property声明中声明了“复制”。

    当我知道默认情况下,水果对象将驻留在自己的内存空间中。因为我正在创造一个水果指针。 Fruit *apple = [[Fruit alloc]....

  4. NSString *a = @"Hello Everyone";

    @""做了什么?

    它是否像这样:

    [[NSString alloc] initWithValue:"ok"];
    

3 个答案:

答案 0 :(得分:8)

  1. 该方法使用C中的变量参数列表(,...在C函数声明中)实现,在这种情况下参数的数量是未知的。因此,您必须使用nil(0)值关闭列表。
  2. 控制 - /
  3. 因为NSArray是一个指针数组。如果分配数组而不复制它,则其他对象(引用数组)可以修改数组。使用副本,您可以确保不会在课堂外更改数组的元素。
  4. @“xyz”contruct将返回一个自动释放的NSString。所以它会像[[[NSString alloc] initWithUTF8String:“xyz”] autorelease]。

答案 1 :(得分:4)

  1. C中的变量参数(因此,在Objective-C中)是非常原始的。该方法只获取指向堆栈的指针,并且必须有一个机制来计算参数的类型和数量。对于printf和类似的,它的格式代码; for -initWithObjects:,它是一个哨兵,即表示列表末尾的已知值,在这种情况下为零。
  2. 首选项 - >键绑定 - >文本键绑定 - >代码检测选择下一个占位符。
  3. 请考虑以下事项:
  4. NSMutableString *str = [NSMutableString stringWithString:@"Fred"];
    fruit.name = str; // Legal; NSMutableString is a subclass of NSString
    [str setString:@"Barney"];

    如果fruit.name未声明为复制属性,则最后一行将更改水果的名称(因为fruit.namestr引用同一个对象)。如果它被声明为副本,则它们将是单独的对象。 (但是,如果使用普通的NSString对象,则不会进行任何复制,因为NSString是不可变的,并且引用同一个对象没有问题。

答案 2 :(得分:3)

以下是对问题1的更完整的解释。与Java,C#,Python,Ruby等语言相比,C和Objective-C是相当低级的语言。在C和Objective-C中,允许使用具有可变数量参数的函数(所谓的 varargs 可变参数函数),但该语言不提供用于知道数字的机制实际传入的参数。高级语言通常通过将额外参数公开为对象的列表或数组来提供此功能。 C和Objective-C使用一组更有限的宏来一次访问一个额外的参数。

因此,因此,任何可变函数都需要一些其他方法来确定传递的实际参数数量。函数及其类似printfscanf系列使用格式字符串作为固定参数之一,格式字符串中的格式说明符表示传入的额外参数的数量和类型。另一方面,Objective-C类-initWithObjects:的{​​{1}}消息要求使用NSMutableArray终止额外参数列表。因此,您不能将nil作为参数传递(因为它会标记参数列表的结尾),但在这种情况下可以正常,因为nil指定它们不能包含{ {1}} objets。

在x86架构上,使用C调用约定(cdecl)实现可变参数函数,从而将参数从右到左推入堆栈。呼叫者负责清理堆栈。因此,对NSMutableArray的调用可能会编译成这样的内容:

nil

从右到左而不是从左到右推送参数的原因是堆栈向下向下 - x86 printf()指令递减堆栈指针{{ 1}} 4个字节。因此,当被调用函数检查堆栈时,它将以正确的顺序看到参数。在第一次调用// ignore the fact that these are invalid calls to printf printf("format string 1", a1, a2); printf("format string 2", b1, b2, b3); // The above might get compiled into this: push a2 push a2 push <address of "format string 1"> call printf add $12. %esp // restore stack pointer to offset the pushes push b3 push b2 push b1 push <address of "format string 2"> call printf add $16, %esp // restore stack pointer 之后,堆栈就像这样:

%esp+0x00: return address to calling function
%esp+0x04: address of "format string 1">
%esp+0x08: a1
%esp+0x0c: a2
%esp+0x10 and above: local variables from calling function, rest of stack

当被调用的函数检查它的参数时,它只是遍历堆栈,但它不知道在哪里停止 - 调用约定没有指定有多少参数。该功能只需要通过其他方式知道。大多数函数都有固定数量的参数,因此对它们来说很容易,但是可变函数需要一些其他方法来确定参数的确切数量。

如果函数认为传递的参数数量与实际传递的数量之间存在不匹配(例如,将错误的格式字符串传递给push),则会导致错误。最可能的情况是该函数将继续读取堆栈,并且您将在某处获得垃圾值。更糟糕的是,您的程序可能会崩溃。更糟糕的是,您的程序似乎可以正常工作,但您可能无意中打开了一个安全漏洞。