Iphone 内存管理-何时释放?

Iphone 内存管理-何时释放?,iphone,objective-c,memory-management,Iphone,Objective C,Memory Management,我自己学习Objective C已经有一段时间了,但仍然没有完全掌握内存管理的窍门。我应该什么时候发布属性 例如,我有一个类可以处理2个(register&updateParticulars)不同的URLRequest连接。UpdateParticularConnection将在registerConnection完成时执行 @interface ConnectionViewController : UIViewController { } @property (nonatomic, reta

我自己学习Objective C已经有一段时间了,但仍然没有完全掌握内存管理的窍门。我应该什么时候发布属性

例如,我有一个类可以处理2个(register&updateParticulars)不同的URLRequest连接。UpdateParticularConnection将在registerConnection完成时执行

@interface ConnectionViewController : UIViewController {

}
@property (nonatomic, retain) NSURLConnection *registerConnection;
@property (nonatomic, retain) NSURLConnection *updateParticularsConnection;
@property (nonatomic, retain) NSMutableData *responseData;
@property (nonatomic, retain) NSMutableURLRequest *requestURL;

@end

@implementation ConnectionViewController
@synthesize registerConnection, updateParticularsConnection, responseData, requestURL,


(void)performRegistration {
    // other here to prepare the data.
    requestURL = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"myURL"]];
    registerConnection = [[NSURLConnection alloc] initWithRequest:requestURL delegate:self startImmediately:YES];
}

(void)updateParticulars {
    // other here to prepare the data.
     [requestURL setURL:[NSURL URLWithString:@"http:myURL.com"]];
     updateParticularsConnection = [[NSURLConnection alloc] initWithRequest:requestURL delegate:self startImmediately:YES];
}
处理委托回调

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
    [SVProgressHUD dismissWithError:@"Unable to connect"];
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    if (responseData == nil) {
        responseData = [[NSMutableData alloc] init];
    }
    [responseData appendData:data];
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    if (connection == registerConnection) {
        NSMutableString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
        NSLog(@"Register connection recieved data reads : %@", responseString);
        if ([responseString isEqualToString:@"-1"]) { // error. stop connection
            [self.requestURL release]; // remember to release requestURL since we would not be continuing on.
        }   
        else if ([responseString isEqualToString:@""]) { // error. stop connection

            [self.requestURL release]; //remember to release requestURL since we would not be continuing on.
        }

        else {
            [self updateParticulars]; // perform next connection, updateParticulars

        }       
        responseData = nil; // clear the current stored data in preparation for the next connection.
        [self.registerConnection release];
        [responseString release];
    } // end of definition for register connection

    else if (connection == updateParticularsConnection) {
            // do stuff with data received back here 
        self.responseData = nil;
        [self.requestURL release];
        [self.updateParticularsConnection release];
    }       
}

我的问题是,我是否应该尽快释放我的财产,我想这就是我现在正在做的事情?还是仅在dealloc方法期间?如果我做得不对,一定要提出建议。

您在
发布时的备忘:

如果您用于创建对象的方法包含单词
new
copy
alloc
,则您赢得了它,并且在不再需要引用时必须释放它

你说得对

您可以在需要时(如果需要)创建它们,并在不再需要它们时尽快释放它们,这样可以节省内存。 在init中为所有属性和ivar分配内存会减慢实例化过程。 为对象查找内存是Cocoa中最慢的任务之一,您必须尝试在CPU使用和内存消耗之间取得完美的平衡–在这个级别上,您不需要担心CPU使用

在Cocoa中,如果向nil对象发送消息,则不会发生任何事情,因此,如果确定为每个副本调用了release/alloc/retain,则应将其设置为nil


在iOS 5.0中,您可以使用ARC,这完全消除了为cocoa自己进行内存管理的需要,但是您仍然需要为corefoundation和其他基于C的API创建/保留/发布。

您需要根据具体情况进行处理。一般的答案是“一旦你完成了”,除非这是一个微不足道的分配。对于琐碎的分配(例如
NSString*firstName
),您只需等待dealloc或它被替换即可(例如
setFirstName:
)。这仅仅简化了实现

你的例子略有不同

// typically, you will set these to nil right when they 
// have finished and you have grabbed what you need.
// that's pretty common for an async one shot request.
@property (nonatomic, retain) NSURLConnection *registerConnection;
@property (nonatomic, retain) NSURLConnection *updateParticularsConnection;
@property (nonatomic, retain) NSMutableURLRequest *requestURL;

重要提示:您直接在OP中处理实例的IVAR-使用访问器,它们将为您节省大量的麻烦。以下是使用访问器编写程序时所做的更改:

- (void)performRegistration {
    self.requestURL = [[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"myURL"]] autorelease]; // use setter and autorelease
    self.registerConnection = [[[NSURLConnection alloc] initWithRequest:requestURL delegate:self startImmediately:YES] autorelease]; // use setter and autorelease
}

