NSObject 不保留

NSObject not retaining

进程-

NSObject Class 用于生成具有特定属性的卡片。这被添加到 MutableArray 并相应地使用。然而,在另一个 class 中确定手牌结果的函数之后,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:Handclass中的一个很长的函数。所以这就是为什么我假设他们没有被保留。

谁能详细说说?我认为从 _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];
    }
}

最近出现了一些涉及组合的问题,因此除非您正在创建帐户,否则我们怀疑您正在做功课...没问题,让我们看看能否为您指明正确的方向。但是我们不能回答这个问题,不是因为它可能是家庭作业,而是因为没有足够的信息来回答这个问题。

Now I know a MutableArray simply points to the objects as opposed to holding them,

到目前为止正确...

so for it to lose all it's values I'm assuming the objects are being swept up by ARC.

但现在完全错了 :-( 你误解了 Objective-C 中的自动内存管理是如何工作的。首先忘记 "retain",现代 ARC-based 管理是关于 所有权的 - 存储引用的 变量 是否断言对 object 引用的所有权。当它断言所有权时, 变量 具有 strong 属性,当它存储引用但不声明所有权时,它具有 weak 属性(还有一些其他所有权属性稍后你会遇到,暂时可以忽略。Object 参考变量默认具有 strong.

属性

打个比方:

  • 考虑一个气球("object"),除非按住它,否则它会飘走;和一只手 ("variable"),可以拿东西。
  • 许多不同的手可以握住系在同一个气球上的绳子(参考)。
  • 如果手紧紧抓住一根绳子(强),气球就不会飘走。
  • 如果绳子刚好放在手掌上(弱),除非至少有另一只手紧紧抓住另一根绳子,否则气球会飘走。
  • 只要至少一只手紧紧抓住一根绳子,气球就不会飘走。
  • ARC 是 breeze,它会吹走没有紧紧抓住的气球。

未注释的变量默认为 strong,因此当在其中存储引用时,变量断言所引用的 object 的所有权并且不会被清除弧。 class 或标准(强)属性 的实例变量都声明所有权。所有标准 collections(数组、字典、集合)都声明对存储在 collection.

中的引用所引用的 objects 的所有权

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

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

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

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

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

这是旧式语法,您可以使用 数组文字 @[ ... ]:

更轻松地创建 NSArray
NSArray *suits = @[@"h", @"d", @"c", @"s"];

没有 NSMutableArray 字面值,因此您使用 NSArray 字面量来制作可变副本:[@[ ... ] mutableCopy] 或更短的 @[ ... ].mutableCopy (对于使用后者)。 NSNumberobjects还有一个字面量,你的代码:

[NSNumber numberWithInt:41]

可以简单地替换为@41

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

现在你的声明:

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

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

的字符串
card.face = [faces[i % 13] copy];

然而,不可变 object 的副本只是原始 object。你知道 faces 只包含不可变字符串,因为你使用字符串文字创建它,所以上面等同于:

card.face = faces[i % 13];

重要提示: 你可以使用一个可变的,NSMutableString,作为 sub-classing 的一个 NSString 引用,所以这里的最后一步删除 copy 有效 如果您知道引用是 NSString object 而不是 NSMutableString

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

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

以及其他一些地方。都可以用[...]代替,例如:

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

虽然你使用的除法 (i / 13) 和余数 (i % 13) 都是正确的你 mi不想考虑使用两个嵌套循环来避免它们,例如类似于:

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. organizeCardsRankOrder:
  4. 的结果覆盖fiveCardHand中的引用

所以在这里你似乎没有改变了fiveCardHand引用的数组,而是改变了变量来引用一个不同的 大批。你不需要使用可变数组来做到这一点,你正在改变持有引用而不是引用数组的变量。现在这里使用 "appear" 因为你没有提供 organizeCardsRankOrder: 的代码,也许那个方法确实改变了传递给它的数组,如果是这样的话它也不需要 return它并且不需要分配给变量。因此,请在此处仔细查看您的代码,并决定您是要改变数组还是仅改变变量,然后相应地进行更改。

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

HTH,调试愉快!