2010-05-23 19 views
21

Soy algo nuevo con el objetivo cy estoy tratando de pasar un argumento por referencia, pero se está comportando como si fuera un valor. ¿Sabes por qué esto no funciona?Pasando argumentos por valor o por referencia en el objetivo C

Ésta es la función:

- (void) checkRedColorText:(UILabel *)labelToChange { 
    NSComparisonResult startLaterThanEnd = [startDate compare:endDate]; 
    if (startLaterThanEnd == NSOrderedDescending){ 
     labelToChange.textColor = [UIColor redColor]; 
    } 
    else{ 
     labelToChange.textColor = [UIColor blackColor]; 
    } 

} 

Y esta es la llamada:

UILabel *startHourLabel; // This is properly initialized in other part of the code 
[self checkRedColorText:startHourLabel]; 

Gracias por su ayuda

+3

¿Qué quiere decir con "comportarse como si fuera un valor"? –

Respuesta

68

Objetivo-C solo ayuda que pasa parámetros por valor. El problema aquí probablemente ya se haya solucionado (dado que esta pregunta tiene más de un año de antigüedad), pero necesito aclarar algunas cosas con respecto a los argumentos y Objective-C.

Objective-C es un estricto superconjunto de C, lo que significa que todo lo que C hace, Obj-C lo hace también.

Al tener un rápido vistazo a Wikipedia, que puede see que Function parameters are always passed by value

Objective-C no es diferente. Lo que sucede aquí es que cada vez que pasamos un objeto a una función (en este caso, un UILabel *), pasamos el valor que contiene en la dirección del puntero.

Hagas lo que hagas, siempre será el valor de lo que está pasando. Si desea pasar el valor de la referencia , deberá pasarle un ** objeto (como se ve a menudo al pasar NSError).

Esto es lo mismo con los escalares, se pasan por valor, por lo tanto puede modificar el valor de la variable que recibió en su método y que no cambiará el valor de la variable original que pasó a la función .

He aquí un ejemplo para facilitar la comprensión:

- (void)parentFunction { 
    int i = 0; 
    [self modifyValueOfPassedArgument:i]; 
    //i == 0 still! 
} 

- (void)modifyValueOfPassedArgument:(NSInteger)j { 
    //j == 0! but j is a copied variable. It is _NOT_ i 
    j = 23; 
    //j now == 23, but this hasn't changed the value of i. 
} 

Si quería ser capaz de modificar i, que tendría que pasar el valor de la referenciade la siguiente manera:

- (void)parentFunction { 
    int i = 0; //Stack allocated. Kept it that way for sake of simplicity 
    [self modifyValueOfPassedReference:&i]; 
    //i == 23! 
} 

- (void)modifyValueOfPassedReference:(NSInteger *)j { 
    //j == 0, and this points to i! We can modify i from here. 
    *j = 23; 
    //j now == 23, and i also == 23! 
} 
+27

Técnicamente, sí, solo pasas las primitivas por valor. Sin embargo, esto es completamente engañoso porque mientras el puntero a un objeto se pasa por valor, ese puntero apunta al mismo objeto. Como NO HAY OTRA MANERA DE PASAR (o tratar con) OBJETOS, * los objetos * siempre se pasan por referencia. La única vez que se comportan como si no lo fueran es si OP dijo labelToChange = nil; o algo así, pero eso es algo que todos aquí saben que no funcionaría y no se discutirán. –

+2

esto es tan engañoso ... Los objetos se pasan por referencia en Objective-C ..para agregar más diversión, el objeto formuló la pregunta y se respondió con una explicación de int que se pasa por valor. Y si no es lo suficientemente divertido, tienes más de 60 votos para "Objective-C solo admite pasar parámetros por valor". – hariszaman

0

En Objective-C, no hay manera de pasar objetos por valor (a menos que lo copie explícitamente, pero esa es otra historia). Examine su código: ¿está seguro de que se llama checkRedColorText? ¿Qué pasa con [startDate compare: endDate], alguna vez es igual a NSOrderedDescending? ¿LabelToChange es nulo?

+0

En el método, NSOrderedDescending a veces es verdadero como esperaba. La etiqueta no es nula. En realidad, si conecté LabelToChange para startHourLabel, funciona ... Me parece que se está comportando como si estuviera pasando la etiqueta como un valor y no como una referencia: S ... No lo entiendo ... Gracias por su ayuda ! – Rafael

+1

¿Qué quiere decir con "etiqueta alámbricaToChange to startHourLabel"? No puede cablear un argumento de método a nada, excepto al pasarlo como un parámetro. – JeremyP

+0

Quiero decir por cableado que no use labelToChange y use la variable startHourLabel directamente (solo para depurar puroposes). El startHourLabel es global y podría alcanzarse en el método. Pero quiero usar el mismo método para otras etiquetas en la vista. Es por eso que agregué el parámetro labelToChange. ¡Gracias! – Rafael

0

Quizás quiso editar código a cabo entre esta línea

UILabel *startHourLabel; 

y esta línea?

[self checkRedColorText:startHourLabel]; 

Si no es así, el problema es que estás volver a declarar la variable de startHourLabel, por lo que está perdiendo cualquier tipo de inicialización que estaba allí previamente. Debería obtener un error de compilación aquí.

+0

Es de suponer que fue para fines ilustrativos, porque si nada más, habría (probablemente) un EXE_BAD_ACCESS si hiciera algo con una variable local no inicializada. –

+0

Hola, gracias. No, startHourLabel no está allí, la inicialización es otra parte del código. Lo declare en la interfaz e hice un constructor para él. No estoy teniendo errores allí ... – Rafael

0

Estas son las posibilidades de por qué esto no funciona:

  1. la etiqueta se pasa en a checkRedColorText no es el que usted piensa que es.
  2. el resultado de la comparación siempre sale de la misma manera.
  3. ... en realidad, no hay 3.

Usted afirma que inicializado startHourLabel en otro lugar, pero, si se trata de una etiqueta de un archivo de punta, que no se debe inicialización de él en absoluto. Debe declararse como IBOutlet y conectarse a la etiqueta en el plumín con el constructor de interfaz.

Si no se trata de una etiqueta en el plumín, es decir, si la está creando mediante programación, debe verificar la dirección de la etiqueta que inicializa y verificar la dirección de la etiqueta pasada a checkRedColorText. O NSLog su dirección en la inicialización y en checkRedColorText o inspeccionarlo con el depurador.

11

Objective-C, como Java, solo tiene un valor por paso. Al igual que Java, siempre se accede a los objetos a través de punteros. Los "objetos" nunca son valores directamente, por lo tanto, nunca asigna ni pasa un objeto. Está pasando un puntero de objeto por valor. Pero ese no parece ser el problema: está intentando modificar el objeto apuntado por el puntero, que está perfectamente permitido y no tiene nada que ver con pasar por valor vs. pasar por referencia. No veo ningún problema con tu código.

Cuestiones relacionadas