Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/120.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c 目标c指针_Objective C_Ios - Fatal编程技术网

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;