【问题标题】:Message sent to deallocated instance on object that should exist消息发送到应该存在的对象上的已释放实例
【发布时间】:2025-12-02 01:15:02
【问题描述】:

[CFString isEqualToString:]: message sent to deallocated instance

这是我遇到的错误。我有一个视图控制器,其属性是 NSMutableArray,它包含一些 Player 对象。

然后我有一个方法可以切换到另一个视图,我可以在其中添加和删除玩家。当我加载下一个视图时,我将指向第一个视图的指针传递给第二个视图。然后我使用[previousView.playerList addObject:p]; 更新了数组,其中 p 是新创建的播放器对象。

但是,当我尝试在第二个视图的表格视图中显示玩家列表时,错误出现了。当我尝试访问 [previousView.playerlist objectAtIndex:[indexPath row]]; 时,我得到了上面的错误。

代码如下:

这是在第一个视图中,它加载第二个并将自身传递给第二个的属性。

- (IBAction) addPlayerButton:(id)sender {
    [self retain];
    PlayerListViewController *playerListViewController = [[PlayerListViewController alloc] init];
    playerListViewController.previousView = self;
    [UIView transitionFromView:self.view toView:playerListViewController.view duration:0.5 options:UIViewAnimationOptionTransitionFlipFromLeft completion:nil];
}

这是我初始化播放器并将其添加到数组的地方。

- (IBAction)addPlayer:(id)sender {
    Player *p = [[[Player alloc] initWithPlayerName:playerNameField.text withOrder:[previousView.playerList count] withDelegate:previousView] retain];
    [previousView.playerList addObject:p];
    [playerNameField resignFirstResponder];
    [playerTableView reloadData];
}

这是我得到错误的地方

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    static NSString *cellIdentifier = @"MyCell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIdentifier];
    if (cell == nil) {
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier] autorelease];
    }
    Player* p = [previousView.playerList objectAtIndex:[indexPath row]];
    [cell.textLabel setText:[p playerName]];
    cell.accessoryType = UITableViewCellAccessoryCheckmark;

    return cell;
}

我在设置单元格文本的那一行出现错误。 [cell.textLabel setText:[p playerName]];

有人知道我在哪里搞砸了吗?如果需要,我会发布更多代码。

我将 Player.m 修剪为只包含 Synthesis 和 Initalization,因为其余的代码很多,与此错误无关,因为它没有被调用。

播放器.h

@protocol playerProtocol <NSObject>

@optional
- (void) playerDied:(id)playerObject;
- (void) playerWasAdded:(id)playerObject;
- (void) playerLifeDidChange:(id)playerObject;
@end

@interface Player : NSObject {
    id <playerProtocol> delegate;
}
@property (nonatomic,retain) NSString *playerName;
@property (nonatomic, readwrite) int playerLife;
@property (nonatomic, readwrite) int playerPoison;
@property (nonatomic, readwrite) int order;
@property (nonatomic, readwrite) Boolean invincible;
@property (nonatomic, assign) id <playerProtocol>delegate;
@property (nonatomic, retain) UIView *viewPane;
@property (nonatomic) Boolean shown;
@property (nonatomic, readwrite) int minusButton;
@property (nonatomic, readwrite) int plusButton;
@property (nonatomic, retain) UIImageView *readout;
@property (nonatomic, retain) NSArray *playerLifeNumerals;


- (id) initWithPlayerName:(NSString *)playersName withOrder:(int)Order withDelegate:(id)d;
- (void) setPlayerLife:(int)pplayerLife;
- (void) setPlayerPoison:(int)pplayerPoison;
- (NSArray *) getLifeNumeralsFromPlayer:(Player *)playerObject;

@end

播放器.m

@implementation Player

@synthesize playerLife, playerName, playerPoison, order, delegate, invincible, viewPane, readout, shown, minusButton, plusButton, playerLifeNumerals;

#pragma mark - Custom Initalizer

- (id) initWithPlayerName:(NSString *)playersName withOrder:(int)Order withDelegate:(id)d {

    [super init];
    delegate = d;
    playerLife = 20;
    playerPoison = 0;
    order = Order;
    playerName = playersName;
    invincible = NO;
    [delegate playerWasAdded:self];
    viewPane = nil;
    readout = nil;
    shown = NO;
    return self;
}

还有数组声明@property (nonatomic, retain) NSMutableArray *playerList;

【问题讨论】:

  • 你应该发布Player的声明和实现。

标签: iphone objective-c cocoa-touch


【解决方案1】:

在:

- (id) initWithPlayerName:(NSString *)playersName withOrder:(int)Order withDelegate:(id)d {

    [super init];
    delegate = d;
    playerLife = 20;
    playerPoison = 0;
    order = Order;
    playerName = playersName;
    invincible = NO;
    [delegate playerWasAdded:self];
    viewPane = nil;
    readout = nil;
    shown = NO;
    return self;
}

您没有保留playerName。请注意,尽管您已将 playerName 属性声明为 retain(应该改为 copy),但您并没有使用 -initWith… 中的属性设置器。相反,您直接访问支持实例变量。由于您直接将playersName 分配给实例变量,因此您需要手动发送-retain(或者更好的是-copy)。

检查您是否在其他声明的属性中需要它。另外,你应该遵循成语:

self = [super init];
if (self) { … }
return self;

在您的初始化程序中。

编辑:你需要仔细检查你的代码的内存管理实践,因为你在不止一个地方泄漏。例如,在:

- (IBAction) addPlayerButton:(id)sender {
    [self retain];
    PlayerListViewController *playerListViewController = [[PlayerListViewController alloc] init];
    playerListViewController.previousView = self;
    [UIView transitionFromView:self.view toView:playerListViewController.view duration:0.5 options:UIViewAnimationOptionTransitionFlipFromLeft completion:nil];
}

[self retain] 的用途是什么,是否有平衡发布?

另一个例子:在:

Player *p = [[[Player alloc] initWithPlayerName:playerNameField.text withOrder:[previousView.playerList count] withDelegate:previousView] retain];
[previousView.playerList addObject:p];

您从+alloc 获得+1 所有权,从-retain 获得另一个+1,并且该数组还拥有p,因此另一个+1。您应该将 -retain 替换为 -autorelease 以平衡您获得该对象所有权的次数。

【讨论】:

  • 是的,在我使用保留和发布此代码之前,我只是想找到错误。我通常需要一段时间才能把它做好。
  • 干得好,你是神!!!我希望我能给你+100。这一直困扰着我整个周末。
  • 如果您不介意,还有一个关于此代码的问题,您是否知道一个很好的教程来解释我应该何时使用复制或保留?我的 iOS 编程书真的只解释了保留。
  • @Kron Stack Overflow 上有几个关于它的问题,其中之一是:NSString property: copy or retain?