2009-11-07 10 views
21

Hice una pregunta similar, pero no pude hacerlo funcionar exactamente. Estoy construyendo una aplicación para iPhone, y hay un método que quiero invocar desde diferentes archivos. Pensé que la manera más sencilla sería simplemente hacer un método en otro archivo y llamar al método desde los otros archivos.Devolviendo múltiples valores desde un método en Objective-C

Aquí hay algunos problemas. Necesito devolver varios valores del método, después de pasarle múltiples valores. Por ejemplo, lo estoy pasando: (int, int, int, string, string). Y necesita devolver todos esos valores, después de que hayan sido cambiados. Alguien me mostró este código:

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

} 

Sin embargo, este código no funciona, y necesito más información para comprender realmente ella. Vamos a asumir que estoy pasándolo a estos valores:

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

por eso es necesario para conseguir todos estos valores de nuevo a partir del método.

¿Cómo declaro esto en el archivo de encabezado? Esto debería estar en un archivo Objective-C, pero podría darme el código para todo el archivo para que pueda ver dónde iría con el @implementation y @end, whatnot. Además, ¿cómo llamaría a este método?

+12

quisiera señalar que 'withFatness' es una pieza increíble de una función. – Malaxeur

+0

también deberá conservar el resultado de esta función. Como el diccionario que está devolviendo proviene de un método práctico, se libera automáticamente y desaparecerá en breve si no se conserva. es decir, cuando lo llame, haría algo como esto: NSDictionary * myDic = [auto EndOfTurn: turnswithFatness: fatness]; [myDic retain]; –

+1

y luego [lanzamiento de myDic]; cuando estás bien y terminado con eso. –

Respuesta

9

Dado que sólo puede devolver un solo valor de cualquier método en lenguajes C y C-derivados , solo necesita devolver un valor único que represente todos sus otros valores. Esto es lo que su código de muestra está haciendo con un NSDictionary.

El código de muestra es correcto, incluso si es un poco contrario al estilo común de Objective-C.

Lo que se declara en el archivo de cabecera es simplemente la declaración del método, es decir:

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

En el archivo de origen, entonces:

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

Kk, lo intentaré. –

+0

Bien, ¿cuál es la sintaxis para llamar a esta función?Ya importé el archivo de encabezado, pero cuando intento llamar a la función dice "Esperado: antes: token." Esta es la llamada: (NSDictionary *) EndOfTurn: (int) varTurns conFatness: (int) varFatness; \t Le paso las variables "varTurns" y "varFatness" –

+0

Su llamada debe verse como [object EndOfTurn: varTurns withFatness: varFatness] - los bits (int) son solo para la definición, no la llamada. –

59

¿Qué tal pasar los valores como punteros?

Por ejemplo:

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

A continuación, se puede invocar como:

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" 

Editar:

Esto funciona igual de bien con los objetos. A menudo se ve este utiliza cuando se trata de objetos: NSError

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

puede implementarse como:

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

Debe ser * int2 == 0. Además, a su línea NSLog le faltan los parámetros. –

+1

Creo que la otra solución es un poco más efectiva, lo intenté antes, pero no funcionó bien con las cadenas. –

+0

@Chris ¡Ups! eso es lo que obtengo al escribir el código en el navegador. =) –

9

Si usted tiene que muchas cosas diferentes que necesitan ser devueltos por un método, ya sea encapsularlo en un NSDictionary como otros han sugerido o considerar simplemente definir una clase. Puede declarar las variables y propiedades de instancia para encapsular los datos, según sea necesario.

La definición de una clase para encapsular dicha información resulta ser bastante eficiente y maximiza la flexibilidad.Si necesita refactorizar su aplicación de modo que la recopilación de datos obtenga nuevos campos, necesite guardarse para más adelante o podría necesitar obtener funcionalidad, una clase facilitará estos cambios.

+4

+1 para creando una nueva clase. @Wayfarer: abrace el mundo de OOP. – mahboudz

+0

[Apple docs para definir clases.] (https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/ProgrammingWithObjectiveC/DefiningClasses/DefiningClasses. html) –

+0

Esta sería una buena idea si no está preocupado por la carga de trabajo, especialmente para aplicaciones sensibles al marco aciones. Si está desarrollando, digamos una aplicación de realidad virtual, ahorrar un poco sería un beneficio, así que personalmente usaría la respuesta DaveDeLong para esas instancias. – Septronic

4

Si solo tiene que devolver valores primitivos, devolver una estructura puede ser la solución óptima. Obtiene la verificación de errores en tiempo de compilación (por ejemplo, a diferencia de un NSDictionary donde podría intentar leer una clave no válida), sin requerir todos los códigos/archivos involucrados en la creación de una clase.

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

Apple utiliza estructuras en muchos de sus métodos demasiado (por ejemplo CGPoint, CGRect).

La razón por la que esto no funciona con objetos es porque ARC forbids this.

+0

Estoy bastante seguro de que no se admite la incrustación de objetos en struct desde ARC. Probablemente sea mejor usar una clase o diccionario como otros lo han mencionado, incluso si es un poco menos "óptimo". – Taum

+0

@Taum: tienes razón, actualicé la respuesta. – Senseful

1

Una ligera mejoría al último punto en algunos diseños es utilizar una estructura que contenga miembros enum. Esto le proporciona la comprobación en tiempo de compilación ya mencionada, algo que se parece a un objeto en el valor de retorno, y el beneficio de casos claros si necesita verificar los valores en la declaración.

La estructura:

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

El código de cliente:

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

Se puede utilizar un cierre de bloque para pasar de nuevo a varios valores de un método como este. -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); 
} 

Resultados: dos valores devueltos, int-fruitCount: 2, NSString-fruiteString: Usted tiene la manzana en su lista de esto muchas veces: 2

+1

Este es otro gran ejemplo también. – Septronic

-1
In Swift 4: 

func changeV(varMoney:inout Int, varNumSheep: inout Int, varNumShepherds: inout Int, test1: inout String, test2: inout String){ 
    varMoney = 10 
    varNumSheep = 10 
    varNumShepherds = 10 
    test1 = "TEST1" 
    test2 = "TEST2" 
} 
var varMoney = 1 
var varNumSheep = 1 
var varNumShepherds = 1 
var test1 = "test1" 
var test2 = "test2" 

changeV(varMoney: &varMoney, varNumSheep: &varNumSheep, varNumShepherds: &varNumShepherds, test1: &test1, test2: &test2) 

print(varNumSheep) 
Cuestiones relacionadas