2010-07-26 11 views
19

Estoy tratando de pasar un NSString por referencia, pero no funciona.Argumentos por referencia en Objective-C

Ésta es la función:

+(void)fileName:(NSString *) file 
{ 
    file = @"folder_b"; 
} 

y esta es la llamada:

NSString *file; 

[function fileName:file]; 

nslog(@"%@",file); // and there is nothing in the string.... 

¿Qué debo hacer para pasar mi cadena por referencia?

Respuesta

30

Creo que usted está buscando:

+ (void)fileName:(NSString **)file 
{ 
    *file = @"folder_b"; 
} 

Lo que realmente está hecho aquí es que estamos trabajando con un puntero a un puntero a un objeto. Consulte las guías C (yup, simplemente C) para "desreferencia del puntero" para obtener más información.

(... Sin embargo, como se ha señalado en repetidas ocasiones, en este ejemplo particular, no hay razón para pasar por referencia en absoluto: simplemente devolver un valor.)

+5

+1 La llamada al método tendrá que cambiarse a [function fileName: & file] –

+2

@bbum: El parámetro * podría * ser un parámetro in/out, pero incluso entonces. . . – dreamlax

-2

Sospecho que esto se debe a que NSString es inmutable. ¿Has probado NSMutableString?

+0

El uso de una cadena mutable no puede 'configurar' la variable a un nuevo objeto, por lo que no funcionará estrictamente en el ejemplo dado. Pero dependiendo de las circunstancias, es la mejor manera de ir (+1) (en lugar de ptr de objeto doble) – Akusete

+0

Una opción sería pasar un 'NSMutableString' y luego usar' setString: ', pero eso no sería así" por referencia". – andyvn22

+0

@andyvn: Tiene razón, mi punto fue que (como suele ser el caso) la respuesta técnicamente escrita a la pregunta, y la mejor solución al problema no es lo mismo. – Akusete

63

Si desea devolver un valor, a continuación, devuelve un valor. Pase por referencia en Cocoa/iOS se limita en gran medida a NSError**.

Dado:

+(void)fileName:(NSString *) file 

Después, realice:

+(NSString *) fileName; 

y hacerse con él.

Si necesita devolver más de un valor a la vez, eso exige una estructura o, más a menudo, una clase.

En Objective-C, pase por referencia huele como si lo estuviera haciendo mal.


Pasar por referencia en Objective-C está reservado en gran parte para devolver NSError* información sobre un fallo recuperable, donde el valor de retorno del método en sí mismo indica si la tarea solicitada correctamente o no (se puede pasar NULL como el argumento NSError** para permitir que el método optimice la creación de dichos metadatos de error).

Pasar por referencias también se usa para recuperar el estado interior de los objetos donde el valor de retorno es efectivamente un multivalor. Es decir. métodos de AppKit como el siguiente. En estos casos, los argumentos de paso por referencia son normalmente opcionales o actúan como valores de retorno secundarios.

Se utilizan con bastante frecuencia en la API. Ciertamente, se utiliza para pasar por referencia, pero, como se dijo anteriormente, hacerlo debería ser bastante raro y aún más raro en el código de la aplicación. En muchos casos, y en algunos de los casos a continuación, potencialmente, un mejor patrón sería crear una clase que pueda encapsular el estado y luego devolver una instancia de dicha clase en lugar de pasar por referencia.

NSWorkspace.h:- (BOOL)getInfoForFile:(NSString *)fullPath application:(NSString **)appName type:(NSString **)type; 
NSTextView.h:- (void)smartInsertForString:(NSString *)pasteString replacingRange:(NSRange)charRangeToReplace beforeString:(NSString **)beforeString afterString:(NSString **)afterString; 
NSAttributedString.h:- (BOOL)readFromURL:(NSURL *)url options:(NSDictionary *)options documentAttributes:(NSDictionary **)dict; 
NSNib.h:- (BOOL)instantiateWithOwner:(id)owner topLevelObjects:(NSArray **)topLevelObjects NS_AVAILABLE_MAC(10_8); 
NSSpellChecker.h:- (NSRange)checkGrammarOfString:(NSString *)stringToCheck startingAt:(NSInteger)startingOffset language:(NSString *)language wrap:(BOOL)wrapFlag inSpellDocumentWithTag:(NSInteger)tag details:(NSArray **)details NS_AVAILABLE_MAC(10_5); 
+2

"En Objective-C, pasar por referencia huele como si lo estuvieras haciendo mal". ¿Podrías explicar eso? ¿Cuál es el lado negativo de hacerlo? – Philip007

+2

@bbum - ¿Y si necesito 2 params de vuelta? No estoy de acuerdo contigo. – Gal

+2

@gal ¿leyó la respuesta real? Si necesita dos parámetros, use una estructura o una clase. Muy rara vez se pasa por ref el patrón correcto para usar. – bbum

3

pasar un puntero a su objeto es la manera de pasar por referencia Objective C (y C).

Estoy de acuerdo con 'bbum' que una necesidad percibida de pasar por referencia es una señal para pensar en lo que está haciendo; sin embargo, de ningún modo es el caso que no haya razones legítimas para pasar por referencia.

No debe crear clases de todas maneras cada vez que tenga una función o método que necesite devolver más de un valor. Considere por qué está devolviendo más de un valor y si tiene sentido crear una clase para eso, hágalo. De lo contrario, solo pasa los punteros.

-Sólo mis 2 centavos

3

probar este

+(void)filename:(NSString **)file { 
    *[email protected]"folder_b"; 
} 

y enviar el archivo como &file como:

NSString *file; 
[function fileName:&file]; 
nslog(@"%@",file); 

esperanza de que esto va a funcionar.

Cuestiones relacionadas