我已经阅读了在这里和其他许多地方找到的帖子-没有答案。
我有一个包含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上的代码格式)