web-dev-qa-db-ja.com

Objective-Cのメソッドから複数の値を返す

同様の質問をしましたが、正確に機能させることができませんでした。私はiPhoneアプリを構築していて、別のファイルから呼び出したいメソッドがあります。最も簡単な方法は、メソッドを別のファイルに作成し、そのメソッドを他のファイルから呼び出すことだと考えました。

ここにいくつかの問題があります。複数の値を渡した後、メソッドから複数の値を返す必要があります。たとえば、私はそれを渡しています:(int, int, int, string, string)。そして、それらが変更された後、それらのすべての値を返す必要があります。誰かが私にこのコードを見せました:

- (NSDictionary *)EndOfTurn:(int)varTurns withFatness:(int)varFatness
{
    varTurns--;

    if (varTurns <= 0) {
        varFatness = varFatness - 5;
    }
    else {
        varFatness += 2;
    }

    return [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:varFatness], @"FATNESS", [NSNumber numberWithInt:varTurns], @"TURNS", nil];

}

ただし、このコードは機能せず、実際に理解するにはさらに情報が必要です。私がそれにこれらの値を渡していると仮定しましょう:

int varMoney;
int varNumSheep;
int varNumShepherds;
NSString *test1;
NSString *test2;

したがって、これらの値をすべてメソッドから取得する必要があります。

これをヘッダーファイルでどのように宣言しますか?これはObjective-Cファイルにあるはずですが、ファイル全体のコードを教えていただければ、@implementationおよび@end、なんでもない。また、このメソッドをどのように呼び出しますか?

24
Ethan Mick

CおよびC派生言語では、どのメソッドからも1つの値しか返せないため、他のすべての値を表す1つの値を返すだけで済みます。これは、サンプルコードがNSDictionaryで実行していることです。

サンプルコードは、一般的なObjective-Cスタイルに少し反しているとしても、正しいです。

ヘッダーファイルで宣言するのは、メソッドの宣言だけです。

@interface MyClass : NSObject
- (NSDictionary *)EndOfTurn:(int)varTurns withFatness:(int)varFatness;
@end

ソースファイルでは、次のようになります。

@implementation MyClass
// code, as given above
@end
9
Jim Puls

ポインタとして値を渡すのはどうですか?

例えば:

- (void) getValuesForInt:(int *)int1 anotherInt:(int *)int2 aBool:(BOOL *)bool1 anotherBool:(BOOL *)bool2 {
  if (*int1 == 42 && *int2 == 0) {
    *int1 = 0;
    *int2 = 42;
  }
  if (*bool1 == NO) {
    *bool2 = YES;
  }
}

その後、次のように呼び出すことができます。

int int1 = 42;
int int2 = 0;
BOOL bool1 = NO;
BOOL bool2 = NO;
[self getValuesForInt:&int1 anotherInt:&int2 aBool:&bool1 anotherBool:&bool2];
NSLog(@"int1: %d int2: %d bool1: %d bool2: %d", int1, int2, bool1, bool2);
//prints "int1: 0 int2: 42 bool1: 0 bool2: 1"

編集:

これはオブジェクトでも同様に機能します。 NSErrorオブジェクトを処理するときにこれが使用されることがよくあります。

NSError *error = nil;
[anObject doSomething:foo error:&error];

次のように実装できます。

- (void) doSomething:(id)terrible error:(NSError **)error {
  if ([terrible isEqual:reallyBad]) {
    if (error != nil) { *error = [NSError errorWithDomain:@"domain" code:42 userInfo:nil]; }
  }
}
64
Dave DeLong

メソッドから返す必要のあるさまざまなものがたくさんある場合は、他の人が提案したようにNSDictionaryにカプセル化するか、クラスの定義だけを検討してください。必要に応じて、インスタンス変数とプロパティを宣言して、データをカプセル化できます。

そのような情報をカプセル化するクラスを定義すると、非常に効率的で柔軟性が最大になります。データのコレクションが新しいフィールドを取得するようにアプリをリファクタリングする必要がある場合、後で使用するために保存する必要がある場合、または機能を取得する必要がある場合は、クラスによってこれらの変更が容易になります。

10
bbum

ブロッククロージャを使用して、このようなメソッドから複数の値を返すことができます。 -rrh

[self heyFunctionGiveMeBackTwoValuesFromThisFruitArray:@[@"Apple", @"orange", @"banana", @"Apple"] findThisFruit:@"Apple" closureFunction:^(int fruitCount, NSString* fruitString)
{
    NSLog(@"Two values returned, int-fruitCount:%d, NSString-fruiteString:%@", fruitCount, fruitString);
}];

- (void)heyFunctionGiveMeBackTwoValuesFromThisFruitArray:(NSArray*)fruitsArray findThisFruit:(NSString*)findThisFruit closureFunction:(void (^)(int fruitCount, NSString *fruitString))passBackResultsUsingThisClosure
{
    NSInteger fruitsFound = 0;
    NSString* fruitsMessage = [NSString stringWithFormat:@"No %@ Found", findThisFruit];
    for (NSString* string in fruitsArray)
    {
        if ([string compare:findThisFruit] == NSOrderedSame)
        {
            fruitsFound++;
        }
    }
    if (fruitsFound > 0)
    {
        fruitsMessage = [NSString stringWithFormat:@"You have %@ on your list this many times:%d", findThisFruit, fruitsFound];
    }
    passBackResultsUsingThisClosure(fruitsFound, fruitsMessage);
}

結果:2つの値が返されます。int-fruitCount:2、NSString-fruiteString:リストにAppleがこれだけある:2

10
Richie Hyatt

プリミティブ値のみを返す必要がある場合は、構造体を返すことが最適な解決策になる場合があります。クラスの作成に関係するすべてのコード/ファイルを必要とせずに、コンパイル時のエラーチェック(たとえば、無効なキーを読み取ろうとするNSDictionaryとは対照的)を取得します。

typedef struct myStruct {
  int varMoney;
  int varNumSheep;
  int varNumShepherds;
} myStruct;

Appleは、多くのメソッドでも構造体を使用しています(CGPoint、CGRectなど)。

これがオブジェクトで機能しない理由は、 ARCがこれを禁止する であるためです。

4
Senseful

一部のデザインの最後のポイントに対するわずかな改善の1つは、列挙型メンバーを保持する構造体を使用することです。これにより、前述のコンパイル時チェック、戻り値のオブジェクトのように見えるもの、および戻り値をチェックする必要がある場合に明確なケースの利点が得られます。

構造体:

typedef struct _SIXRecorderStateChange {
    SIXRecorderState oldState;
    SIXRecorderState newState;
} SIXRecorderStateChange;

クライアントコード:

    SIXRecorderStateChange stateChange = [recorderState stop];
    if (stateChange.newState == SIXRecorderStopped) {
...
...
1
MarkSWeiss