【问题标题】:leaking memory issue, memory management内存泄漏问题,内存管理
【发布时间】:2012-05-19 09:21:20
【问题描述】:

我现在拥有的是

classA.h

@interface ClassA: NSObject <DelegateA>
-(id)initWithData:(NSData*)data;
+(Stores*)makeClass:(Class) name fromData:(NSData*)data;
@property (assign) NSMutableArray    *arr;
@property (assign) RXMLElement       *rxmlRoot;
@end

classA.m

   -(id)initWithData:(NSData*)data { 
        self = [super init]; 
        if (self) { 
            arr      = [[NSMutableArray array] retain]; 
            rxmlRoot = [[RXMLElement elementFromXMLData:data] retain]; 

        } 

        [rxmlRoot iterate:node with:^(RXMLElement *e){   <--------get warning at here
            NSLog(@"element is %@",e.tag);
            Detail   *detail  =   [[[Detail alloc] init] autorelease];
            [detail setLat:       [e attribute:@"lat"]];
            [detail setLon:       [e attribute:@"lon"]];

            [arr addObject:detail];

        }];
        return self; 
        }

      +(classA*)makeClass:(Class) name fromData:(NSData*)data{
            ClassA  *classA =   [[ClassA alloc] initWithData:data];
            return [storeClass autorelease] ;

        }

和 RaptureXML.m

+ (id)elementFromXMLData:(NSData *)data {
    return [[[RXMLElement alloc] initFromXMLData:data] autorelease];
}
- (id)initFromXMLData:(NSData *)data {
    if ((self = [super init])) {
        xml_ = [[TBXML alloc] initWithXMLData:data];
        tbxmlElement_ = xml_.rootXMLElement;
    }

    return self;    
}

警告:实例变量访问(通过'self')导致空指针取消引用

问题:为什么我会收到此警告以及如何解决此问题。 请就此给我建议。谢谢

【问题讨论】:

  • 是classA中的第一个和第三个classA *classA = [[classA alloc] initWithData:data];小写,因为它是一个错字?
  • 谢谢。我刚刚编辑过

标签: iphone objective-c memory-management


【解决方案1】:

尝试将所有初始化代码放入

if (self) {

}

即移动 [rxmlrRoot 迭代...等。进入那个 if 语句

作为一般规则,所有初始化语法(init 方法中的所有内容!)都应该在 if (self) 块中。原因是当超类返回 nil 时,该块之外的代码将运行(想想 else if (!self) {...)。如果未调用超级方法(初始化程序只是 O-C 中的常规方法),您不希望代码继续执行。

我还被教导在我的自定义类中始终有一个指定的初始化程序(这是调用 super init 的那个),我的类中的所有其他初始化程序然后调用这个指定的初始化程序。例如。

// Designated initializer
- (id)init
{
    self = [super init];
    if (self) {
        // initialize some stuff
    }

    // else { something went wrong and super returned nil..
    // don't put anything here

    return self;
}

// Another initializer
- (id)initWithFoo:(int)foo
{
    self = [self init]; // Now i call my designated initializer instead of super
    if (self) {
        self.foo = foo; // or something
    }
}

这使您可以控制从那一点开始的所有流量。

【讨论】:

  • 谢谢,警告消失了,但我也需要对警告进行解释。
  • 你说 self 可能是 nil,所以编译器说 - 在 self 是 nil 的情况下,当你到达使用其他 nil 的代码时,你会崩溃,比如 'arr' .你当然“知道” self 永远不会为零(如果你的内存太少,你肯定会崩溃!) - 但编译器不知道。
  • @ttran 汤姆所说的完全正确,我已经为答案添加了解释。类似问题:stackoverflow.com/questions/10246945/…
【解决方案2】:

在调用[rxmlRoot iterate:node with:^(RXMLElement *e){ ... }]中,节点是什么?它不是局部变量,也不是 iVar。它是全球性的还是存在于其他地方?

不管它是什么,检查以确保它已被初始化。

【讨论】:

    【解决方案3】:

    在块内部,通过引用访问实例变量arr。由于微妙的内存管理规则,访问导致self被块保留。

    由于if (self) 是编译器提示self 可能为nil,因此块隐式保留self 可能会导致空指针取消引用。

    要修复,检查 nil 并提前退出:

    if (!(self = [super init])) {
        return nil;
    }
    
    // now it is impossible for self to be nil and cause a null pointer dereference
    // when self is implicitly retained by the block
    
    // ...continue initialization
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-08
      • 2016-07-28
      相关资源
      最近更新 更多