NSMutableArray与具有相同索引的不同对象的奇怪行为

时间:2014-04-01 14:53:30

标签: ios objective-c

我遇到了一个奇怪的问题,我无法找到我编写的测试代码的错误。我正在编写一段代码来生成AttributedString并将其放在NSMutableArray中,但是当我使用For循环显示来自NSMutableArray的添加对象时,输出显示相同的对象具有相同的索引3次,我正在尝试调试它现在已经2天了,无法找到错误,希望我能在这里得到一些帮助/建议。

实例化NSMutableArray并将AttributedString添加到数组的代码

-(instancetype)init
{
    self = [super init];

    if (self) {
        for (NSMutableAttributedString *attrString in [SetPlayingCard symbolArray]) {
            for (NSString *attrColor in [SetPlayingCard colorsArray]) {
                if ([attrColor isEqualToString:@"redColor"]) {
                    [attrString setAttributes:@{NSStrokeWidthAttributeName : @3,
                                            NSStrokeColorAttributeName : [UIColor redColor]}
                                    range:NSMakeRange(0, [attrString length])];
                    NSLog(@"%@ %@",attrColor, attrString);
                } else if ([attrColor isEqualToString:@"blueColor"]){
                    [attrString setAttributes:@{NSStrokeWidthAttributeName : @3,
                                            NSStrokeColorAttributeName : [UIColor blueColor]}
                                    range:NSMakeRange(0, [attrString length])];
                    NSLog(@"%@ %@",attrColor, attrString);
                } else if ([attrColor isEqualToString:@"purpleColor"]){
                    [attrString setAttributes:@{NSStrokeWidthAttributeName : @3,
                                            NSStrokeColorAttributeName : [UIColor purpleColor]}
                                    range:NSMakeRange(0, [attrString length])];
                    NSLog(@"%@ %@",attrColor, attrString);
                }
                [self addCard:attrString];
            }
        }
    }
    return self;
}

正在调用的Class方法

+ (NSArray *)colorsArray
{
    return @[@"redColor",@"blueColor",@"purpleColor"];
}

+ (NSArray *)symbolArray
{
    NSMutableAttributedString *triangle = [[NSMutableAttributedString alloc] initWithString:@"Triangle"];
    NSMutableAttributedString *square = [[NSMutableAttributedString alloc] initWithString:@"Square"];
    NSMutableAttributedString *round = [[NSMutableAttributedString alloc] initWithString:@"Round"];

    return @[triangle,square,round];
}

添加和显示输出的方法

- (void)addCard:(NSAttributedString *)card
{
    NSLog(@"String to be added to array: %@", card);
    [self.cards addObject:card];
    NSLog(@"Index is %d for %@", [self.cards indexOfObject:card], card);
}


- (NSAttributedString *)printCard
{
    NSAttributedString *card;

    if ([self.cards count]) {
        for (card in self.cards) {
            NSLog(@"Count: %d, Array index: %d, Card from the deck is: %@, ", [self.cards count], [self.cards indexOfObject:card], card);
        }
    } 
    return card;
}

我在 addCard 方法中从NSLog获得的输出如下所示。

