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

发布于 2025-01-07 17:51:10 字数 3517 浏览 6 评论 0原文

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

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

非常简单,创建类、保留名称并分配数组。 为了让视图控制器共享此类,我创建了此协议:

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;不会做任何事。那么,怎么可能呢? NSZombie 已启用?试过了,什么也没做。 目前还没有发布调用,如果有,为什么 NSNumber 转储工作正常? 此外,单击的第一个按钮和第二个按钮之间没有任何反应。 但无论如何,绳子还是消失了!

I have read the posts I found here and in many other places - no answers.

I have a simple class that contains 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

It is very simple, as the class is created, the name is retained and the array allocated.
In order to have view controllers sharing this class, I have created this protocol:

MasterPager.h

#import <Foundation/Foundation.h>

@class MyItem; 

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

which I then use in my 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 

I'm instanciating this property in the application didFinishLaunchingWithOptions as so:

@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;
}

and here is the dumpItem method:

-(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 );
    }
}

(Sorry for all this text, but it is probably required).

Now, I have a view controller that I use in order to test this.
This view controller has 2 buttons, each of them triggers different function.
the first function to create some (4) sub items in this object is working fine:

-(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];
}

As you can see the dumpItems is called and it does what its suppose to do, dumping the objects.

********NOW... here is the thing!*************

There is a second button, as mentioned, that execute the same function:

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

After creation, clicking the second button is calling this method which in turn calls the same dumpItems! BUT, when this is executed, an exc_bad_access is thrown when the line

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

is reached. comment the line and it's all working.
un-commenting the //MyItem * currentItem; will do nothing. So, how could it be?
NSZombieEnabled ? Tried that, did nothing.
There is no release call in sight, and if there were, how come the NSNumber dump working just fine?
Also, nothing happen between the first button clicked and the second one.
but still, the strings somehow disappears!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

说不完的你爱 2025-01-14 17:51:10

这是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 上的代码格式)

is this ARC? If not, it's not that hard, and not that cool ;-)

You pass an autoreleased NSString to your init method

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

Unfortunately you don't retain that autoreleased string in your init.

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

the code steps out of the init method and you run dumpItems on the newly created object

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

since you call dumpItems before the end of the current runloop the autoreleased object still exists.

But the IBAction method happens after the autoreleased object has been deallocated (the object was deallocated when the autorelease pool was drained at the end of the current runloop).

    - (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
    }

the fix:

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

By the objective-c code style guidelines only Class names (e.g. NSString, MyItem) should start with a capital letter. You should fix this to improve readability (and the code formatting on stackoverflow)

孤寂小茶 2025-01-14 17:51:10

我遇到了同样的问题,您应该将代码从: 更改

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

为:

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

I had the same problem, you should change the code from:

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

to:

@property (nonatomic,copy) NSString * ItemName;
@property (nonatomic,copy) NSNumber * TestID;
@property (nonatomic,copy) NSMutableArray * Items;
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文