NSObject不保留

时间:2018-02-09 02:53:25

标签: objective-c function class nsobject retain

流程 -

NSObject类用于生成具有某些属性的卡片。这被添加到MutableArray并相应地使用。但是,在确定另一个类中的手部结果的函数之后,MutableArray会丢失它的所有值。

现在我知道MutableArray只是指向对象而不是持有它们,因此它失去了所有它的值我假设这些对象被ARC扫过。

-(void)rankHand {
    NSString *echo = [Hand returnHandRank:_hand withString:false]; // 7 values in _hand
    // 0 values in _hand.
    NSLog(@"%@", echo);

}

在查看问题后,问题出现在returnHandRank: withString:

之后
@interface Cards : NSObject

@property (nonatomic, strong) NSString *face;
@property (nonatomic, strong) NSString *suit;
@property (nonatomic, strong) NSString *symbol;
@property (nonatomic) int prime;
@property (nonatomic) int rankByInt;

+(NSMutableArray*)createDeck:(id)sender {
    [sender removeAllObjects];
    NSArray *faces = [[NSArray alloc] initWithObjects:@"A",@"2",@"3",@"4",@"5",@"6",@"7",@"8",@"9",@"10",@"J",@"Q",@"K", nil];
    NSArray *suits = [[NSArray alloc] initWithObjects:@"h",@"d",@"c",@"s", nil];
    NSArray *primes = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:41],[NSNumber numberWithInt:2],[NSNumber numberWithInt:3],[NSNumber numberWithInt:5],[NSNumber numberWithInt:7],[NSNumber numberWithInt:11],[NSNumber numberWithInt:13],[NSNumber numberWithInt:17],[NSNumber numberWithInt:19],[NSNumber numberWithInt:23],[NSNumber numberWithInt:29],[NSNumber numberWithInt:31],[NSNumber numberWithInt:37], nil];
    for (int i = 0; i < 52; i++) {
        Cards *card = [[Cards alloc]init];
        card.face = [NSString stringWithFormat:@"%@", faces[i % 13]];
        card.suit = [NSString stringWithFormat:@"%@", suits[i / 13]];
        card.rankByInt = i % 13;
        card.symbol = [Cards symbolForSuit:card.suit];
        card.prime = [[primes objectAtIndex:(i % 13)] intValue];

        [sender addObject:card];
    }
    [sender shuffle];

    return sender;
}

创建_deck,然后_hand填充

[_hand addObject:[_deck objectAtIndex:0]];
[_hand addObject:[_deck objectAtIndex:1]];
[_hand addObject:[_deck objectAtIndex:3]];
[_hand addObject:[_deck objectAtIndex:4]];
[_hand addObject:[_deck objectAtIndex:5]];
[_hand addObject:[_deck objectAtIndex:7]];
[_hand addObject:[_deck objectAtIndex:9]];

returnHandRank: withString:Hand类中的一个非常长的函数。所以这就是为什么我假设他们没有被保留。

任何人都可以详细说明吗?我认为从_deck再次添加卡片毫无意义,它会是最好的解决方案吗?

编辑:已添加returnHandRank: withString:

