Первое, что вы должны сделать, это включить комментарии об использовании в ваш файл .h, которые объясняют, что это неизменяемый класс, а также его назначение и общие рекомендации по использованию. Слишком часто люди идут на все, чтобы попытаться «навязать» компилятору то, чего можно достичь, просто сообщив об этом вызывающему.
Вы, конечно, не должны предоставлять общедоступные установщики или свойства readwrite, если вы хотите, чтобы класс был неизменным (но, конечно, вы должны предоставить частные установщики, чтобы вы могли использовать средства доступа внутри класса; вы всегда должны избегать даже внутри, возиться с иварами напрямую, за исключением нескольких мест). Я полагаю, вы могли бы добавить переопределение accessInstanceVariablesDirectly
, если бы видели в этом вероятную ошибку со стороны вызывающей стороны.
Но ключ к пониманию Objective-C состоит в том, чтобы понять и принять тот факт, что абонент не является врагом. Вызываемый код не должен быть «защищен» от вызывающей стороны. Звонящий должен быть защищен от вероятной ошибки. Здесь все на одной стороне; вызывающий и вызываемый хотят, чтобы программа работала.
Звонящий является клиентом и должен рассматриваться как таковой. Клиент не всегда прав, но клиент всегда клиент. Иногда это означает защиту клиента от самого себя, если есть легкая ошибка, которую он может сделать. NSAssert()
особенно полезно для этого. А предоставление общедоступных сеттеров неизменяемому классу почти обманывает вызывающего и делает ошибку, так что это будет плохо для всех.
В любом случае вы не должны делать свой класс слишком сложным, чтобы попытаться обеспечить неизменность. Вызывающая сторона может почти (*) всегда нарушать инкапсуляцию, напрямую обращаясь к структуре (object->ivar
). Абонент будет глупо сделать это, но вы будете еще глупее, чтобы попытаться предотвратить это. Обратите внимание на неизменность, скрывайте свои установщики и помечайте свои свойства только для чтения, и почти во всех случаях у вас все будет хорошо.
(*) Да, можно еще больше скрыть ваши данные, вложив частную структуру / объект в виде ивара, но тогда вызывающая сторона может все же изменить данные с помощью арифметики с указателями, чтобы она все еще не была «принудительной». Всегда спрашивайте себя, какую проблему вы действительно пытаетесь решить.