保留,分配,属性......让您的Obj-c生活更轻松的主题!

时间:2010-03-22 23:24:06

标签: iphone nsarray equals allocation retain

我的代码越多,我就越迷失...所以我决定为我(以及其他人)创建一个完全专注于内存管理的主题,而不是浪费时间来理解对象基础......我会在提出新问题时更新它!

以下是一些例子:

// myArray is property (retain)
myArray = otherArray;

//myArray isn't a property
myArray = otherArray;

//myArray is a property (retain)
myArray = [[NSArray alloc] init];

//myArray isn't a property
myArray = [[NSArray alloc] init];

---所以,如果我理解......当你把self.myArray放到Xcode上时你会告诉Xcode使用getter或setter但是当你只是做myArray时,你对所有事情负责,对吗?

[已解决] UPDATE1 :之间有区别吗?

//myArray is a property
myArray = otherArray; // it is only a reference, releasing otherArray will imply releasing myArray
self.myArray = otherArray; // otherArray is sent a retain message so releasing otherArray will still keep myArray in memory

---是的,有区别(见上面的评论)

[已解决] UPDATE2: myArray是否等于nil?

NSArray *myArray;

--- Kubi:是的,它等于零。

[已解决] UPDATE3:是否会计入2个保留期?一个保留自己,一个保留来自alloc?这是内存泄漏吗?

self.myArray = [[NSArray alloc] init];

--- Kubi:是的,这是内存泄漏!

[已解决] UPDATE4:该酒店负责一切?无需分配或发布?

self.myArray = [NSArray array];

---我们在这里使用setter以便正确保留数组

[已解决]更新5:这两个区块是否相同?

//myArray is a retained property

self.myArray = [NSArray array]; //retain
self.myArray = nil; //release and set to nil

myArray = [[NSArray alloc] initWithArray]; //retain
self.myArray = nil; //release and set to nil

--- Kubi:是的,他们是相同的

感谢您的时间。

高堤耶。

3 个答案:

答案 0 :(得分:6)

首先,我假设您有一个名为myArray的属性和一个名为myArray的iVar?如果是这样,情况1,2是相同的,3,4是相同的。如果需要设置当前类的属性,则必须通过以下方法之一进行:

self.myArray = otherArray;
[self setMyArray:otherArray];

myArray = otherArray行只会设置iVar,而不是属性。

第二部分,你要问的是内存管理。第一步:阅读Apple's Guide。这真的是需要阅读。不要担心,如果你不完全理解,每月阅读一次,它最终会结晶。

第二步:记住这条经验法则:如果你是alloccopynewretain一个对象,你有责任释放该对象,如果你没有,它会被泄露。

在所有其他情况下,您不负责释放对象,但它最终会被释放。如果你需要保留它,你需要retain它(当然,稍后再发布)。

回到你的例子,在前两种情况下,如果你不保留myArray,它将在此代码块之后的某个时刻被释放。如果您稍后尝试发送该对象,则会收到错误消息。在后两种情况下,如果您在某个时刻没有释放myArray对象,它将被泄露。


更新1 差别很大。这两行完全不同。关于点语法的重要一点是这两行完全等价:

self.myArray = otherArray;
[self setMyArray:otherArray];

注意第二行是方法调用。从理论上讲,你可以在这种方法中放置任何你想要的东西。您可以将myArray设置为nil,或将其设置为someOtherArray,或更新Twitter或其他内容。


更新2 是的,Obj-C中的指针初始化为nil。


更新3 究竟。如果myArray属性声明为retain并且您使用的是默认合成器,则会导致内存泄漏。

更新5 也完全正确。

答案 1 :(得分:5)

Kubi的回答很好。重读Apple的指南直到你理解它是非常强制性的。

与此同时,您可以采用我遵循的这一套严格的做法,以避免意外的内存错误。这些规定的输入比严格必要的更多,并且它们在运行时的效率可能比它们可能略低,但是遵循这些规则将始终保护您免受最常见的内存管理错误的影响。然后,当您对内存管理变得更加熟悉时,您可以选择偏离这些规则,尽管我仍然很少这样做。

  1. 为您创建的每个对象实例变量声明一个属性。将其声明为(非原子,保留),除非它是您的类不拥有的对象,如委托,它将创建循环引用。在这种情况下,将其声明为(非原子,赋值)以避免泄漏该循环中的所有对象。

    @property (nonatomic, retain) NSString *title;
    @property (nonatomic, assign) id <WidgetDelegate> delegate;
    

  2. 即使对象实例变量仅供类私有使用,也要在.m文件顶部的类扩展中为其声明一个属性,以便合成的setter方法可以处理内存为您管理。

    // Widget.m
    @interface Widget()
    @property (nonatomic, retain) NSString *privateState;
    @end
    
    @implementation Widget
    @synthesize title, delegate, privateState;
    // ...
    @end
    
  3. 每次分配实例变量对象时,请始终使用self设置属性。

    self.title = @"Title";

  4. 在你的dealloc中,将每个object属性设置为nil。如果您已遵循上述做法,则会同时正确释放您的实例变量并将其设置为nil以防止EXC_BAD_ACCESS。将dealloc设为您班级中的第一个方法,这样您就不会忘记任何属性。

    - (void) dealloc {
        self.title = nil;
        self.delegate = nil;
        self.privateState = nil;
        [super dealloc];
    }
    
  5. 对于您编写的每个自定义类,请确保它至少有一个类工厂方法,该方法委托给具有相同参数的init方法,并自动释放返回的对象。这几乎限制了对这些工厂方法的所有alloc和init调用,而不是将它们分散到整个代码中。

    - (id)initWithTitle:(NSString *)theTitle delegate:(id )theDelegate {
        if (self = [super init]) {
            self.title = theTitle;
            self.delegate = theDelegate;
            self.privateState = @"start";
        }
        return self;
    }
    + (id)widgetWithTitle:(NSString *)theTitle delegate:(id )theDelegate {
        return [[[self alloc] initWithTitle:theTitle delegate:theDelegate] autorelease];
    }
    
  6. 每当您实例化一个对象时,如果可能,请始终通过工厂类方法执行此操作。这为您提供了一个自动释放的对象,因此除非您保留它,否则不必释放它。

    self.widget = [Widget widgetWithTitle:@"My Widget" delegate:self];
    
  7. 当您需要实例化没有适当工厂类方法的对象时,请在同一行自动释放它,因此您不要忘记稍后再执行此操作。 (例外:如果您在紧密循环中执行了数千次,则手动释放。)

    self.containerView = [[[UIView alloc] initWithFrame:self.bounds] autorelease]; 
    
  8. 如果您要释放具有委托或类似属性的对象,该对象指向循环引用,请先将该属性设置为nil。如果一个对象超过其委托并尝试在该代理被解除分配后调用该委托上的方法,则会阻止EXC_BAD_ACCESS。

    - (void)dealloc {
        self.widget.delegate = nil;
        self.widget = nil;
        self.containerView = nil;
        [super dealloc];
    }
    
  9. 许多有经验的开发人员成功管理内存而不遵循所有这些做法。如果您了解内存管理并且不会有与内存相关的错误,我当然鼓励您坚持使用适合您的内容。但是,如果您是iPhone内存管理的新手,或者您的代码受到意外内存相关错误的困扰,我希望您发现这些实践与我一样有用。

答案 2 :(得分:0)

找到答案的最佳位置是in the relevant Apple documentation that explains all about memory management。话虽如此,你只是在这里使用ivars,你没有使用ObjC生成的setter设置你的ivar。正如库比所说,你不得不说

self.myArray = otherArray;

为了使用myArray的“属性”。