如何在数组对象中使用objectAtIndex

时间:2012-09-01 15:58:34

标签: objective-c cocoa nsmutablearray

我正在尝试使用Objective C和Cocoa,所以我可能在这里使用了错误的术语。

我为我的主AppDelegate.h&读取的一副卡片制作了一个Objective C类。 AppDelegate.m,有两种方法,deckOfCards& pickACard。 deckOfCards只是一个NSMutableArray,每个卡片类型以字符串形式写出,然后在pickACard中我创建一个这样的新数组:

-(void)pickACard
{
    DeckOfCards *newDeck = [[DeckOfCards alloc] init];
    int r = arc4random() % 52;
    NSLog (@"The card you picked is: %@, and there are %i cards left", [newDeck     objectAtIndex:r], [newDeck count]);
    [newDeck removeObjectAtIndex:r];
}

然而XCode说我不能使用objectAtIndex& removeObjectAtIndex在这个新数组上,所以我不能随机选择一张卡,然后通过删除该部分数组“将其从包中删除”。

当它全部在deckOfCards中时,这确实有效,但是当它被AppDelegate.m调用时,它会创建一个新阵列,所以我会得到不同的卡,但永远不会从包中删除多个。

我猜我没有正确创建这个新数组。

为了更清楚,DeckOfCards.h是这样的:

#import <Foundation/Foundation.h>

@interface DeckOfCards : NSObject
{
@private
}
-(void) deckOfCards;
-(void) pickACard;

@end

DeckOfCards.m是这样的:

@implementation DeckOfCards
-(void)deckOfCards
{
NSMutableArray *deckOfCards = [NSMutableArray arrayWithObjects:
    @"One of Hearts", @"Two of Hearts"..., nil];
}
-(void)pickACard
{
    DeckOfCards *newDeck = [[DeckOfCards alloc] init];
    int r = arc4random() % 52;
    NSLog (@"The card you picked is: %@, and there are %i cards left",[newDeck     objectAtIndex:r], [newDeck count]);
    [newDeck removeObjectAtIndex:r];
}

@end

4 个答案:

答案 0 :(得分:4)

我在这里看到一些问题。编译器问题的直接原因是您尝试在NSMutableArray的实例上调用DeckOfCards方法。相反,您希望toc在方法NSMutableArray返回的-[DeckOfCards deckOfCards]上调用这些方法。它看起来像这样:

DeckOfCards *newDeck = [[DeckOfCards alloc] init];
NSMutableArray *deckArray = [newDeck deckOfCards];
int r = arc4random() % 52;
NSLog (@"The card you picked is: %@, and there are %i cards left",[deckArray objectAtIndex:r], [deckArray count]);
[deckArray removeObjectAtIndex:r];

但是这引出了我们的下一个问题 - -deckOfCards实际上并没有返回任何内容 - 它的返回类型定义为void。因此,为了将NSMutableArray实例恢复到程序的其余部分,您将需要return它,并使用适当的返回类型定义方法。如果我们只是为了解决这个问题,我们会改变您的-deckOfCards方法:

-(NSMutableArray *)deckOfCards
{
    NSMutableArray *deckOfCards = [NSMutableArray arrayWithObjects:
        @"One of Hearts", @"Two of Hearts"..., nil];

    return deckOfCards;
}

好的,所以应该立即编译。但这里有一些严重的错误。我担心我现在没有太多时间来回答这个问题,但我建议你阅读一些介绍性的Objective-C,重点关注对象和类之间的区别,以及对象和内存管理的生命周期。基本上,没有任何东西永远存在。无论您在-pickACard的任何实例上调用DeckOfCards多少次,您都将获得一个实例化的单独实例,然后将实例化一个全新的NSMutableArray。但是这些对象都没有被保留(假设您正在使用自动引用计数),它们都会立即消失。因此,您每次都会从-pickACard获得一张全新的52张牌组。

希望这会有所帮助。通过阅读和学习Objective-C和面向对象编程的基础知识,您将能够按照自己的方式使用该程序。如果您有任何问题,请告诉我,我会尽力回答。

答案 1 :(得分:3)

  

然而XCode说我不能使用objectAtIndex&amp; removeObjectAtIndex对这个新数组,...

不,这是说你不是想在阵列上使用它。

您尝试使用它的是DeckOfCards:

DeckOfCards *newDeck = [[DeckOfCards alloc] init];
int r = arc4random() % 52;
NSLog (@"The card you picked is: %@, and there are %i cards left", [newDeck     objectAtIndex:r], [newDeck count]);
[newDeck removeObjectAtIndex:r];

newDeck是您在第一行创建的DeckOfCards

DeckOfCards不是数组:

@interface DeckOfCards : NSObject

DeckOfCards只是一个对象。不只是任何物体;您已添加内容(deckOfCardspickACard方法)。但它不是一个数组,所以不响应objectAtIndex:并且不是一个可变数组,所以也不响应removeObjectAtIndex:

那么你有一个数组吗?好吧,你在deckOfCards方法中创建一个:

-(void)deckOfCards
{
NSMutableArray *deckOfCards = [NSMutableArray arrayWithObjects:
    @"One of Hearts", @"Two of Hearts"..., nil];
}

但该阵列会发生什么?

无。你创建它,然后你把它放在地板上。你不是把它归还给你的任何人;实际上,你不能,因为这个方法返回void