2014-04-01 22:40:56.184 UnitTest[1008:60b] Count: 9, Array index: 0, Card from the deck is: Triangle{
    NSStrokeColor = "UIDeviceRGBColorSpace 0.5 0 0.5 1";
    NSStrokeWidth = 3;
}, 
2014-04-01 22:40:56.185 UnitTest[1008:60b] Count: 9, Array index: 0, Card from the deck is: Triangle{
    NSStrokeColor = "UIDeviceRGBColorSpace 0.5 0 0.5 1";
    NSStrokeWidth = 3;
}, 
2014-04-01 22:40:56.186 UnitTest[1008:60b] Count: 9, Array index: 0, Card from the deck is: Triangle{
    NSStrokeColor = "UIDeviceRGBColorSpace 0.5 0 0.5 1";
    NSStrokeWidth = 3;
}, 
2014-04-01 22:40:56.187 UnitTest[1008:60b] Count: 9, Array index: 3, Card from the deck is: Square{
    NSStrokeColor = "UIDeviceRGBColorSpace 0.5 0 0.5 1";
    NSStrokeWidth = 3;
}, 
2014-04-01 22:40:56.188 UnitTest[1008:60b] Count: 9, Array index: 3, Card from the deck is: Square{
    NSStrokeColor = "UIDeviceRGBColorSpace 0.5 0 0.5 1";
    NSStrokeWidth = 3;
}, 
2014-04-01 22:40:56.189 UnitTest[1008:60b] Count: 9, Array index: 3, Card from the deck is: Square{
    NSStrokeColor = "UIDeviceRGBColorSpace 0.5 0 0.5 1";
    NSStrokeWidth = 3;
}, 
2014-04-01 22:40:56.190 UnitTest[1008:60b] Count: 9, Array index: 6, Card from the deck is: Round{
    NSStrokeColor = "UIDeviceRGBColorSpace 0.5 0 0.5 1";
    NSStrokeWidth = 3;
}, 
2014-04-01 22:40:56.191 UnitTest[1008:60b] Count: 9, Array index: 6, Card from the deck is: Round{
    NSStrokeColor = "UIDeviceRGBColorSpace 0.5 0 0.5 1";
    NSStrokeWidth = 3;
}, 
2014-04-01 22:40:56.192 UnitTest[1008:60b] Count: 9, Array index: 6, Card from the deck is: Round{
    NSStrokeColor = "UIDeviceRGBColorSpace 0.5 0 0.5 1";
    NSStrokeWidth = 3;
},

3 个答案:

答案 0 :(得分:2)

您的printCard方法错误,请将其更改为:

- (NSAttributedString *)printCard
{
    if ([self.cards count] > 0) {
        for (NSAttributedString *card in self.cards) {
            NSLog(@"Count: %d, Card from the deck is: %@, ", [self.cards count], card);
        }
    } 
    return card;
}

如果您想索引,可以使用:

for (int i = 0; i < self.cards.count; i++) {
    NSAttributedString *card = self.cards[i];
    NSLog(@"Count: %d, Array index: %d, Card from the deck is: %@, ", [self.cards count], i, card);
}

您应该查看循环的工作原理。

答案 1 :(得分:2)

init方法中,外部for循环遍历3个字符串中的每一个,而内部for循环遍历3种颜色中的每一种,因此总共9个致电addCard:。因此,数组中每个字符串的三个副本,但每个字符串都有不同的颜色。

日志为每个对象提供相同索引的原因是indexOfObject:使用[NSObject isEqual:]来确定相等性。显然,NSMutableString的{​​{1}}实现仅比较字符串内容,而不是颜色,因此就数组而言,字符串的每个副本都是“相同的”。

如果你使用isEqual:,你会发现每个对象确实有不同的索引。

enumerateObjectsUsingBlock:

答案 2 :(得分:0)

如果我们检查完成设置的代码,你有(总结):

foreach symbol:
    foreach color:
        symbol.color = color
        [array addObject:symbol];

这实际上是为每个符号创建一个NSMutableString,然后更改其颜色并添加到数组3次。由于您没有创建字符串的副本,而只是更改单个字符串的属性,因此您在数组中拥有相同的对象3次。

现在,当你使用indexOfObject:来查看该对象时,你添加了3次,它只找到第一个实例。

修复方法是创建要添加的字符串的副本,而不是添加原始字符串:

[self addCard:[attrString copy]];

更好的解决方案可能是返回一个字符串数组:

return @[ @"triangle", @"square", @"round"];

并使用不同的构造函数创建属性字符串:

attrString = [[NSAttributedString alloc] initWithString:shape attributes:color];