+(NSString *)returnHandRank:(id)cards withString:(BOOL)returnString {
    NSArray *combinations = [self returnCombinations];

    cards = [self organizeCardsRankOrder:cards];

    __block int maxRank = 0;
    __block int maxValue = 0;
    for (int i = 0; i < [combinations count]; i++) {
        NSArray *splitString = [combinations[i] componentsSeparatedByString:@" "]; // splits the combination string.

        NSArray *pointerArray = [[NSArray alloc] initWithObjects:
                                 [NSNumber numberWithInt:[splitString[0] intValue]],
                                 [NSNumber numberWithInt:[splitString[1] intValue]],
                                 [NSNumber numberWithInt:[splitString[2] intValue]],
                                 [NSNumber numberWithInt:[splitString[3] intValue]],
                                 [NSNumber numberWithInt:[splitString[4] intValue]],
                                 nil]; // turns the combinations into int values in an array.

        NSMutableArray *fiveCardHand = [[NSMutableArray alloc] initWithObjects:
                                 [cards objectAtIndex:[[pointerArray objectAtIndex:0] intValue]],
                                 [cards objectAtIndex:[[pointerArray objectAtIndex:1] intValue]],
                                 [cards objectAtIndex:[[pointerArray objectAtIndex:2] intValue]],
                                 [cards objectAtIndex:[[pointerArray objectAtIndex:3] intValue]],
                                 [cards objectAtIndex:[[pointerArray objectAtIndex:4] intValue]],
                                 nil]; // Create the 5 card hand for the combination loop we are in, we'll now check this to see what rank it returns.


        //Check for hand rank.

        fiveCardHand = [self organizeCardsRankOrder:fiveCardHand];

        NSArray *fiveCardHandOrganized = fiveCardHand;

        int strength = [self handRankWithFiveCards:fiveCardHandOrganized];

        if (strength > maxRank) {
            maxRank = strength;
            maxValue = 0;
        }

        int value = [self associateStrengthToHand:fiveCardHandOrganized andHand:strength];

        if (value > maxValue) {
            maxValue = value;
        }
    }

    if (returnString) {
        return [self handForStrengthWithStrength:maxRank];
    } else {
        return [NSString stringWithFormat:@"%i", maxValue];
    }
}

1 个答案:

答案 0 :(得分:1)

最近有一些涉及组合的问题,所以除非你创建帐户,否则我们怀疑有正在进行的家庭作业......没问题,让我们看看我们是否可以指出你正确的方向。但是我们无法回答这个问题,不是因为它可能是家庭作业,而是因为没有足够的信息这样做。

  

现在我知道MutableArray只是指向对象,而不是持有它们,

到目前为止......

  

所以它失去了所有它的价值我假设这些物品被ARC扫过。