- (void)updateParticulars {
    [self.requestURL setURL:[NSURL URLWithString:@"http:myURL.com"]]; // use getter
    self.updateParticularsConnection = [[[NSURLConnection alloc] initWithRequest:requestURL delegate:self startImmediately:YES] autorelease]; // use setter and autorelease
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    if (self.responseData == nil) { // use getter
        self.responseData = [NSMutableData data]; // use setter and autorelease
    }
    [self.responseData appendData:data]; // use getter
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    if (connection == self.registerConnection) { // use getter
        NSMutableString *responseString = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding]; // use getter
        NSLog(@"Register connection recieved data reads : %@", self.responseString); // use getter
        if ([responseString isEqualToString:@"-1"]) {
            self.requestURL = nil; // use setter
        }
        else if ([responseString isEqualToString:@""]) {
            self.requestURL = nil; // use setter
        }
        else {
            [self updateParticulars];
        }
        self.responseData = nil; // use setter
        self.registerConnection = nil; // use setter
        [responseString release];
    }
    else if (connection == self.updateParticularsConnection) { // use getter
        self.responseData = nil; // use setter
        self.requestURL = nil; // use setter
        self.updateParticularsConnection = nil; // use setter
    }
}

我只对公共类变量使用
@属性
,这些变量可以从该类外部获取/设置。 对于私有变量,如您拥有的
requestURL
,无需创建
retain
ed属性

对于定义中声明为
retain
的每个变量,设置
self.variable
会将保留计数增加1。必须记住这一点,因为最常见的泄漏问题是将属性设置为已保留的值,如
self.myString=[[NSString alloc]init]
。在这里,
myString
的retain count将为2,即使您不希望它出现

那么你的问题是什么时候发布


对于类的dealloc方法中的
@property
,对于私有变量:,无论何时使用它,通常都应尝试将alloc/retain和release保持在相同的范围内。如果该值是一个属性,那么它的作用域对于对象实例是全局的,应该在dealloc方法中释放。如果该值是方法中的局部变量(并且随后没有分配给更全局范围的变量),那么显然必须在该方法中释放它,并且应该尝试在与alloc/retain相同的{}括号内进行释放

例如,如果您发现在代码中的某个点之后不再需要某个属性,您可能会在该点将其置为零,但将该版本保留在dealoc方法中仍然是明智的

对于具有委托的对象,偶尔可以在委托方法中释放对象,但您应该始终在alloc位置记录这一点,并且应该100%确保通过委托的所有“最终”路径都会释放


这些不是硬性规定,但它们会让你远离麻烦。在修改程序的过程中,很容易改变控制流或其他类似的东西,从而导致“巧妙地放置”的版本丢失。通过遵守范围规则,您很少会遇到这样的问题。(并记录范围规则的任何例外情况。)

在ARC下,您需要管理所有C API的内存,因此CoreFoundation、CoreGraphics、GCD、ABAddressBook……这使它更容易,但不会消失。您的意思是我应该使用
self.requestURL=[[nsmutableUrlRequestAlloc]init…
而不仅仅是
requestURL=alloc init
?每当我访问属性时,我都应该检查访问器?任何不应该使用访问器的特殊场合?你的意思是我应该使用self.requestURL=[[NSMutableURLRequest alloc]init…而不仅仅是requestURL=alloc init?-是的。只需添加一个释放或自动释放。每当我访问属性时,我都应该检查访问器?-当你是新手时,是的。随着时间的推移,你会了解到使用直接访问非常理想的一些情况。任何不应该使用访问器的特殊场合?-在正在初始化部分构造的状态(init…,dealloc)。此外,您不应使用
[self.requestURL release]
,而应使用
self.requestURL=nil
。可能重复的
- (void)performRegistration {
    self.requestURL = [[[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:@"myURL"]] autorelease]; // use setter and autorelease
    self.registerConnection = [[[NSURLConnection alloc] initWithRequest:requestURL delegate:self startImmediately:YES] autorelease]; // use setter and autorelease
}

- (void)updateParticulars {
    [self.requestURL setURL:[NSURL URLWithString:@"http:myURL.com"]]; // use getter
    self.updateParticularsConnection = [[[NSURLConnection alloc] initWithRequest:requestURL delegate:self startImmediately:YES] autorelease]; // use setter and autorelease
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
    if (self.responseData == nil) { // use getter
        self.responseData = [NSMutableData data]; // use setter and autorelease
    }
    [self.responseData appendData:data]; // use getter
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
    if (connection == self.registerConnection) { // use getter
        NSMutableString *responseString = [[NSString alloc] initWithData:self.responseData encoding:NSUTF8StringEncoding]; // use getter
        NSLog(@"Register connection recieved data reads : %@", self.responseString); // use getter
        if ([responseString isEqualToString:@"-1"]) {
            self.requestURL = nil; // use setter
        }
        else if ([responseString isEqualToString:@""]) {
            self.requestURL = nil; // use setter
        }
        else {
            [self updateParticulars];
        }
        self.responseData = nil; // use setter
        self.registerConnection = nil; // use setter
        [responseString release];
    }
    else if (connection == self.updateParticularsConnection) { // use getter
        self.responseData = nil; // use setter
        self.requestURL = nil; // use setter
        self.updateParticularsConnection = nil; // use setter
    }
}