Objective c 目标c指针
我有一个财产:Objective c 目标c指针,objective-c,ios,Objective C,Ios,我有一个财产: @property(nonatomic, assign)UIView *currentView; 当我处理以下代码时,为什么它会中断 _currentView =nil; UIView * v1 = [[UIView alloc] initWithFrame:CGRectZero]; _currentView = v1; NSLog(@"_currentView %@", _currentView); NSLog(@"v1 %@", v1); [v1 release]; NS
@property(nonatomic, assign)UIView *currentView;
当我处理以下代码时,为什么它会中断
_currentView =nil;
UIView * v1 = [[UIView alloc] initWithFrame:CGRectZero];
_currentView = v1;
NSLog(@"_currentView %@", _currentView);
NSLog(@"v1 %@", v1);
[v1 release];
NSLog(@"_currentView %@", _currentView); ///break here.
NSLog(@"v1 %@", v1);
我认为\u currentView
和v1
都指向同一个内存。当使用v1
来实现对象,并使用\u currentView
来打印对象时,它将崩溃。我能理解这一点
但是如果在v1
发布之后和打印之前添加以下行\u currentView
。我看不懂日志
v1 = nil;
代码如下所示
_currentView =nil;
UIView * v1 = [[UIView alloc] initWithFrame:CGRectZero];
_currentView = v1;
NSLog(@"_currentView %@", _currentView);
NSLog(@"v1 %@", v1);
[v1 release];
v1 = nil;
NSLog(@"_currentView %@", _currentView);
NSLog(@"v1 %@", v1);
打印结果为:
> 2012-05-30 15:16:57.314 All[3068:15203] _currentView <UIView:
0x81ccbc0; frame = (0 0; 0 0); layer = <CALayer: 0xa07e5a0>>
> 2012-05-30 15:16:57.798 All[3068:15203] v1 <UIView: 0x81ccbc0; frame =
(0 0; 0 0); layer = <CALayer: 0xa07e5a0>
> 2012-05-30 15:16:59.189 All[3068:15203] _currentView <UIView: 0x81ccbc0; frame = (0 0; 0 0); transform = [0, 0, 0, 0, 0, 0]; alpha = 0; layer = (null)
> 2012-05-30 15:17:09.042 All[3068:15203] v1 (null)
问题在于如何声明属性:
@property(nonatomic, assign)UIView *currentView;
@property(nonatomic, retain)UIView *currentView;
应该是:
@property(nonatomic, retain)UIView *currentView;
当您尝试NSLog
时,它将有一个垃圾值,因为您以前释放过它:
[v1 release];
NSLog(@"_currentView %@", _currentView);
请记住,此时,当您尝试
NSLog
it时,v1和\u currentView将指向同一内存块。第二次输出得到不同打印输出的原因如下:
执行后:[v1版本]代码>v1和currentView都指向旧内存块。但是设置v1=nil代码>仅将v1设置为nill,而不是\u currentView(请记住,这些是指针)
我希望这能为你澄清一些事情
亲切的问候,
Bo这不一定与@property
属性(分配或保留)相关,因为您没有使用访问器
这就是代码中发生的情况:
@property(nonatomic, assign)UIView *currentView;
您将ivar声明为assign
,尽管在本例中这与此无关,因为您没有使用self.currentView
或[self-setCurrentView:…]代码>
_currentView = nil;
// You just made your pointer _currentView point to nil or 0
UIView *v1 = [[UIView alloc] initWithFrame:CGRectZero];
// You created an UIView object and made v1 to point to it. (v1 is NOT the real object)
_currentView = v1;
// You just made _currentView to point the same object v1 points to
NSLog(@"_currentView %@", _currentView);
// and because of that you correctly see the object here (because _currentView points to the view object)
NSLog(@"v1 %@", v1);
// also here (because v1 points to the object from the start)
[v1 release];
// now you release the object pointed by v1 , since no other is retaining it, it gets deallocated BUT note that v1 is still pointing to it, which now is garbage memory!)
//NSLog(@"_currentView %@ v1 %@", _currentView, v1);
// If above line were executed the app will crash because of v1 and _currentView both are pointing to the object that was just released and it is not valid anylonger.
v1 = nil;
// Now you made v1 to point to nothing so next time you use it terrible things will not happen (★) :)
NSLog(@"_currentView %@", _currentView);
// Oh no! you called _currentView and since it was still pointing to the object you released a bit ago the app crashes :(
NSLog(@"v1 %@", v1);
// This is fine, you set v1 to point to nil so it is not pointing to some garbage memory you simply get nil.
(★) 因为在objective-c中,将方法发送到nil
是无害的,所以使用nil作为其他方法的参数是另一回事
还有一件事:
即使您编写的是self.currentView=v1;
而不是\u currentView=v1;
结果也将是相同的,因为正确地将声明为assign
如果将属性声明为retain
,情况会有所不同。在这种情况下,在执行[v1 release];
之后,对象将不会被解除分配,因为该对象由currentView保留(self.currentView=v1
)。然后,如果您执行v1=nil
v1将指向nil,并且只有currentView才能访问该对象。
然后,如果您执行\u currentView=nil
操作,则\u currentView将指向nil,但对象本身不会被释放,因为您没有使用附件方法(也没有显式释放),因此您将得到一个悬空指针
并不是所有声明为retain的属性都是解决方案,这是逐案解决的。我建议阅读更多关于Obj-c中内存管理的内容(至少)还有一点关于C指针,然后是关于ARC,只想在nacho4d的答案上加一点。如果你NSLog
一个被解除分配的对象,有时会崩溃,有时不会。当对象被解除分配时,所发生的一切就是它被重新添加到可用内存块列表中。内存的实际内容仍然是看起来像一个对象,在部分或全部块被重用之前,向它发送消息通常是可行的
当您记录解除分配的对象时,可能会发生以下三种情况之一
- 它可以记录下来,就像它还活着一样
- 如果一个完全不同的对象完全在同一个位置启动,它可能会响应
- 你的EXC\u访问权限不好
无论发生哪种情况,很大程度上都是偶然的。您正在声明一个属性,但没有使用它,而是直接使用实例变量。此外,您无法保留变量所指向的内存
看起来您在类中声明了一个实例变量:
@interface MyClass : NSObject {
UIView * _currentView;
}
@end
您所做的是直接访问该属性,而不使用该属性。发生的情况是,在分配内存时,您没有保留内存,这意味着您正在完全释放内存并将其删除。要使其以这种方式工作,您可以执行以下操作:
(请注意,如果要为_currentView指定新值,也需要执行此操作)
另一种方法是实际使用您声明的属性,但使用retain属性:
@property(nonatomic, assign)UIView *currentView;
@property(nonatomic, retain)UIView *currentView;
要使其可访问,您需要在类实现中综合它:
@implementation MyClass
@synthesize currentView = _currentView;
/*...*/
@end
这将为您处理retain。此外,您无需考虑释放存储在变量中的上一个值,因为这将为您处理。但是,您需要通过以下方式访问属性:
self.currentView
您的代码示例如下所示:
UIView * v1 = [[UIView alloc] initWithFrame:CGRectZero];
self.currentView = v1;
NSLog(@"currentView %@", self.currentView);
NSLog(@"_currentView %@", _currentView);
NSLog(@"v1 %@", v1);
[v1 release];
NSLog(@"currentView %@", self.currentView);
NSLog(@"_currentView %@", _currentView); ///Should not break anymore
NSLog(@"v1 %@", v1);
从打印输出中可以看到,这两个变量仍然指向相同的内存。不同的是,由于您保留内存,因此会向内存中添加一个保留计数器。在保留计数器达到0之前,内存不会被释放,这意味着您每次保留内存时都需要释放一次。在后一种情况下,您也可以需要在dealloc方法中释放保留:
-(void)dealloc {
[_currentView release];
}
至于你这一排的最后一个问题
v1 = nil;
只会影响v1指向的地址。它不会影响变量_currentView,也不会影响它指向的内存。最终NSLOG输出的原始格式有误导性。他还需要使用self.currentView=v1
而不是_currentView=v1;
来保留对象,否则将保留相同的内容g将发生:崩溃。我假设他做了@synthesis currentView=\u currentView;
,在这种情况下,他不需要做self。currentView
他只需要做\u currentView
。他的问题实际上与属性声明无关。他根本不在任何代码片段中使用属性。他更关心的是为什么设置v1=nil
会使以下NSLog开始工作。@Jacky Boy:不,这是错误的
v1 = nil;