暂时不考虑架构问题,假设您对编程很陌生,可以原谅,您需要做几件事:

  1. 更改deckOfCards方法的声明,以声明它将返回NSMutableArray *,而不是void
  2. 在创建返回数组的数组后立即添加一行:

    return deckOfCards;
    

    (请注意deckOfCards这里是指数组*。)

  3. 更改pickACard以致电deckOfCards。这将创建数组和(一旦你做出更改#2)返回给你。在pickACard中声明一个变量,类似于您在deckOfCards中声明的变量,并将结果分配给deckOfCards

  4. 现在您在pickACard中有一个数组,您可以尝试检索其中一个项目,记录并删除它。通过将objectAtIndex:removeObjectAtIndex:消息发送到数组,而不是发送到不是数组的对象来执行此操作。
  5. 在您使用它时,请更正r的类型。 NSArray索引的类型为NSUInteger,而不是int
  6. 现在程序应该编译,运行并且几乎可以正常工作。

    几乎?好吧,你还有一件事要做。

    deckOfCards每次创造一个新的牌组;你从那个牌组中取出一张牌,但随后忘掉了所有关于那张牌组的牌,并且下次将使用另一张新牌组。

    这是您的下一个挑战:更改程序以在初始化中创建一个套牌,并记住并重复使用该套牌进行每次后续抽奖。一定要正确处理甲板耗尽(不再是卡片)的情况,可能是在那一刻创建一个新的甲板。

    (你的第一直觉就是复制和粘贴。只做初稿。然后改变它,以便甲板创建代码只在一个地方,一个方法用于那个目的,你从中调用该方法这两个地方你需要创造一个新的甲板。)

    我会给你一个提示:实例变量。


    *在deckOfCards方法中,您会看到两个名为deckOfCards的内容:该方法以及您在其中声明的数组。两个不同的东西同名。编译器不关心;方法和变量存在于不同的命名空间中,因此在任何给定时刻知道哪个是哪个都没有问题。但是你应该改变其中一个以帮助你理解,更不用说别人对改变什么的建议(“用deckOfCards做这个”,我说 - 但deckOfCards我的意思是?)。

    我建议重命名数组变量。只需将其命名为array即可。 (但只要它是在该方法中声明的局部变量。)

    当您将其设为实例变量时,请将名称更改回更具体的名称。 _deckOfCards是当今常见的命名约定 - 下划线告诉您(再次,编译器不关心)此名称是实例变量的名称。

答案 2 :(得分:2)

正如其他评论者所说,您的应用程序结构存在多个问题。我已经创建了一个示例应用程序,向您展示如何开始解决此问题。首先,在你的DeckOfCards类中,你想要一个指向可变数组的属性来保存你的牌组 - 我称之为甲板。然后,您需要一个init方法,它不仅返回DeckOFCards类的实例,还创建并填充该卡阵列。所以这就是我在DeckOfCards类中的内容。

在.h中,就是这样:

@interface DeckOfCards : NSObject

@property (retain,nonatomic) NSMutableArray *deck;

@end

而且,在.m:

-(id)init {
    if (self = [super init]) {
        NSArray *cardNames = [NSArray arrayWithObjects:@"Two",@"Three",@"Four",@"Five",@"Six",@"Seven",@"Eight",@"Nine",@"Ten",@"Jack",@"Queen",@"King",@"Ace",nil];
        NSArray *suits = [NSArray arrayWithObjects:@" of Hearts",@" of Diamonds",@" of Spades",@" of Clubs",nil];
        self.deck = [NSMutableArray array];
        for (NSString *aCard in cardNames) {
            for (NSString *aSuit in suits) {
                [self.deck addObject:[aCard stringByAppendingString:aSuit]];
            }
        }
    }
    return self;
}

您想要创建此类的实例,并从另一个类中选择卡,而不是从DeckOfCards类本身中选择。在这个例子中,我已经在app delegate中完成了这个(为简单起见 ),但在某些控制器类中执行此操作会更好。所以,我有一个属性,aNewDeck来保持对该实例的引用(编译器不会让你使用以“new”开头的名字,不知道为什么,或者如果这是山狮的新东西)。我在applicationDidFinishLoading方法中创建了这个新实例,然后将IBAction连接到一个选择卡的按钮。请注意,我将随机数生成器更改为不使用52,但是数组的计数 - 如果不这样做,则会选择大于数组的数字,因为它会变小。您应该注意,为了访问数组,我使用aNewDeck.deck,这是访问实例aNewDeck的属性deck的方法。这是.h文件:

@class DeckOfCards;
#import <Cocoa/Cocoa.h>

@interface AppDelegate : NSObject <NSApplicationDelegate>

@property (assign) IBOutlet NSWindow *window;
@property (strong) DeckOfCards *aNewDeck;

-(IBAction)pickACard:(id)sender ;

@end

这是.m:

#import "AppDelegate.h"
#import "DeckOfCards.h"

@implementation AppDelegate

- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
    self.aNewDeck = [[DeckOfCards alloc] init];
}

-(IBAction)pickACard:(id)sender {
    if (self.aNewDeck.deck.count != 0) {
        int r = arc4random() % [self.aNewDeck.deck count];
        NSLog (@"The card you picked is: %@, and there are %li cards left", [self.aNewDeck.deck  objectAtIndex:r], [self.aNewDeck.deck count] - 1 );
        [self.aNewDeck.deck removeObjectAtIndex:r];
    }else{
        NSLog(@"Game Over!");
    }
}

我希望这可以帮助你开始。

答案 3 :(得分:1)

DeckOfCards不是NSMutableArray的子​​类,它也没有实现- objectAtIndex:- removeObjectAtIndex:方法 - 所以你不能使用这些方法。