Lo primero y más importante que debe hacer es incluir comentarios de uso en su archivo .h que explique que esta es una clase inmutable, junto con el propósito de la clase y la guía de uso general. Con demasiada frecuencia las personas hacen todo lo posible para tratar de "hacer cumplir" con el compilador lo que se puede lograr simplemente informando a la persona que llama.
Por cierto, no debe proporcionar los emisores públicos o propiedades ReadWrite si tiene la intención de la clase que son inmutables (pero por supuesto que debe proporcionar los emisores privados para que pueda utilizar descriptores de acceso dentro de la clase, siempre se debe evitar, incluso internamente , jugando con ivars directamente excepto en algunos lugares). Supongo que puede agregar su anulación accessInstanceVariablesDirectly
si ve esto como un probable error por parte de la persona que llama.
Pero la clave para entender Objective-C es comprender y aceptar el hecho de que quien llama no es el enemigo. El código llamado no necesita estar "protegido" de la persona que llama. La persona que llama debe estar protegida de posibles errores. Todos están del mismo lado aquí; llamante y llamado quieren que el programa funcione.
La persona que llama es cliente y debe tratarse como tal. El cliente no siempre tiene la razón, pero el cliente siempre es el cliente. A veces eso significa proteger al cliente de sí mismo si hay un error fácil que pueda cometer. NSAssert()
es particularmente útil para eso. Y proporcionar a los organismos públicos a una clase inmutable casi engaña a la persona que llama para que cometa un error, por lo que sería malo para todos.
En cualquier caso, no debe hacer que su clase sea demasiado compleja para tratar de forzar la inmutabilidad. La persona que llama casi puede (*) violar la encapsulación al acceder directamente a la estructura (object->ivar
). La persona que llama sería tonto al hacerlo, pero sería aún más tonto tratar de evitarlo. Tenga en cuenta la inmutabilidad, oculte sus incubadores y marque sus propiedades de solo lectura, y en casi todos los casos debería estar bien.
(*) Sí, es posible ocultar aún más sus datos al anidar una estructura/objeto privado como un ivar, pero la persona que llama puede modificar los datos con la aritmética del puntero para que no se "aplique". Siempre pregúntate qué problema realmente estás tratando de resolver.
La misma lógica se aplica a los singletons 'defensivos', supongo? –
Absolutamente. Los singletons forzados (overriding + allocWithZone :) son casi siempre un error y hacen más daño que bien. El único lugar que tendría sentido es si * desea * que la naturaleza singleton sea un detalle de implementación privada. De lo contrario, normalmente debería utilizar el patrón "singleton compartido" donde se permiten múltiples instancias, o bien debería hacer que la creación de una segunda instancia sea un error de programación con NSAssert(). –
+1 para la postura de "todos están en el mismo bando". –