我已经阅读了在这里和其他许多地方找到的帖子-没有答案。

我有一个包含NSString的简单类:


  MyItem.h


#import <Foundation/Foundation.h>
@interface MyItem : NSObject
{
NSString * ItemName;
NSNumber * TestID;
NSMutableArray * Items;
}

//property
@property (nonatomic,retain) NSString * ItemName;
@property (nonatomic,retain) NSNumber * TestID;
@property (nonatomic,retain) NSMutableArray * Items;

// methods
-(id)initWithName:(NSString*)theName;
@end



  我的物品


#import "MyItem.h"
@implementation MyItem
@synthesize Items;
@synthesize TestID;
@synthesize ItemName;
-(id)initWithName:(NSString*)theName
{
    ItemName=theName;
    Items=[[NSMutableArray alloc]init];
    return self;
}
@end


这很简单,因为创建了类,将保留名称并分配数组。
为了使视图控制器共享此类,我创建了以下协议:


  MasterPager.h


#import <Foundation/Foundation.h>

@class MyItem;

@protocol MasterPager <NSObject>
@required
@property (nonatomic,retain) MyItem * currentItem;
-(void)dumpItems;
@end


然后在我的appdelegate中使用:


  ArrayTestAppDelegate.h


#import <UIKit/UIKit.h>
#import "MasterPager.h"

@class ArrayTestViewController;

@interface ArrayTestAppDelegate : NSObject <UIApplicationDelegate,MasterPager>
{
      //MyItem * currentItem;
}
@property (nonatomic,retain) MyItem * currentItem;
@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet ArrayTestViewController *viewController;

@end


我正在应用程序didFinishLaunchingWithOptions中实例化此属性,如下所示:

@synthesize currentItem;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:            (NSDictionary *)launchOptions
{
    // Override point for customization after application launch.
    currentItem=[[MyItem alloc] initWithName:@"main stuff"];
    self.window.rootViewController = self.viewController;
    [self.window makeKeyAndVisible];
    self.viewController.mainPage=self;
    return YES;
}


这是dumpItem方法:

-(void)dumpItems
{
    NSLog(@"Dumping %@",currentItem.ItemName);
    for(int i=[currentItem.Items count]-1;i>=0;i--)
    {
        MyItem * item=[currentItem.Items objectAtIndex:i];
        NSLog(@"current item id:%@", item.TestID );
        NSLog(@"current item name:%@", item.ItemName );
    }
}


(对不起,所有这些文本,但这可能是必需的)。

现在,我有一个视图控制器可以用来测试。
该视图控制器具有2个按钮,每个按钮触发不同的功能。
在此对象中创建一些(4)子项的第一个功能运行良好:

-(IBAction)onCreate:(id)sender
{
    for(int i=0;i<4;i++)
    {
        MyItem * item=[[MyItem alloc] initWithName :[NSString stringWithFormat:@"Test number %d",i]];
        item.TestID=[NSNumber numberWithInt:i];
        [mainPage.currentItem.Items addObject:item];
    }

    [mainPage dumpItems];
}


如您所见,dumpItems被调用,并且它按照预期的方式进行操作,转储对象。

********现在...这是东西!*************

如上所述,还有另一个按钮执行相同的功能:

- (IBAction)onDump:(id)sender
{
    NSLog(@"executing dump on the protocol");
    [mainPage dumpItems];
}


创建后,单击第二个按钮将调用此方法,该方法又调用相同的dumpItems!但是,当执行此命令时,在该行中会抛出一个exc_bad_access

NSLog(@"current item name:%@", item.ItemName );


到达了。评论这行,一切正常。
取消注释// MyItem * currentItem;什么也不会做。那么,怎么可能呢?
NSZombieEnabled吗?试过了,什么也没做。
看不到释放调用,如果存在,那么NSNumber转储如何正常运行?
同样,在单击的第一个按钮和第二个按钮之间没有任何反应。
但仍然,弦以某种方式消失了!

最佳答案

这是ARC吗?如果没有,那不是那么难,也不是很酷;-)

您将自动释放的NSString传递给init方法

    MyItem * item=[[MyItem alloc] initWithName :[NSString stringWithFormat:@"Test number %d",i]];
    //                                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ autoreleased object


不幸的是,您没有在初始化中保留该自动释放的字符串。

-(id)initWithName:(NSString*)theName {
    ItemName=theName;    // <- no retain
}


代码退出init方法,然后在新创建的对象上运行dumpItems

    [mainPage dumpItems]; // <- within same runloop iteration. AutoreleasePool has not be drained.


由于您在当前运行循环结束之前调用dumpItems,因此自动释放的对象仍然存在。

但是IBAction方法在自动释放的对象被释放后发生(当在当前运行循环的末尾释放自动释放池时,对象被释放了)。

    - (IBAction)onDump:(id)sender
    {
        NSLog(@"executing dump on the protocol");
        [mainPage dumpItems]; // <- not in the same runloop. AutoreleasePool has been drained. Autoreleased object has been deallocated
    }


解决方法:

-(id)initWithName:(NSString *)theName
{
    if ((self = [super init])) {
        itemName = [theName retain];            // to match your @property
        items = [[NSMutableArray alloc] init];
    }
    return self;
}




根据Objective-C代码样式指南,仅类名(例如NSString,MyItem)应以大写字母开头。您应该解决此问题以提高可读性(以及stackoverflow上的代码格式)

09-19 11:55