Почему id это общий указатель? - PullRequest
9 голосов
/ 24 октября 2011

Я хочу знать, почему id является слабым ссылочным указателем, как он может обрабатывать любой указатель типа class и во время выполнения, как мы можем определить, какой тип указателя класса назначен id.

Ответы [ 3 ]

17 голосов
/ 24 октября 2011

Почему id является слабым ссылочным указателем?

id не является слабым ссылочным указателем, по крайней мере, не в смысле владения ARC. Слабая ссылка типа id на объект или нет, зависит от того, была ли объявлена ​​ссылка __weak (и варианты), и от класса объекта, фактически поддерживающего слабые ссылки.

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

Как он может обрабатывать любой указатель типа класса?

Это часть определения языка Objective-C . Компилятор распознает id как супертип каждого класса Objective-C и обрабатывает id по-разному. Смотрите также ответ ниже.

Во время выполнения, как мы можем определить, какой тип указателя класса назначен на id?

Во время выполнения Apple Objective-C первые байты в памяти, выделенной для объекта, должны указывать на класс этого объекта. Вы можете увидеть это в другом месте как указатель isa, и именно так среда выполнения Apple определяет класс каждого объекта 1 . Тип id также определен, чтобы иметь эту информацию. Фактически, его единственный атрибут - указатель isa, что означает, что все объекты 1 Objective-C соответствуют этому определению.

Если у вас есть ссылка id и вы хотите узнать класс ссылочного объекта, вы можете отправить его -class:

id someObject;

// Assign something to someObject

// Log the corresponding class
Class c = [someObject class];
NSLog(@"class = %@", c);

// Test whether the object is of type NSString (or a subclass of NSString)
if ([someObject isKindOfClass:[NSString class]]) {
    NSLog(@"it's a string");
}

1 Помеченные указатели являются заметным отклонением этой структуры, и (частично) из-за них нельзя напрямую обращаться к указателю isa.

8 голосов
/ 24 октября 2011

Хорошо иметь универсальный тип объекта, поэтому вы можете определить типы коллекций, которые могут содержать любой тип объекта, и другие универсальные сервисы, которые работают с любым объектом, не зная, какой это тип объекта.

Нет хитрости, чтобы заставить id работать. На двоичном уровне все указатели являются взаимозаменяемыми. Они просто представляют адрес памяти в виде числового значения. Чтобы id мог принять любой тип указателя, необходимо только отключить правила компилятора, которые обычно требуют, чтобы типы указателей совпадали.

Вы можете узнать информацию о классе переменной типа id следующими способами:

id theObject = // ... something
Class theClass = [theObject class];
NSString *className = NSStringFromClass(theClass);
NSClassDescription *classDescription = [NSClassDescription classDescriptionForClass:theClass];

Но редко нужно делать такие вещи в коде. Чаще вы хотите проверить, является ли ваша переменная id экземпляром определенного класса, и если это так, привести его к этому классу и начать обрабатывать его как этот тип.

if ([theObject isKindOfClass:[MySpecializedClass class]]) {
    MySpecializedClass *specialObject = (MySpecializedClass *)theObject;
    [specialObject doSomethingSpecial];
}

Если бы вы использовали -class, чтобы узнать класс, но он возвратил класс, о котором вы ничего не знаете, то в любом случае вы ничего не можете сделать с объектом, основанным на его классе. Так что нет никаких оснований что-либо делать, кроме как проверять, соответствуют ли они классам, о которых вы знаете, и только в том случае, если вы все равно намереваетесь выполнить специальную обработку для этих классов.

Иногда вы можете использовать isMemberOfClass вместо isKindOfClass. Это зависит от того, хотите ли вы точное соответствие или включить подклассы.

3 голосов
/ 24 октября 2011

Возможно, стоит заглянуть в заголовочный файл objc / objc.h, чтобы найти внутренние компоненты id.

typedef struct objc_class *Class;
typedef struct objc_object {
   Class isa;
} *id;


typedef struct objc_selector    *SEL;    
typedef id          (*IMP)(id, SEL, ...); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...