exc_bad_access из nsstring в экземпляре - HARD, НО COOL - PullRequest
0 голосов
/ 19 февраля 2012

Я прочитал сообщения, которые я нашел здесь и во многих других местах - без ответов.

У меня есть простой класс, который содержит 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; ничего не сделаю. Итак, как это может быть? NSZombieEnabled? Пробовал, ничего не делал. В данный момент не существует никакого вызова релиза, и если так было, почему дамп NSNumber работает просто отлично? Кроме того, ничего не происходит между первой нажатой кнопкой и второй. но все же струны как-то исчезают ...! Любая мысль будет оценена!

Ответы [ 2 ]

1 голос
/ 19 февраля 2012

это 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)

0 голосов
/ 07 ноября 2014

У меня была такая же проблема, вы должны изменить код с:

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