iPhone - 使用self初始化变量

时间:2010-10-12 15:18:57

标签: iphone objective-c

所以,假设您在类头文件中声明了一个局部变量NSArray * myArray。

然后在头文件中写下@property (nonatomic, retain) NSArray *myArray

在.m文件中,您可以编写@synthesize myArray

到目前为止一切都很标准。你现在有了一个变量myArray,它可以通过Apple合成的setter和getters来访问。

稍后,您初始化变量。

NSArray *anArray = [[NSArray alloc] initWithObjects etc etc...];
self.myArray = anArray;
[anArray release];

所以现在myArray指向内存中的数组,其释放计数为1(如果我没有记错的话)。

我的问题是,为什么我们不能写

@property (nonatomic, assign) NSArray *myArray;
@synthesize myArray;

..然后通过初始化写

self.myArray = [[NSArray alloc] initWithObjects etc etc...];

自从我第一次看到它以来,这让我很困惑。这有技术原因吗?还是道德? ;-)或理论?

任何帮助都会受到很多赞赏......

干杯

...卡尔

7 个答案:

答案 0 :(得分:5)

其中一个属性点是让我们不必自己考虑内存管理。使属性assign然后将保留对象分配到其中会破坏使用该属性的目的。

这很简单:

@property (nonatomic, retain) NSArray * myArray;
@synthesize myArray;

self.myArray = [NSArray arrayWithObjects:etc, etc1, etc2, nil];

然后所有的内存管理都会为你完成。

答案 1 :(得分:1)

你可以。

我的意思是,这是我在我的程序中所做的,因为我不喜欢使用retain属性^^

它不起作用?什么是错误?

顺便说一句,你可以写

myArray = [[NSArray alloc] initWithObjects etc etc...];

答案 2 :(得分:1)

你可以写:

self.myArray = [[[NSArray alloc] initWithObjects etc etc...] autorelease];

(注意添加自动释放)

虽然写起来会更简单:

self.myArray = [NSArray arrayWithObjects etc etc...];

纯粹主义者可能会争辩说,除非你真的需要,否则你不应该把东西放到自动释放池中,但是如果它让你的代码变得更简单我说要去做,那么在许多/大多数情况下性能开销可以忽略不计。

如果您使用的是assign属性,则需要确保自己释放myArray的旧内容,否则这会消除很多优点和简单性。

答案 3 :(得分:1)

简短的回答是使用assign可能会导致内存泄漏。除非你非常小心。

通过将数组属性声明为retain,您指示该对象应通过向其发送retain消息来获取该数组的所有权,更重要的是,它应该向其发送{release消息。 1}}消息,当它不再有兴趣保持数组。使用assign时,对象不会向任何retainrelease消息发送数组。所以,在你给出的例子中,没有问题。您创建了一个保留计数为1的数组(从概念上讲)并将其赋予您的对象。在这种情况下,数组在内存中挂起,保留计数为1,就像在声明属性时使用retain属性时一样。

当您想要更改myArray的值时,会出现问题。如果您的财产声明为retain,则作业将执行以下操作:

- (void)setMyArray:(NSArray *)newArray {
    if (myArray != newArray) {
        [myArray release];    // Old value gets released
        myArray = [newValue retain];
    }
}

旧的myArray会收到一条release消息,表明该对象已完成。如果保留计数myArray降至零,它将被取消分配并回收其内存。如果使用assign声明属性,则基本上会发生这种情况:

- (void)setMyArray:(NSArray *)newArray {
    myArray = newArray;
}

该对象在myArray处忘记了数组而没有向其发送release消息。因此,myArray之前引用的数组可能不会被解除分配。

所以,这不是分配问题。在重新分配期间未能释放阵列会导致内存泄漏。如果另一个对象拥有该数组,这可能不是问题。

