1

次のコードで、単純に NSNumbers の静的配列を作成できないのはなぜですか? C の配列と int を使用するだけですが、これらはコピーできず、init() でわかるように、配列を別の配列にコピーする必要があります。私が受け取ったエラーは「初期化要素が定数ではありません」です。とても紛らわしいです。const キーワードがどこにもないことを考えると、それが何を意味するのかさえわかりません。

また、補足として、getNextIngredient メソッドでは、「メソッドのパラメーターとしてオブジェクトを使用できません」および「互換性のない型が返されます」というエラーが表示されますが、その理由はわかりません。

コードは次のとおりです。

// 1 = TOMATO
// 2 = LETTUCE
// 3 = CHEESE
// 4 = HAM

#import "Recipe.h"




@implementation Recipe

// List of hardcoded recipes
static NSArray *basicHam = [[NSArray alloc] initWithObjects:[[NSNumber alloc] numberwithInt:1], [[NSNumber alloc] numberwithInt:2], [[NSNumber alloc] numberWithInt:3], [[NSNumber alloc] numberwithInt:4]];

// Upon creation, check the name parameter that was passed in and set the current recipe to that particular array.
// Then, set nextIngredient to be the first ingredient of that recipe, so that Game can check it.
-(id) initWithName: (NSString*)name {
    self = [super init];

    indexOfNext = 0;

    if (self) {
        if ([name isEqualToString: @"Basic Ham"]) {
            currRecipe = [NSArray arrayWithArray: basicHam]; 
        }                                
    }
}

-(NSNumber) getNextIngredient {
    return [currRecipe  objectAtIndex:indexOfNext];
}
4

4 に答える 4

11

現代でdispatch_once()は、1回限りの初期化を行うために使用します。Xcode には、まさにそれを行うための便利なテンプレートが組み込まれています。


NSArray は静的に割り当てられたオブジェクトではないため、静的変数の初期化子にすることはできません。

次のようにします。

@implementation Recipe

+ (NSArray *) basicHam {
    static NSArray *hams;
    if (!hams) 
        hams = [[NSArray alloc] initWithObjects:[NSNumber numberwithInt:1], [NSNumber numberwithInt:2], [NSNumber numberWithInt:3], [NSNumber numberwithInt:4], nil];
    return hams;
}

ただし、次の点に注意してください。

  • コードを少し変更しました。割り当てない場合はnumberWithInt:NSNumber. それはうまくいきません。

  • nil引数リストの最後にa を追加しました。それが必要です。

それでもなお、ギャップのない順序で自然なカウント数の小さなセットを効果的に含む配列は、明らかに奇数であることに注意する必要があります。それが恒等式である場合はいつでも、x = foo[x]通常、使用されているパターンに明らかに奇妙な点があることを示しています。

于 2010-10-21T07:29:16.063 に答える
1

これを行う古典的な方法は、 +initialize メソッドを使用することです:

static NSArray *basicHam;

@implementation Recipe

+ (void)initialize {
    if (self == [Recipe class]) {
        basicHam = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:1], [NSNumber numberWithInt:2],
                                                    [NSNumber numberWithInt:3], [NSNumber numberWithInt:4, nil]];
    }
}

Obj-C クラスにアタッチする代わりに C でこれが必要な場合に機能する代替手段は、次のようなものです。

static NSArray *basicHam;

static void initBasicHam() __attribute__((constructor)) {
    basicHam = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:1], [NSNumber numberWithInt:2],
                                                [NSNumber numberWithInt:3], [NSNumber numberWithInt:4, nil]];
}

そうは言っても、それははるかに慣用的であるため、bbumの答えを使用することをお勧めします。

于 2010-10-21T21:38:00.387 に答える
0

より完全な例を次に示します (ここで概説したココアのイディオム bbum も使用しています)。他のいくつかのエラーを指摘し、サイドノートに対処します。

/* Recipe.h */

@interface Recipe : NSObject
{
    NSUInteger indexOfNext;
    NSArray * currentRecipe;
}

- (id)initWithName:(NSString *)name;
- (id)initWithBasicHam;

- (NSNumber *)getNextIngredient;

@end

extern NSString * const Recipe_DefaultRecipeName_BasicHam;

/* Recipe.m */

NSString * const Recipe_DefaultRecipeName_BasicHam = @"Basic Ham";

@implementation Recipe

/* @return list of hardcoded recipes */
+ (NSArray *)basicHam
{
    // there may be a better place to declare these
    enum { TOMATO = 1, LETTUCE = 2, CHEESE = 3, HAM = 4 };
    static NSArray * result = 0;
    if (0 == result) {
        result = [[NSArray alloc] initWithObjects:[NSNumber numberWithInt:TOMATO], [NSNumber numberWithInt:LETTUCE], [NSNumber numberWithInt:CHEESE], [NSNumber numberWithInt:HAM], nil];
    }
    return result;
}

/* Upon creation, check the name parameter that was passed in and set the current recipe to that particular array. */
/* Then, set nextIngredient to be the first ingredient of that recipe, so that Game can check it. */
- (id)initWithName:(NSString *)name
{
    self = [super init];
    if (0 != self) {
    /* note: set your ivar here (after checking 0 != self) */
        indexOfNext = 0;

        if ([name isEqualToString:Recipe_DefaultRecipeName_BasicHam]) {
            currentRecipe = [[Recipe basicHam] retain];
        }
    }
    return self;
}

- (id)initWithBasicHam
{
    self = [super init];
    if (0 != self) {
        indexOfNext = 0;
        currentRecipe = [[Recipe basicHam] retain];
    }
    return self;
}

- (NSNumber *)getNextIngredient
{
    assert(currentRecipe);
    return [currentRecipe objectAtIndex:indexOfNext];
}

@end

文字列リテラルの代わりに、文字列キーを作成し、- (id)initWithBasicHam(示されているように) などの便利なコンストラクターを使用するのが最善の場合があります。

[[Recipe basicHam] copy]また、通常は --ではなく呼び出しますRecipe basicHam] retain]が、この特定の例では必要ありません。

于 2010-10-21T21:48:28.340 に答える