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