但现在完全错了:-(你误解了Objective-C中的自动内存管理是如何工作的。首先忘记&#34;保留&#34;,现代基于ARC的管理是关于所有权 - 存储引用的变量是否对引用引用的对象断言所有权。当它确定所有权时,变量具有属性 strong ,当它存储引用但不断言所有权然后它具有属性 weak (稍后会遇到一些其他所有权属性,暂时可以忽略它们。)默认情况下,对象引用变量具有属性 strong

让我们尝试类比:

  • 考虑一个气球(&#34;对象&#34;),除非被按下,否则它会飘走;和一只手(&#34;变量&#34;),它保存着东西。
  • 许多不同的手可以握住连接到同一气球的琴弦(参考)。
  • 如果手握紧绳子(强壮),气球就不能飘走。
  • 如果绳子只是放在手掌上(弱),那么气球就会漂浮掉,除非至少另一只手紧紧握着另一根绳子连着气球。
  • 只要至少有一只手紧紧握住绳子,气球就不会漂浮。
  • ARC是微风,它吹走了没有紧紧握住的气球。

未注释的变量默认为 strong ,因此当引用存储在其中时,变量会声明所引用对象的所有权,并且ARC不会将其清除。类的实例变量或标准(强)属性都声明所有权。所有标准集合(数组,字典,集合)都声明对集合中存储的引用所引用的对象的所有权。

因此,如果将引用存储在NSMutableArray中,只要引用保留在数组中,引用的对象就不会被ARC清除掉。如果你改变了数组并删除了一个引用,那么它引用的对象将被ARC 回收(返回到可用的内存池)当且仅当没有其他引用存储在强变量中时

只要对它的引用存储在一个强变量中,数组本身就会保持不变。当数组中没有强引用时,数组本身将被ARC回收,在此过程中,将删除存储在数组中的所有引用,如果这些引用是引用对象的最后一个引用,它们也将被回收。

希望有助于理解其工作原理将帮助您找到清空数组的位置,或者丢失对数组本身的所有强引用;例如通过为引用数组的变量分配新的引用(或nil)。

现在让我们看看你的一些代码:

NSArray *suits = [[NSArray alloc] initWithObjects:@"h",@"d",@"c",@"s", nil];

这是旧式语法,您可以使用数组文字NSArray更轻松地创建@[ ... ]

NSArray *suits = @[@"h", @"d", @"c", @"s"];

没有NSMutableArray文字,因此您使用NSArray一个制作可变副本:[@[ ... ] mutableCopy]或较短@[ ... ].mutableCopy(对后者的使用有不同看法)。还有NSNumber个对象的文字,代码:

[NSNumber numberWithInt:41]

可以简单地替换为@41

使用上述文字将使您的代码更短,更容易阅读。

现在你的陈述:

card.face = [NSString stringWithFormat:@"%@", faces[i % 13]];

暗示了对引用和不可变对象如何工作的误解。 NSString对象是 immutable ,一旦创建,其值将永远不会改变。方法stringWithFormat:根据其格式和参数构造NSString,在本例中是单个字符串,因此您只需复制相当于的字符串:

card.face = [faces[i % 13] copy];

但是,不可变对象的副本只是原始对象。您知道faces只包含使用字符串文字创建的不可变字符串,因此上述内容相当于:

card.face = faces[i % 13];

重要提示:您可以通过子类别使用可变的NSMutableString引用作为NSString引用,因此这里放弃copy的最后一步仅有效如果您知道引用是NSString对象而不是NSMutableString对象。

facessuits上使用直接索引后,您切换为长格式:

card.prime = [[primes objectAtIndex:(i % 13)] intValue];

以及其他一些地方。所有这些都可以被[...]取代,例如:

card.prime = [[primes[i % 13] intValue];

虽然您使用除法(i / 13)和余数(i % 13)都是正确的,但您可能需要考虑使用两个嵌套循环来避免它们,例如类似的东西:

for(int suitRank = 0; suitRank < 4; suitRank++)
{  for(int cardRank = 0; cardRank < 13; cardRank++)
   {  // now use suitRank for i / 13 and cardRank for i % 13

以上所有内容都是为了让您的代码更短,更易读,更不容易出错。现在是一个更严重的问题:

+(NSMutableArray*)createDeck:(id)sender {
   [sender removeAllObjects];

从不这样做!虽然id使用它会降低编译器检查代码是否正确的能力,但是当编译器遇到的简单错误运行时,可能会导致代码出错。这里sender显然是对可变数组的引用,声明如下:

+ (NSMutableArray *)createDeck:(NSMutableArray *)sender
{
   [sender removeAllObjects];

稍后(在应用上述文字后)你有:

NSMutableArray *fiveCardHand = @[ cards[[pointerArray[0] intValue]],
                                  ...
                                ].mutableCopy;
//Check for hand rank.

fiveCardHand = [self organizeCardsRankOrder:fiveCardHand];

在这里:

  1. 创建一个可变数组
  2. 将对它的引用分配给fiveCardHand
  3. 使用fiveCardHand
  4. 的结果覆盖organizeCardsRankOrder:中的引用

    所以在这里你似乎没有突变fiveCardHand引用的数组,而是改变了变量来引用不同的数组。您不需要使用可变数组来执行此操作,您正在改变包含引用而不是引用数组的变量。现在&#34;出现&#34;这里使用的是因为你还没有提供organizeCardsRankOrder:的代码,也许这个方法确实改变了传递给它的数组,如果是这样的话,它也不需要也返回它,并且不需要赋值给变量。所以在这里仔细查看你的代码,然后决定是改变数组还是改变变量并相应地改变它。

    最后,您不会在_deck_hand的问题中提供任何声明。通过命名约定,您可能直接访问属性的支持变量(通常最好避免这样做),或访问实例变量,这两个都是未指定的类。因此,我们无法提供任何真正的帮助,只需检查它们是否连接到您正在使用相同实例的实例 - 一个常见的早期错误是设置实例变量一个实例,尝试从另一个实例读取它,然后想知道为什么值不同......

    HTH,快乐的调试!