【问题标题】:A variable not a CFString变量不是 CFString
【发布时间】:2011-04-19 09:10:00
【问题描述】:

我在 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方法从@调用,它可以正常工作987654331@ 方法。 请帮我一把!我要疯了!程序太简单了,我真的很担心以后编码的问题……

【问题讨论】:

  • 我强烈建议使用 NSMutableArray 类,cards[j] 看起来 c-ish。

标签: objective-c cfstring


【解决方案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中的字符串也被释放。

【讨论】:

  • 巴伐利亚,非常感谢!现在一切正常。顺便说一句,如果我使用简单的 'NSString*' 变量,如何成为字符串形式 [cardlist substringWithRange:NSMakeRange(i,2)]] 的所有者?使用retain?我的意思是:NSString * temp; ... temp=[cardlist substringWithRange:NSMakeRange(i,2)]; [临时保留];我对吗?我应该读什么才能知道你知道的所有这些东西? :-)
  • @yyk 如果它只是一个局部/自动变量,即仅用于特定方法的变量,那么您通常不需要拥有它。这些变量将在整个方法中有效。但是,是的,如果您需要拥有该字符串的所有权,请使用-copy-retain。您应该阅读Memory Management Programming Guide 以了解有关内存管理的更详细讨论。
猜你喜欢
  • 2011-08-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多