简体   繁体   English

从Objective-C中的方法返回多个值

[英]Returning multiple values from a method in Objective-C

I asked a similar question, but I couldn't get it working exactly. 我问了一个类似的问题,但我无法让它完全正常工作。 I'm building an iPhone app, and there is a method that I want called from different files. 我正在构建一个iPhone应用程序,我想从不同的文件中调用一个方法。 I figured the easiest way would simply be to make a method in another file, and call the method from the other files. 我认为最简单的方法就是在另一个文件中创建一个方法,并从其他文件中调用该方法。

Here are some problems. 这是一些问题。 I need to return multiple values from the method, after passing it multiple values. 我需要在传递多个值后从该方法返回多个值。 For example, I'm passing it: (int, int, int, string, string) . 例如,我传递它: (int, int, int, string, string) And it needs to return all of those values, after they have been changed. 并且它们需要在更改后返回所有这些值。 Someone showed me this code: 有人给我看了这段代码:

- (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];

}

However, this code doesn't work, and I need some more information to really understand it. 但是,此代码不起作用,我需要更多信息才能真正理解它。 Let's assuming I'm passing it these values: 让我们假设我传递了这些值:

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

So I need to get all of these values back from the method. 所以我需要从方法中获取所有这些值。

How do I declare this in the header file? 如何在头文件中声明这个? This should be in an Objective-C file, but could you give me the code for the entire file so I can see where it would go with the @implementation and @end , whatnot. 这应该是一个Objective-C的文件,但你可以给我的代码整个文件,所以我可以看到哪里会与去@implementation@end ,诸如此类的东西。 Also, how would I call this method? 另外,我怎么称呼这种方法?

What about passing in the values as pointers? 如何将值作为指针传递?

For example: 例如:

- (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;
  }
}

Then you can invoke it like: 然后你可以调用它:

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"

Edit: 编辑:

This works equally well with objects. 这同样适用于对象。 You'll often see this used when dealing with NSError objects: 在处理NSError对象时,您经常会看到这种情况:

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

Can be implemented as: 可以实现为:

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

If you have that many different things that need to be returned from a method, either encapsulate it into an NSDictionary as others have suggested or consider just defining a class. 如果您需要从方法返回许多不同的东西,请将其封装到NSDictionary中,就像其他人建议的那样,或者只考虑定义一个类。 You can declare the instance variables and properties to encapsulate the data, as needed. 您可以根据需要声明实例变量和属性以封装数据。

Defining a class to encapsulate such information proves to be quite efficient and maximizes flexibility. 定义用于封装此类信息的类证明非常有效并且最大化灵活性。 If you need to refactor your app such that the collection of data gains new fields, needs to be saved for later, or might need to gain functionality, a class will ease these changes. 如果您需要重构您的应用程序,使得数据集合获得新字段,需要保存以供日后使用,或者可能需要获得功能,那么类将简化这些更改。

You can use a block closure to pass back multiple values from a method like this. 您可以使用块闭包从这样的方法传回多个值。 -rrh -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);
}

Results: Two values returned, int-fruitCount:2, NSString-fruiteString:You have apple on your list this many times:2 结果:返回了两个值,int-fruitCount:2,NSString-fruiteString:你的列表中有多次苹果:2

Since you can only return a single value from any method in C and C-derived languages, you simply need to return a single value that represents all of your other values. 由于您只能从C和C派生语言中的任何方法返回单个值,因此您只需返回表示所有其他值的单个值。 This is what your sample code is doing with an NSDictionary . 这是您的示例代码使用NSDictionary

The sample code is correct, even if it's a bit contrary to common Objective-C style. 示例代码是正确的,即使它与常见的Objective-C样式有点相反。

What you declare in the header file is simply the declaration of the method, that is: 你在头文件中声明的只是方法的声明,即:

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

In the source file, then: 在源文件中,然后:

@implementation MyClass
// code, as given above
@end

If you only need to return primitive values, then returning a struct may be the optimal solution. 如果您只需要返回原始值,那么返回结构可能是最佳解决方案。 You get compile-time error checking (eg as opposed to an NSDictionary where you could attempt to read an invalid key), while not requiring all the code/files involved in creating a class. 您将获得编译时错误检查(例如,与您可能尝试读取无效密钥的NSDictionary相反),同时不需要创建类所涉及的所有代码/文件。

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

Apple uses structs in many of their methods too (eg CGPoint, CGRect). Apple也在其许多方法中使用结构(例如CGPoint,CGRect)。

The reason this won't work with objects is because ARC forbids this . 这不适用于对象的原因是因为ARC禁止这样做

One slight improvement to the last point in some designs is to use a struct holding enum members. 对某些设计中的最后一点稍微改进的是使用包含枚举成员的结构。 This gives you the compile-time checking already mentioned, something that looks like an object in the return value, and the benefit of clear cases if you need to check the values in the return. 这为您提供了已经提到的编译时检查,它看起来像返回值中的对象,如果您需要检查返回值中的值,则可以获得明确的情况。

The struct: 结构:

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

The client code: 客户端代码:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM