【问题标题】:Error: "Unrecognized selector" when using addObjects: on an NSMutableArray错误:使用 addObjects 时出现“无法识别的选择器”:在 NSMutableArray 上
【发布时间】:2011-07-01 17:37:36
【问题描述】:

执行时

[self.blockViews addObject:curBlockView];

我收到一个错误

2011-07-01 13:35:26.240 Block Breaker[42061:207] -[__NSArrayI addObject:]:无法识别的选择器发送到实例 0x4e037a0

我对 Objective-C 很陌生。是我的init 方法中的东西吗?

//
//  GameEngine.h
//  Block Breaker
//
//  Created by Chris Muench on 7/1/11.
//  Copyright 2011 N/A. All rights reserved.
//

#import <Foundation/Foundation.h>


@interface GameEngine : NSObject {
    NSMutableArray *blockViews;
    int numBlockRows;
    int score;
}
@property (nonatomic, copy) NSMutableArray *blockViews;
@property int numBlockRows;
@property int score;

- (void) setup;
- (void) setupBlocks;
@end


//
//  GameEngine.m
//  Block Breaker
//
//  Created by Chris Muench on 7/1/11.
//  Copyright 2011 N/A. All rights reserved.
//

#import "GameEngine.h"
#import "Block.h"
#import "BlockView.h"


@implementation GameEngine
@synthesize blockViews;
@synthesize numBlockRows;
@synthesize score;

- (id) init
{
    if ((self = [super init])) 
    {
        self.blockViews = [[NSMutableArray alloc] init];
        self.numBlockRows = 2;
        self.score = 0;
    }
    return self;
}

- (void) setup
{
    [self setupBlocks];
}

- (void) setupBlocks
{
    float blockWidth = 10;
    float blockHeight = 10;
    float rowSpacing = 2;
    float colSpacing = 2;
    float currentX = 0;
    float currentY=10;
    float screenWidth = 200;

    for (int rowCounter=0;rowCounter<self.numBlockRows;rowCounter++)
    {

        while(currentX <=screenWidth)
        {
            Block *curBlock = [[Block alloc] initWithWidth:blockWidth height:blockHeight];
            BlockView *curBlockView = [[BlockView alloc] initWithFrame:CGRectMake(currentX, currentY, curBlock.width, curBlock.height)];
            curBlockView.block = curBlock;

            [self.blockViews addObject:curBlockView];           
            currentX+=blockWidth+colSpacing;
            [curBlock release];
            [curBlockView release];
        }

        currentX=0;
        currentY+=blockHeight+rowSpacing;
    }


}

@end

【问题讨论】:

  • 看来如果我更改@property (nonatomic, copy) NSMutableArray *blockViews, 保留,错误就会消失。但为什么呢?
  • 再想一想,很多情况下不需要设置可变数组。该数组是可变的,这就是为什么您只需要“访问”它的指针来添加新对象。除此之外,您不需要使用init 中的设置器。您可以直接在那里引用 ivars。
  • 你不想做 self.blockviews = [[NSMutableArray alloc] init];无论人们在下面回答的复制/保留问题如何。你最终会泄漏内存。使用 blockViews = [[NSMutableArray alloc] init];或 self.blockViews = [NSMutableArray 数组];
  • @sidyll:实际上,从封装的角度来看,在对象之间传递可变数组时复制它们是很有意义的。否则他们每个人都可以修改数组的同一个实例,这很快就很难跟踪。

标签: objective-c properties nsmutablearray nsarray


【解决方案1】:

当您使用copy 方法复制NSMutableArray 或将属性指定为copy 的合成setter 时,您将获得一个不可变 副本,这意味着您基本上结束了加上一个普通的NSArray。* 有一个方法mutableCopy 可以保留可变性,但我不相信有任何方法可以为属性指定它。

如果您希望数组在设置时被可变复制,则必须编写自己的 setter 方法,并在属性声明中指定该方法。

@property (nonatomic, copy, setter=setBlockViewsByCopying) NSMutableArray * blockViews;

- (void) setBlockViewsByCopying: (NSMutableArray *)newBlockViews {
    NSMutableArray * tmp = [newBlockViews mutableCopy];
    [blockViews release];
    blockViews = tmp;
}

附带说明,正如@InsertWittyName 在评论中提到的那样,初始化blockViews 的代码会造成泄漏,因为您对正在创建的数组有两个所有权声明——一个用于alloc,一个用于对于您使用该属性获得的retaincopy

self.blockViews = [[NSMutableArray alloc] init];
//  ^ One claim                    ^ Two claims
// Only one release later, when the property is set again!
// LEAK!

你应该这样做:

self.blockViews = [NSMutableArray array];
// Creates an object you don't own which you then make one claim
// on using the setter

*虽然它是一个类集群,但你确实得到了一些未指定的具体子类。

【讨论】:

    【解决方案2】:

    如果我没记错的话,副本应该保留。

    无论如何使用复制都不是最优的,每次调用访问器(集合)时,都会得到一个副本,并且正如上面所指出的,它是不可变的。

    添加没问题,但记得在完成后释放数组。

    【讨论】:

      【解决方案3】:

      retain你的数组了吗??

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-04-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多