Я только начал программировать Objective-C и, имея опыт работы с Java, удивляюсь, как люди, пишущие программы на Objective-C, имеют дело с приватными методами.
Я понимаю, что может быть несколько соглашений и привычек, и думаю, что этот вопрос объединяет лучшие методы, которые люди используют для работы с частными методами в Objective-C.
Пожалуйста, укажите аргумент в пользу вашего подхода при публикации. Почему это хорошо? Какие у него недостатки (о которых вы знаете) и как с ними справляться?
Что касается моих выводов до сих пор.
Для группировки частных методов можно использовать категории [например, MyClass (Private)], определенные в файле MyClass.m.
Этот подход имеет 2 проблемы:
- Xcode (и компилятор?) Не проверяет, определяете ли вы все методы в частной категории в соответствующем блоке @implementation
- Вы должны поместить @interface, объявляющий вашу личную категорию, в начале файла MyClass.m, в противном случае XCode жалуется сообщением типа «self может не отвечать на сообщение« privateFoo ».
Первая проблема может быть решена с пустой категорией [например, MyClass ()].
Второй очень беспокоит меня. Я хотел бы видеть частные методы, реализованные (и определенные) в конце файла; Я не знаю, возможно ли это.
источник
Ответы:
Как уже говорили другие, в Objective-C нет такого понятия, как закрытый метод. Однако, начиная с Objective-C 2.0 (имеется в виду Mac OS X Leopard, iPhone OS 2.0 и более поздние версии), вы можете создать категорию с пустым именем (то есть
@interface MyClass ()
) под названием Class Extension . Уникальным в расширении класса является то, что реализации методов должны идти так же,@implementation MyClass
как публичные методы. Итак, я структурирую свои классы так:В файле .h:
И в файле .m:
Я думаю, что наибольшим преимуществом этого подхода является то, что он позволяет группировать реализации методов по функциональности, а не по (иногда произвольному) общему / частному различию.
источник
if (bSizeDifference && [self isSizeDifferenceSignificant:fWidthCombined])...
вложил вызов, подобный этому: Тогда fWidthCombined всегда получал как 0.В Objective-C на самом деле не существует «частного метода», если среда выполнения может определить, какая реализация его использует. Но это не значит, что нет методов, которые не являются частью документированного интерфейса. Для этих методов я думаю, что категория хорошо. Вместо того, чтобы помещать
@interface
верхнюю часть файла .m, как ваш пункт 2, я бы поместил его в свой собственный файл .h. Соглашение, которому я следую (и видел в другом месте, я думаю, что это соглашение Apple, поскольку XCode теперь обеспечивает его автоматическую поддержку), заключается в том, чтобы называть такой файл после его класса и категории с +, разделяющим их, так что@interface GLObject (PrivateMethods)
его можно найти вGLObject+PrivateMethods.h
. Причиной предоставления файла заголовка является то, что вы можете импортировать его в свои классы модульного теста :-).Кстати, что касается реализации / определения методов в конце файла .m, вы можете сделать это с помощью категории, реализовав категорию в нижней части файла .m:
или с расширением класса (то, что вы называете «пустой категорией»), просто определите эти методы последними. Методы Objective-C могут быть определены и использованы в любом порядке в реализации, поэтому ничто не мешает вам помещать «приватные» методы в конец файла.
Даже с расширениями классов я часто создаю отдельный header (
GLObject+Extension.h
), чтобы при необходимости использовать эти методы, имитируя видимость «друг» или «защищенный».Так как этот ответ был первоначально написан, компилятор clang начал делать два прохода для методов Objective-C. Это означает, что вы можете не объявлять свои «приватные» методы полностью, и независимо от того, находятся ли они выше или ниже вызывающего сайта, они будут найдены компилятором.
источник
Хотя я не эксперт по Objective-C, я лично определяю метод в реализации моего класса. Конечно, он должен быть определен до (выше) любых методов, вызывающих его, но он определенно требует наименьшего количества работы.
источник
Определение ваших личных методов в
@implementation
блоке идеально подходит для большинства целей. Clang увидит их в пределах@implementation
, независимо от порядка объявления. Нет необходимости объявлять их в продолжении класса (расширение класса) или именованной категории.В некоторых случаях вам нужно будет объявить метод в продолжении класса (например, если используется селектор между продолжением класса и
@implementation
).static
функции очень хороши для особо чувствительных или критичных по скорости частных методов.Соглашение о присвоении имен префиксам может помочь вам избежать случайного переопределения закрытых методов (я считаю имя класса безопасным для префикса).
Именованные категории (например
@interface MONObject (PrivateStuff)
) не особенно хорошая идея из-за возможных конфликтов имен при загрузке. Они действительно полезны только для друзей или защищенных методов (которые очень редко бывают хорошими). Чтобы убедиться, что вы предупреждены о неполных реализациях категорий, вы должны реализовать их:Вот небольшая аннотированная шпаргалка:
MONObject.h
MONObject.m
Другой подход, который может быть неочевидным: тип C ++ может быть очень быстрым и обеспечивать гораздо более высокую степень контроля при минимизации количества экспортируемых и загружаемых методов objc.
источник
Вы можете попытаться определить статическую функцию ниже или выше вашей реализации, которая принимает указатель на ваш экземпляр. Он сможет получить доступ к любой из ваших переменных экземпляров.
источник
Вы могли бы использовать блоки?
Я знаю, что это старый вопрос, но он один из первых, который я нашел, когда искал ответ на этот вопрос. Я не видел, чтобы это решение обсуждалось где-либо еще, поэтому дайте мне знать, если в этом есть что-то глупое.
источник
static
). Но я экспериментировал с назначением блоков частным иварам (из метода init) - своего рода JavaScript-стиль - который также позволяет получить доступ к частным иварам, что невозможно из статических функций. Еще не уверен, что я предпочитаю.все объекты в Objective C соответствуют протоколу NSObject , который поддерживает метод executeSelector : . Я также ранее искал способ создания некоторых «вспомогательных или частных» методов, которые мне не нужны были бы доступны на публичном уровне. Если вы хотите создать приватный метод без накладных расходов и не определять его в заголовочном файле, тогда попробуйте ...
определите ваш метод с такой же сигнатурой, как в коде ниже ...
тогда, когда вам нужно обратиться к методу, просто вызовите его как селектор ...
эта строка кода вызовет созданный вами метод и не будет раздражать предупреждением о том, что он не определен в заголовочном файле.
источник
Если вы хотите избежать
@interface
блока сверху, вы всегда можете поместить частные объявления в другой файл,MyClassPrivate.h
не идеальный, но не загромождающий реализацию.MyClass.h
MyClassPrivate.h
MyClass.m
источник
Еще одна вещь, о которой я не упоминал, упоминается здесь - Xcode поддерживает файлы .h с именем "_private". Допустим, у вас есть класс MyClass - у вас есть MyClass.m и MyClass.h, и теперь у вас также может быть MyClass_private.h. XCode распознает это и включит его в список «контрагентов» в помощнике редактора.
источник
Нет способа обойти проблему № 2. Именно так работает компилятор C (и, следовательно, компилятор Objective-C). Если вы используете редактор XCode, функция всплывающих должны легко перемещаться по
@interface
и@implementation
блоков в файле.источник
Есть преимущество отсутствия частных методов. Вы можете переместить логику, которую вы намеревались скрыть, в отдельный класс и использовать ее в качестве делегата. В этом случае вы можете пометить объект делегата как закрытый, и он не будет виден снаружи. Перемещение логики в отдельный класс (возможно, в несколько) улучшает дизайн вашего проекта. Потому что ваши классы становятся проще, а ваши методы сгруппированы в классы с собственными именами.
источник
Как говорили другие люди, определение приватных методов в
@implementation
блоке подходит для большинства целей.На тему организации кода - мне нравится держать их вместе
pragma mark private
для облегчения навигации в Xcodeисточник