Переменная не CFString
Я программирую на Ojective-C всего на месяц и захожу в тупик. Нужна помощь. Вот история:
У меня есть простой класс LXPPlayingCard:
#import <Cocoa/Cocoa.h> @interface LXPPlayingCard : NSObject { @private NSString* cardCV; @private int position; } @property (readwrite, assign) NSString* cardCV; @property (readwrite,assign) int position; @end @implementation LXPPlayingCard @synthesize cardCV; @synthesize position; @end
Также у меня есть чуть более сложный класс LXPDeck:
#import <Cocoa/Cocoa.h> #import "LXPPlayingCard.h" @interface LXPDeck : NSObject { LXPPlayingCard* cards[100]; int deckCapacity; } -(void) fill:(NSString *) cardlist; -(void) showList; -(int) deckCapacity; @end #import "LXPDeck.h" #import "LXPPlayingCard.h" @implementation LXPDeck -(void) fill:(NSString *) cardlist { int l,i,j; l=[cardlist length]; j=0; for (i=0;i<l;i+=2) { cards[j]=[[LXPPlayingCard alloc] init] ; [cards[j] setCardCV:[cardlist substringWithRange:NSMakeRange(i,2)]]; [cards[j] setPosition:j+1]; NSLog(@"%@",[cards[j] cardCV]); j++; } deckCapacity=j; } -(int) deckCapacity { return deckCapacity;} -(void) showList { NSLog(@"deck capacity:%d",deckCapacity); NSString * temp; temp=[[NSString alloc] init]; for (int i=0;i<deckCapacity;i++) { NSLog(@"card[%d]=%d, adress:%p",i,[cards[i] position],cards[i]); temp=[cards[i] cardCV]; NSLog(@"%@",temp); } } @end
которые делают пару вещей: заполняет массив карточек именами (setCardCV) из строки и печатает содержимое колоды (showList). Далее я создаю класс AppController:
@interface LXPAppController : NSObject {
}
-(IBAction) openNewDeck:(NSButton * )sender;
-(IBAction) printDeckContent:(NSButton *)sender ;
@end
#import "AppController.h"
#import "LXPDeck.h"
@implementation LXPAppController
BOOL deckOpened=FALSE;
LXPDeck* workDeck;
-(IBAction) openNewDeck:(NSButton *) sender{
if (!deckOpened) {
NSLog(@"Opening new deck...");
workDeck=[LXPDeck alloc];
[workDeck fill:@"pacataca"];
}
deckOpened=TRUE;
}
-(IBAction) printDeckContent:(NSButton *) sender {
if (deckOpened) {
NSLog(@"Printing deck content...");
[workDeck showList];
}
}
@end
и две кнопки в основных окнах, с которыми я связался openNewDeck
а также printDeckContent
методы. Проблема в том, что приложение падает с ошибкой "EXC_BAD_ACCESS", и это происходит на i
=3 потому что (когда я использую отладчик) [card[i] cardCV]
не является CFString.
Я пробовал с разными строками заполнить колоду, и иногда программа проваливалась на первом круге показа [cards[i] cardCV]
, Я действительно не понимаю, что происходит, но я думаю, это как-то связано с указателями и правилами выделения памяти, потому что нет проблем с простыми типами данных (position
например) и showList
метод работает правильно, если он вызывает из fill
метод. Пожалуйста, дайте мне руку! Я схожу с ума! Программа настолько проста, что я очень переживаю из-за проблем в будущем кодировании...
1 ответ
Проблема в том, что
[cardlist substringWithRange:NSMakeRange(i,2)]]
возвращает NSString
что вам не принадлежит. Поскольку вы не владеете им, нет никакой гарантии, что строка будет действительна в течение всего времени жизни вашего LXPPlayingCard
объект. Если вы хотите сохранить действительную ссылку на эту строку, вы должны изменить объявление LXPPlayingCard
таким образом cardCV
собственность становится copy
собственность вместо assign
один. Заменить:
@property (readwrite, assign) NSString* cardCV;
с:
@property (readwrite, copy) NSString* cardCV;
Делая это, когда вы отправляете -setCardCV:
лайк:
[cards[j] setCardCV:[cardlist substringWithRange:NSMakeRange(i,2)]];
setCardCV
скопирую свой аргумент, [cardlist substringWithRange:NSMakeRange(i,2)]
и ваш объект будет владеть этой строкой. Это означает, что строка останется действительной на протяжении всего жизненного цикла этого объекта. Помните, что, поскольку вы взяли на себя ответственность за эту строку, вы несете ответственность за ее выпуск. Следовательно, вам необходимо реализовать -dealloc
метод:
- (void)dealloc {
[cardCV release];
[super dealloc];
}
Это означает, что когда соответствующий LXPPlayingCard
освобождается, строка хранится в cardCV
выпущен тоже.