Métodos privados en Objetive-C

Si programamos habitualmente en Objetive-C seguramente nos habremos encontrado con la necesidad de crear un método que sea solo accesible desde dentro de la clase, vamos, un método privado🙂

Seguramente, en este momento recordemos como se hace en otros lenguajes, pero no podemos recordar como se hacia en este lenguaje. El motivo de esta falta de recuerdo es por que realmente no nos habremos encontrado una sección sobre ello en el libro o web que usamos para aprender este lenguaje.

Si bien existe la habituales directivas de ámbito @private, @public y @protected de compilador, solo tienen aplicación en los atributos de la clase, y no en los métodos. Además al igual que pasa con otros lenguajes estas directivas solo se aplican en el compilador, pero en el caso de Objetive-C, si accedemos a estas variables privadas, solo obtendremos un warning, como el que vemos en la imagen.

Pero entonces ¿como definimos métodos privados?. Antes de ello vamos a repasar que contiene un fichero de implementación.

Los ficheros .m habitualmente contienen la definición de los métodos que se han declarado en el fichero .h. Como seguramente sabremos, dichas definiciones están comprendidas entre las directivas @implementation CLASE y @end. ¿Que pasa si intentamos definir un método fuera de este bloque?. Pues depende😉, si intentamos definir un método de la clase, el compilador no nos dejara, pero si por otro lado tratamos de definir una función de C o C++, el compilador no pondrá ningún problema. De esta manera podemos pensar que la sección entre @implementation y @end es la parte Objetive-C del fichero .m. Fuera de esta sección no podremos acceder a cosas como “self”, aunque si podremos meter sin problemas código en Objetive-C. Por ejemplo, veamos el contenido del siguiente fichero .m.

int sumaC(int a, int b) {
	PruebaPrivado *pp = [[PruebaPrivado alloc] init];
	return [pp suma:a with:b];
}

@implementation PruebaPrivado
-(int) suma: (int) op1 with: (int) op2 {
	return op1 + op2;
}

-(int) suma2: (int) op1 with: (int) op2 {
	return sumaC(op1, op2);
}

@end

En Objetive-C se sigue una filosofía parecida. La primera aproximación de método privado pasa por declarar esa función únicamente en el fichero .m, y no en el .h. De esta manera los clientes de la clase importarán en fichero .h, y no sabrán de la existencia de los métodos privados. Eso si, como hemos visto, si queremos acceder al contenido de la clase, debe estar definida dentro del bloque de implementación. Como podemos ver en el siguiente ejemplo.

@implementation PruebaPrivado

-(int) suma: (int) op1 with: (int) op2 {
	return [self sumaPrivada: op1 with: op2];
}

-(int) sumaPrivada: (int)o1 with: (int) o2 {
	return o1 + o2;
}

@end

Sin embargo, esta forma de hacerlo tiene sus inconvenientes, por un lado, si compilamos el código del ejemplo el compilador nos dará un warning. Este warning viene de que sumaPrivada no esta definido en el momento de compilar el método suma. Por lo que el compilador nos informa de que PruebaPrivado puede no responder al mensaje sumaPrivada. Este warning se solucionaría poniendo la declaración del método antes de su uso, como pasa habitualmente con C.

Pero aún sin el warning, otro principal inconveniente es la legibilidad. Si intercalamos métodos privados con públicos, mas adelante puede ser un follón revisar nuestro propio código, ya que no tendremos agrupadas todas las funciones privadas de nuestra clase.

Aunque las solución anterior presentaba ciertos inconvenientes, sienta las bases de la solución que habitualmente se suele usar. Con la incorporación de las categorías en Objetive-C se abre la posibilidad de modificar una clase “a posteriori” como ya vimos en esta otra entrada.

La solución pasa por crear una categoría en el fichero .m de implementación, que no estará visible por ningún cliente y que agrupara los métodos privados, de esta manera todos los métodos estarán declarados en el mismo lugar, y nos quitaremos tanto el problema del warning del compilador como la desorganización.

Por tanto, el código quedara como:

@interface PruebaPrivado ()

-(int) sumaPrivada:(int)o1 with:(int)o2;

@end


@implementation PruebaPrivado

-(int) suma: (int) op1 with: (int) op2 {
	return [self sumaPrivada: op1 with: op2];
}

-(int) sumaPrivada: (int)o1 with: (int) o2 {
	return o1 + o2;
}

@end

Como vemos, ahora sumaPrivada esta declarada dentro de la categoría, que además como habéis visto, no lleva nombre. Este hecho nos aporta alguna ventaja como es que la definición de los métodos puede ir en la misma sección de implementación que los métodos públicos, en lugar de tener que crear una sección especifica para esta categoría.

2 respuestas a Métodos privados en Objetive-C

  1. LightMan dice:

    Hola Roberto,

    Estaba revisando tu blog, muy bueno por cierto, y al ver el de los métodos privados me he acordado de una opción que vi en un código pero no trata sobre los métodos sino sobre variables.

    Como comentas se puede hacer una categoría para guardar los métodos privados, y también se utiliza para los atributos privados.

    Por ejemplo:
    @interface PruebaPrivado () {
    NSIntenger _sumasRealizadas;
    }

    -(int) sumaPrivada:(int)o1 with:(int)o2;

    @end

    El caso es que he visto que en el implementation también se pueden abrir corchetes y meter variables:

    @implementation PruebaPrivado {
    NSIntenger _sumasRealizadas;
    }

    Mi cuestión es, ¿hay alguna diferencia entre hacerlo por categoría o meterlo en la implementación?

    • robjperez dice:

      Hola!

      Gracias por el comentario!!

      Como bien dices, también puedes utilizar ese mecanismo para declarar variables privadas o incluso propiedades. Realmente no hay diferencias, quizas la claridad a la hora de leer el código.

      Otra alternativa para declarar variables privadas sin tener que hacerlo con una categoria, es usando la directiva @prvate en la declaración de la clase

      @interface PruebaPrivado {
      NSString *_variablePublica;
      @private
      NSString *_variablePrivada;
      }

      Un Saludo.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: