内存管理 - 何时发布?
我一直在学习Objective C,已经有一段时间了,仍然没有完全掌握内存管理。我应该何时发布属性?内存管理 - 何时发布?
实施例,我有一个类将处理2(寄存器& updateParticulars)不同的URLRequest连接。 updateParticularsConnection将在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方法期间?如果我做得不对,请指教。
你有必要把它在个案的基础上。一般的答案是“一旦你完成了它”,除非它是一个微不足道的分配。对于普通的分配(例如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;
和
// in the context of your program, this allocation could be large.
// in many cases, you'll simply convert it to the destination (if
// it's an image, just turn it into an image without holding onto
// the data representation), then dispose of it.
@property (nonatomic, retain) NSMutableData *responseData;
重要:你直接处理您的实例的实例变量在OP - 使用访问器,他们会为你节省大量的头痛。这些都是你会做使用存取写程序的变化:
- (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
}
}
你的意思是我应该使用'self.requestURL = [[NSMutableURLRequest alloc] init ...'而不是'requestURL = alloc init'?每当我访问属性,我应该经常访问访问器?任何不应使用访问器的特殊场合? –
*你的意思是我应该使用self.requestURL = [[NSMutableURLRequest alloc] init ...而不是仅仅requestURL = alloc init?* - 是的。只需添加一个版本或autorelease。 *当我访问属性时,我应该经常访问访问者?* - 当你是新的,是的。随着时间的推移,您将了解到使用直接访问的理想情况。 *任何不应使用访问器的特殊场合* - 不要在部分构建的状态(init ...,dealloc)中使用它们。 – justin
也是,你不应该使用'[self.requestURL release]',而是'self.requestURL = nil'。 – justin
上release
备忘单:
如果您使用的方法来创建一个对象包含文字
new
,copy
或alloc
然后你赢得了,将不得不释放它,一旦你不需要更多的参考。
你是对的。
时(如果)你需要他们,只要你不需要他们了释放他们可以创建他们,这样你会节省内存。 为init中的所有属性和iVar分配内存可能会减慢实例化过程。 寻找对象的内存是Cocoa中最慢的任务之一,您必须尝试在CPU使用率和内存消耗之间取得完美平衡 - 您无需担心此级别的CPU使用率。
可可如果您发送邮件至零对象没有任何反应,所以如果你确信你叫释放每拷贝/分配/保留,那么你应该将其设置为零。
中的iOS 5.0,你可以使用ARC可以完全消除需要做内存管理可可自己,你仍然需要,虽然做的建立/保持/对的CoreFoundation及其他基于C的API的释放。
在ARC下,你需要管理所有C API的内存,所以CoreFoundation,CoreGraphics,GCD,ABAddressBook ......它使它更容易,但它不会让它消失。 – Abizern
我使用@property
仅可获取/从这个类的外部设置的公共类变量。 对于像requestURL
这样的私有变量,您不需要创建retain
ed属性。
对于定义中声明为retain
的每个变量,设置self.variable
都会将保留计数增加1。必须牢记这一点,因为最常见的泄漏问题是将属性设置为已保留的值,如self.myString = [[NSString alloc] init]
。这里,myString
即使不期望,也会保留2。
那么你的问题什么时候发布?
对于@property
:在类的dealloc方法和私有变量:当你使用它完成。
您通常应该尝试在同一范围内保持alloc/retain和release。如果该值是一个属性,则它的范围对于对象实例是全局的,并且应该在dealloc方法中释放。如果该值是方法中的局部变量(并且随后不会被分配给更具全局作用域的变量),那么您显然必须在该方法中释放它,并且您应该尝试在相同的{}括号内你在哪里做了分配/保留。
如果你发现你在你的代码的某个点之后不再需要一个属性,那么你可以在那个时候删除它,但将版本留在dealloc方法中仍然是明智的。
对于具有委托的对象,它偶尔会在委托方法中执行对象的发布,但您应该始终将其记录在alloc位置,并且应该100%确定所有通过委托的“最终”路径做释放。
这些都不是硬性/快速规则,但它们会让你摆脱困境。在修改程序的过程中,改变控制流或其他一些因素,导致错误放置“巧妙放置”的版本非常容易。通过观察范围规则,您很少会遇到这样的问题。 (并记录范围规则的任何例外情况。)
[Objective-C内存管理的可能的重复:何时\ [释放\]?](http://*.com/questions/3012001/objective-c内存管理什么时候发布) –