iphone - exc_bad_access 来自实例中的 nsstring - 困难,但很酷

标签 iphone ios nsmutablearray protocols exc-bad-access

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

我有一个包含 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/

相关文章:

ios - 带条件的 NSArray componentsJoinedByString

iphone - iOS 5 中字典/定义词的 View Controller

iphone - GLSL ES 2.0(适用于 iPhone/iPod touch/iPad)中的 highp float 的精度是多少?

ios - ViewController 与文档提供程序中的系统导航栏重叠

objective-c - 在 UITableView Objective-C 中的每一行附近添加标签颜色

ios - 创建具有最大大小并在添加更多项目时删除项目的 NSMutableArray 的最佳途径是什么?

iphone - iPhone 上的下一个/上一个按钮 MPMoviePlayerController

ios - UIView over UIScrollView 阻止它滚动

ios - 删除 SwiftyJSON 数组中的字典记录

iOS:存储联系信息和 GPS 坐标的最佳方式