如果另一个对象拥有该数组,并且该数组刚被myArray引用,那么其他对象负责确保数组保持在{{1需要它并在不再需要时释放数组。这是通常用于代表的模式。然后,在其他对象释放它引用的数组之后,您必须小心不要访问myArray

基本上,这归结为谁拥有myArray引用的数组的问题。如果另一个对象拥有它并将根据需要处理保留和释放它,那么您的对象可以简单地引用它。但是,如果您的对象是myArray的所有者(并将在myArray中发布),则使用dealloc属性会更有意义。否则,为了避免泄漏,在调用对象的setter之前,您需要其他对象释放retain的内容,因为您的myArray setter不会为您执行此操作。

答案 4 :(得分:1)

Cocoa(和Cocoa Touch)中的内存管理非常强烈地基于conventions。其中一个惯例是对象拥有他们需要保留的其他对象的所有权,这意味着他们必须正确地保留(声明所有权)和释放(放弃所有权)这些对象。如果您将其设置为assign属性并要求每个调用者为您处理内存,则这违反了内存管理约定。

这也是糟糕的程序设计,因为而不是将一个地方(设置者)与管理该财产有关,而是将责任分散到访问该财产的每个地方。明确区分关注点是设计中最重要的方面之一。

简而言之:您可以按照您的要求进行操作。在各个方面都更糟糕。它违反了Cocoa所做的假设,它使错误更容易发生,它使你的设计变得复杂,并使你的代码膨胀。

但是,如果您要设置self的属性,则可以执行您想要的操作。您可以只编写self.someProperty = [[NSString alloc] initWithString:@"Foo"](假设someProperty = [[NSString alloc] initWithString:@"Foo"]是底层实例变量),而不是编写someProperty。事实上,这是在初始化方法或dealloc方法中执行此操作的常规方法。这允许您简单地在类的内部实现中分配变量,而不需要使用类的每个人为其执行类的内存管理。

答案 5 :(得分:0)

没有理由不能这样做。你只需要特别注意你的记忆。

因为稍后再分配给该属性会发生什么?

使用您的示例:

@property (nonatomic, assign) NSArray *myArray;
@synthesize myArray;

...

self.myArray = [[NSArray alloc] initWithObjects: @"foo", nil];
self.myArray = [[NSArray alloc] initWithObjects: @"bar", nil]; // MEMORY LEAK!

在这种情况下,您必须通过调用release来手动释放您的ivar。如果你不这样做,你就会泄露记忆。

保留(或复制,少易出错)的另一个聪明之处就是你可以说:

self.myArray = nil;

这将释放变量AND将引用设置为nil,这样可以避免让自己陷入麻烦。

我绝对看到了你的观点。要写3行而不是1行更麻烦。您可以作为@willcodejavaforfood建议在您分配保留属性时使用自动释放,因为他似乎错过了)。但是Apple建议你在iPhone上做尽可能少的自动释放,我们总是像好小孩一样听苹果。

<强>更新

当您将属性指定为(非原子,分配)进行综合时,生成的setter代码如下所示:

- (void)setMyArray:(NSArray *)newValue {
    myArray = newValue;
}

另一方面,如果你将其定义为(非原子,保留),你会得到:

- (void)setMyArray:(NSArray *)newValue {
    if (myArray != newValue) {
        [myArray release];
        myArray = [newValue retain];
    }
}

希望它能够解决问题。

答案 6 :(得分:0)

你绝对可以。

使用“assign”属性而不是“retain”属性实际上是一种常见的做法(例如,请参阅Apple的一些核心对象头文件)。这里的问题是你的代码知道这种内存关系(如果属性在任何给定的时间都有内容)。

事实上,有些程序员更喜欢这种模式。完全控制记忆。

但是,我会补充一点,当项目中有多个开发人员时,保护这是一个非常困难的模式,除非他们都是喜欢手动管理内存的类型。通过简单的疏忽,在这种模式中泄漏内存要容易得多,而且编译器在审理这些问题时会有更艰难的时间。