Objective C NSString问题

时间:2010-12-20 05:27:08

标签: objective-c nsstring

我的progrram中有以下代码。我试图将每个数字追加到NSString。我在第二次附加字符串后收到错误。错误是 消息发送到解除分配的对象。我知道这是一个内存管理问题。我没有发布小计。有人知道小计被解除分配的原因吗?提前谢谢。

-(IBAction)digitPressed:(UIButton *)sender
{
       NSString *digit = [[sender titleLabel] text];
       subtotal=[subtotal stringByAppendingString:digit];
       NSLog(@"appended string is :%@",subtotal);
}

-(void)ViewDidLoad
{
  subtotal = [[NSString alloc]init];

}

4 个答案:

答案 0 :(得分:5)

您的viewDidLoad需要以小写v开头。您还应该为retain字符串声明subtotal属性,然后使用setter来分配它,这样您的视图控制器就有了自己的指向字符串的指针,并且它不会被意外释放到自动释放池。

在您的标头文件中:

@property (nonatomic, retain) NSString *subtotal;

在您的实施文件中:

-(IBAction)digitPressed:(UIButton *)sender
{
    NSString *digit = [[sender titleLabel] text];
    self.subtotal = [subtotal stringByAppendingString:digit];
    NSLog(@"appended string is :%@",subtotal);
}

-(void)viewDidLoad
{
    self.subtotal = @"";
}

-(void)dealloc
{
    [subtotal release];
    [super dealloc];
}

但是如果你有一个不断被修改的字符串,那么最好将NSMutableString用作Jacob Relkin mentions。它是为可修改而设计的,因此您不会继续创建和销毁不可变的NSString对象。

答案 1 :(得分:4)

两件事:

1 - 您的viewDidLoad方法错误,名称为viewDidLoad,您需要通过调用[super viewDidLoad]调用超类的实现

2 - 这条线错了:

subtotal = [NSString alloc]init];

您错过了领先的[字符:

subtotal = [[NSString alloc]init];

stringByAppendingString:的要点是返回的NSString 已自动释放,因此,您应该retain返回的NSString 将您的实例变量设为NSMutableString并调用appendString:

@interface YourViewController : UIViewController {
   //...
   NSMutableString *subtotal;
}
@property (nonatomic, retain) NSMutableString *subtotal;
@end

@implementation YourViewController 

@synthesize subtotal;

- (void) dealloc {
  [subtotal release];
  //...
  [super dealloc];
}

- (void) viewDidLoad {
   [super viewDidLoad];
   subtotal = [[NSMutableString alloc] init];
}
-(IBAction)digitPressed:(UIButton *)sender {
   NSString *digit = [[sender titleLabel] text];
   [subtotal appendString: digit];         
   NSLog(@"appended string is :%@",subtotal);
}

//...

@end

答案 2 :(得分:2)

你没有release subtotal,但你也永远不会retain。您有几个内存管理问题。首先,您应该在为其分配新值之前释放subtotal的旧值,其次,您应该retain该新值。现在对您所拥有的内容进行微小更改的示例:

-(IBAction)digitPressed:(UIButton *)sender
{
   NSString *digit = [[sender titleLabel] text];
   [subtotal autorelease];
   subtotal = [[subtotal stringByAppendingString:digit] retain];
   NSLog(@"appended string is :%@",subtotal);
}

答案 3 :(得分:0)

你需要阅读Cocoa Memory Management Rules。这一行:

   subtotal = [subtotal stringByAppendingString:digit];

有两件事与内存管理规则有关。

  1. 它会为您提供您不拥有的字符串,因为该方法不以newalloc开头或包含copy。这意味着它将在未来的某个时刻消失,而不会问你。如果您想停止此操作,则可以通过保留所有权来声明所有权。

  2. 它会覆盖对小计的前一个值的引用。如果您拥有该对象,它现在已泄露。你需要先发布它。

  3. 修复代码:

    首先删除

    subtotal = [[NSString alloc]init];
    
    来自viewDidLoad的

    。这是毫无意义的,因为它只是设置一个空字符串的小计。请改用:

    subtotal = @"";
    

    常量字符串文字永远不会消失,虽然从技术上讲你应该保留它,但你可以忘记它没有任何不良后果。

    digitPressed:中,您将需要释放字符串的旧值,因为您将要替换它。有两种方法可以做到这一点。将其保存到临时变量并在追加后释放它,或者在追加之前自动释放它。您还需要保留新值。 e.g。

    NSString* temp = [subtotal];
    subtotal = [subtotal stringByAppendingString: digit];
    [subtotal retain];
    [temp release];
    

    [subtotal autorelease];
    subtotal = [subtotal stringByAppendingString: digit];
    [subtotal retain];
    

    您还需要确保在dealloc

    中发布小计

    说了这么多,使用属性尽可能多地执行内存管理要好得多。因此在@interface中声明属性:

    @property (copy) NSString* subtotal; // string properties should normally be copy
    

    在实现中,您需要综合它。然后viewDidLoad包含

    [self setSubtotal: @""];
    

    并且您的操作包含

    [self setSubtotal: [[self subtotal] stringByAppendingString: digit]];
    

    您仍然需要release中的dealloc