我已经阅读了在这里和许多其他地方找到的帖子 - 没有答案。
我有一个包含 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
MyItem.M
#import "MyItem.h"
@implementation MyItem
@synthesize Items;
@synthesize TestID;
@synthesize ItemName;
-(id)initWithName:(NSString*)theName
{
ItemName=theName;
Items=[[NSMutableArray alloc]init];
return self;
}
@end
非常简单,创建类后,保留名称并分配数组。 为了让 View Controller 共享此类,我创建了此协议(protocol):
MasterPager.h
#import <Foundation/Foundation.h>
@class MyItem;
@protocol MasterPager <NSObject>
@required
@property (nonatomic,retain) MyItem * currentItem;
-(void)dumpItems;
@end
然后我在我的应用程序委托(delegate)中使用它:
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 );
}
}
(对所有这些文字感到抱歉,但这可能是必需的)。
现在,我有一个 View Controller ,我用它来测试它。 该 View Controller 有 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!但是,当执行此操作时,当行
NSLog(@"current item name:%@", item.ItemName );
已达到。评论该行,一切正常。 取消注释//MyItem * currentItem;不会做任何事。那么,怎么可能呢? NSZombie 已启用?试过了,什么也没做。 目前还没有发布调用,如果有,为什么 NSNumber 转储工作正常? 此外,单击的第一个按钮和第二个按钮之间没有任何反应。 但无论如何,字符串还是消失了!
最佳答案
这是ARC吗?如果没有,那就没那么难,也没那么酷;-)
你将一个自动释放的 NSString 传递给你的 init 方法
MyItem * item=[[MyItem alloc] initWithName :[NSString stringWithFormat:@"Test number %d",i]];
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ autoreleased object
不幸的是,您没有在 init 中保留该自动释放的字符串。
-(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 上的代码格式)
关于iphone - exc_bad_access 来自实例中的 nsstring - 困难,但很酷,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9348630/