Скрытые возможности Objective-C

Objective-C получает все более широкое распространение благодаря его использованию Apple для Mac OS X и разработки для iPhone. Какие из «скрытых» функций языка Objective-C вам больше всего нравятся?

  • Одна функция на ответ.
  • Приведите пример и краткое описание функции, а не просто ссылку на документацию.
  • Обозначьте объект, используя заголовок в первой строке.

См. Сообщения meta.stackexchange.com/questions/56669/…, meta.stackexchange.com/questions/57226/… и связанные с ними мета-сообщения.

Roger Pate 16.07.2010 06:57
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
12
1
33 003
8

Ответы 8

Позирует

Objective-C разрешает классу полностью заменить другой класс в приложении. Говорят, что замещающий класс «изображает» целевой класс. Все сообщения, отправленные целевому классу, вместо этого принимаются позирующим классом. Существуют некоторые ограничения на то, какие классы могут позировать:

  • Класс может изображать только один из своих прямых или косвенных суперклассов.
  • Позирующий класс не должен определять какие-либо новые переменные экземпляра, которые отсутствуют в целевом классе (хотя он может определять или переопределять методы).
  • Никакие сообщения не должны быть отправлены целевому классу до позирования.

Позирование, как и категории, позволяет использовать глобальное расширение существующих классов. Постановка разрешает две функции, отсутствующие в категориях:

  • Позирующий класс может вызывать переопределенные методы через super, таким образом, включая реализацию целевого класса.
  • Позирующий класс может переопределять методы, определенные в категориях.

Пример:

@interface CustomNSApplication : NSApplication
@end

@implementation CustomNSApplication
- (void) setMainMenu: (NSMenu*) menu
{
     // do something with menu
}
@end

class_poseAs ([CustomNSApplication class], [NSApplication class]);

Это перехватывает каждый вызов setMainMenu для NSApplication.

Class_poseAs устарел, начиная с версии 10.5. Замена делает то же самое для каждого метода, что теперь явно поддерживается во время выполнения.

Ken 19.10.2008 22:19

Упс, забыл связать документы.

Ken 19.10.2008 22:22
#include <Foundation/Debug.h>

Множество инструментов для отслеживания утечек памяти, преждевременных отключений и многого другого в этом заголовочном файле.

Это специфично для Cocoa (может быть, и OpenSTEP?), А не языковой функции, хотя, поскольку никто не использует ObjC, кроме как с Cocoa, я думаю, это не имеет большого значения

Mark Baker 17.10.2008 19:44

Итак, это не работает для Cocoa Touch, то есть iOS? Что именно он делает?

ma11hew28 13.06.2011 04:09

Пересылка объекта / отсутствует метод

Когда объекту отправляется сообщение, для которого у него нет метод, исполняющая система дает ему еще один шанс обработать звонок перед тем, как отказаться. Если объект поддерживает -forward :: method, среда выполнения вызывает этот метод, передавая ему информация о необработанном звонке. Возвращаемое значение из переадресованный вызов возвращается к исходному вызывающему абоненту метод.

-(retval_t)forward:(SEL)sel :(arglist_t)args {
  if ([myDelegate respondsTo:sel])
 return [myDelegate performv:sel :args]
 else
 return [super forward:sel :args];
 }

Контент из Карманный справочник Objective-C

Это очень мощный инструмент, который активно используется сообществом Ruby для различных DSL, рельсов и т. д. Изначально он возник в Smalltalk, который повлиял как на Objective-C, так и на Ruby.

Я бы рекомендовал вместо этого использовать документированный метод «- [NSObject forwardInvocation:]». Недокументированный метод -[Object forward::] давно устарел и больше не доступен в современной среде выполнения Objective-C. Такие как 64-битные и ARM на устройствах iOS.

PeyloW 10.01.2011 10:43

Кто-нибудь знает, работает ли это еще? Кажется, я не могу найти никакой документации по этому поводу.

Richard J. Ross III 08.01.2012 03:34

Метод Swizzling

По сути, во время выполнения вы можете заменить одну реализацию метода другой.

Вот объяснение с кодом.

Один из умных вариантов использования - это отложенная загрузка разделяемого ресурса: обычно вы реализуете метод sharedFoo, приобретая блокировку, создавая foo, если необходимо, получая его адрес, снимая блокировку, а затем возвращая foo. Это гарантирует, что foo создается только один раз, но каждый последующий доступ тратит время на блокировку, которая больше не нужна.

