0

我在 Ojective-C 上编写了一个月的代码并陷入僵局。需要帮忙。这是故事:

  1. 我有一个简单的类 LXPlayingCard:

     #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
    
  2. 此外,我几乎没有更复杂的 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

以及我链接到的主窗口上的两个按钮openNewDeckprintDeckContent方法。问题是应用程序因错误“EXC_BAD_ACCESS”而崩溃,并且它发生在i=3 上,因为(当我使用调试器时)[card[i] cardCV]不是 CFString。

我尝试用不同的字符串来填充甲板,有时程序在显示的第一圈失败[cards[i] cardCV]position我真的不明白会发生什么,但我猜它与指针和内存分配规则有某种联系,因为简单类型的数据(例如)没有问题,并且showList如果从fill方法调用,方法可以正常工作。请帮我一把!我要疯了!该程序是如此简单,以至于我真的很担心将来编码中的问题...

4

1 回答 1

0

问题是

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

This means that when the corresponding LXPPlayingCard is released, the string stored in cardCV is released, too.

于 2011-04-19T09:28:15.137 回答