好吧,我仍然对目标c属性和实例变量感到困惑。 我在viewDidLoad中创建了一个LocationManager对象。一方面,LocationMan只是一个实例变量,另一方面它被声明为属性。看看这些例子:
第一个例子:
部首:
CLLocationManager* _locationMan;
实现:
CLLocationManager* theManager = [[[CLLocationManager alloc] init] autorelease];
_locationMan = theManager;
_locationMan.delegate = self;
第二个例子
部首:
CLLocationManager* _locationMan;
@property (retain, nonatomic) CLLocationManager* locationMan;
实现:
self.locationMan = [[[CLLocationManager alloc] init] autorelease];
self.locationMan.delegate = self;
这些例子之间的区别是什么,除了第二个是工作而第一个没有?内存管理会发生什么?
答案 0 :(得分:3)
您在第一个示例中遇到的问题:
CLLocationManager* theManager = [[[CLLocationManager alloc] init] autorelease];
是由使用autorelease
引起的。 autorelease
可以被视为含义:在不久的将来的某个时刻,release
会自动显示此对象。给定autorelease
的实现方式,通过发布池,这通常在下一次控制流返回主循环并且释放池被清空时发生。
因此,在您的第一种情况下,您正在创建对象并将其存储在您的ivar中;但很快它就会被释放,而且由于你没有在其他任何地方明确地保留它,它最终会被释放。之后访问它时,会出现错误。如果你没有使用autorelease
,一切都会正常工作:
CLLocationManager* theManager = [[CLLocationManager alloc] init]; //-- this is correct
_locationMan = theManager; //-- because you assign directly to the ivar
在你的第二个例子中,创建是一样的,这意味着,对象也将被标记为自动释放。但是,在这种情况下,您将其分配给具有retain
修饰符的属性。这意味着在分配属性时将自动保留对象。因此,当自动释放实际完成时(粗略地回到主要外观),您的对象已经将其保留计数递增1;然后自动释放它不会使其保留计数变为0,并且该对象将不会被释放。
你必须清楚知道的是:
alloc
会将保留计数设置为1;
retain
属性会在分配时增加保留计数;
autorelease
就像一个延迟发布,所以在同一时间(在发布实际完成之前,这意味着在你的方法的其余部分和调用者到主循环之前)你可以使用对象安全,然后将被释放。
答案 1 :(得分:1)
我在代码中标记了保留的更改,可能会更清晰。
CLLocationManager* theManager = [[[CLLocationManager alloc] init] autorelease];
^^^^^ + 1 ^^^^^^^^^^^ - 1 = 0
_locationMan = theManager;
当您的保留值降至0时,该对象不再存在。下次您尝试访问它时,您的应用程序崩溃。由于自动释放,这将在您的自动释放池耗尽后,在您离开当前方法后的未来未知点发生。
self.locationMan = [[[CLLocationManager alloc] init] autorelease];
^ + 1 ^^^^^ + 1 ^^^^^^^^^^^ - 1 = +1
您仍然保留该对象。你必须稍后发布它,但你可以毫无问题地访问它。
答案 2 :(得分:0)
在第一个实例中,您没有经过合成的setter,它负责保留对象。在这种情况下,当theManager
被自动释放时,_locationManager
不会保留任何内容,因此theManager
会被取消分配。
第二种情况使用合成的setter(因为它通过self
调用它),因此它在自动释放后保留theManager
。