С помощью смены методов вы можете сделать то же самое, что и раньше, за исключением того, что после создания foo используйте swizzling для замены первоначальной реализации sharedFoo на вторую, которая не выполняет никаких проверок и просто возвращает foo, который, как мы теперь знаем, был создан. !

Конечно, замена методов может вызвать у вас проблемы, и могут быть ситуации, когда приведенный выше пример - плохая идея, но эй ... вот почему это функция скрытый.

Справочник по среде выполнения Objective-C

Легко забыть, что синтаксический сахар Objective-C преобразуется в обычные вызовы функций C, которые являются средой выполнения Object-C. Скорее всего, вам никогда не придется вникать в что-либо и использовать что-либо во время выполнения. Вот почему я считаю это «скрытой функцией».

Позвольте мне указать способ использования системы времени выполнения.

Допустим, кто-то разрабатывает внешний API-интерфейс фреймворка, который будет использоваться третьими сторонами. И если кто-то разрабатывает класс в структуре, который абстрактно представляет пакет данных, мы назовем его MLAbstractDataPacket. Теперь дело за приложением, которое связывает во фреймворке подкласс MLAbstractDataPacket и определяет пакеты данных подкласса. Каждый подкласс должен переопределять метод +(BOOL)isMyKindOfDataPacket:(NSData *)data.

Имея в виду эту информацию ...

Было бы неплохо, если бы MLAbstractDataPacket предоставил удобный метод, возвращающий правильный инициализированный класс для пакета данных, который поступает в форме +(id)initWithDataPacket:(NSData *)data.

Здесь только одна проблема. Суперкласс не знает ни о одном из своих подклассов. Итак, здесь вы можете использовать метод среды выполнения objc_getClassList() вместе с objc_getSuperclass(), чтобы найти классы, которые являются подклассами MLAbstractDataPacket. Когда у вас есть список подклассов, вы можете затем пробовать +isMyKindOfDataPacket: на каждом, пока один из них не будет найден или не найден.

Справочную информацию об этом можно найти в http://developer.apple.com/documentation/Cocoa/Reference/ObjCRuntimeRef/Reference/reference.html.

Категории

Используя категории, вы можете добавлять методы во встроенные классы без создания подклассов. Полная ссылка.

Приятно добавлять удобные методы к часто используемым классам, таким как NSString или NSData.

Отличный совет, но не совсем скрытый… :)

Jonathan Sterling 05.03.2010 18:39

Мне нравится подробное именование методов, например [myArray writeToFile:myPath atomically:YES], где у каждого аргумента есть метка.

Как это спрятано? ... :)

Kuba Suder 07.03.2010 17:24

@Psionides: Это довольно очевидно для людей, которые на самом деле используют этот язык, я согласен, но большинство людей, переходящих на какой-то другой язык, похоже, упускают этот простой факт. по крайней мере, люди, с которыми я разговаривал.

Kris 07.03.2010 18:00

Вы не можете его пропустить! Нет, если вы действительно хотите передавать сообщения!

Casebash 20.09.2010 07:23

Переключение ISA

Нужно переопределить все поведение объекта? Фактически вы можете изменить класс активного объекта с помощью одной строчки кода:

obj->isa = [NewClass class];

Это изменяет только класс, который принимает вызовы методов для этого объекта; он не меняет расположение объекта в памяти. Таким образом, это действительно полезно только тогда, когда у вас есть набор классов с одинаковыми ivars (или один с подмножеством других), и вы хотите переключаться между ними.

Один фрагмент кода, который я написал, использует это для отложенной загрузки: он выделяет объект класса A, заполняет пару критических ivars (в данном случае в основном номер записи) и переключает указатель isa на LazyA. Когда вызывается любой метод, кроме очень маленького набора, такого как release и retain, LazyA загружает все данные с диска, завершает заполнение ivars, переключает указатель isa обратно на A и перенаправляет вызов реальному классу.

Боже мой, я никогда об этом не думал. Мне нужно это проверить, потому что это великолепно. Интересно, есть ли какие-нибудь неприятные побочные эффекты?

Jonathan Sterling 05.03.2010 18:40

Я попробовал это, чтобы ответить на stackoverflow.com/questions/874906/…, но получаю ошибку компиляции: Instance variable 'isa' is protected. Есть ли способ обойти это? См. stackoverflow.com/questions/8512793/…

ma11hew28 15.12.2011 02:45

@MattDiPasquale Главный ответ правильный - современный способ сделать это - использовать objc_setClass ().

Brent Royal-Gordon 15.12.2011 05:45

Другие вопросы по теме