Почему я должен привести себя к ид? - PullRequest
5 голосов
/ 23 ноября 2008

У меня есть метод init, который принимает аргумент (id):


    -(id) initWithObject:(id) obj;

Я пытаюсь назвать это так:


    [[MyClass alloc] initWithObject:self];

Но XCode жалуется на то, что аргумент является «отдельным типом Objective-C» (который обычно указывает на несоответствие типов или уровень ошибки косвенности).

Если я явно приведу себя к (id), предупреждение исчезнет. В любом случае код работает как ожидалось. Интересно, что в следующей строке я передаю себя другому методу, который также принимает идентификатор, и он отлично работает.

Мне интересно, что я упускаю что-то неуловимое - или это особенность компилятора?

Мне не совсем удобно просто разыгрывать его, пока я не буду уверен в причинах, почему это необходимо.

[Изменить]

Меня попросили предоставить больше кода. Не уверен, что есть еще что-то, что имеет отношение к делу. Вот мой фактический код, который делает звонок. Обратите внимание, что он находится внутри метода init. Это звонок initWithSource, который дает предупреждение:


-(id) initWithFrame:(CGRect) frame
{
    self = [super initWithFrame: frame];
    if( self )
    {
        delegate = nil;
        touchDelegate = [[TBCTouchDelegate alloc] initWithSource:self];
        [touchDelegate.viewWasTappedEvent addTarget: self action:@selector(viewWasTapped:)];
    }
    return self;
}

А вот вызываемый метод init:


-(id) initWithSource:(id) sourceObject
{
    self = [super init];
    if (self != nil) 
    {
        // Uninteresting initialisation snipped
    }
    return self;
}

1 Ответ

7 голосов
/ 23 ноября 2008

Обычно это означает, что существует несколько initWithSource: имен методов в разных классах с конфликтующими типами аргументов. Помните, что если переменная имеет тип id, компилятор не знает, что это за класс. Таким образом, если вы вызываете initWithSource: для id -типового объекта, а у нескольких классов есть метод initWithSource:, компилятор по существу просто выбирает один из двух. Если он выберет «неправильный», то вы получите «отдельный тип Objective-C».

Так почему это происходит с вами? Я не уверен на 100%, но помните, что +[TBCTouchDelegate alloc] возвращает id. Таким образом, создание цепочки вызовов alloc / init эквивалентно следующему:

id o = [TBCTouchDelegate alloc];
touchDelegate = [o initWithSource:self];

Следовательно, вы вызываете initWithSource: для переменной id. Если существует конфликтующий метод initWithSource:, вы можете получить эту ошибку компилятора.

Есть ли конфликтующий метод? Я проверил систему, и единственный конфликтующий был в NSAppleScript:

- (id)initWithSource:(NSString *)source;

Теперь NSAppleScript является частью Foundation, но я заметил, что это код iPhone. Так, возможно, вы получаете эту ошибку только при компиляции для симулятора, а не устройства?

В любом случае, если это ваша проблема, вы можете обойти ее, разделив alloc / init на две разные строки:

touchDelegate = [TBCTouchDelegate alloc];
touchDelegate = [touchDelegate initWithSource:self];

Теперь вы вызываете initWithSource: для полностью типизированной переменной (вместо id), поэтому компилятору больше не нужно угадывать, какую из них выбрать. Или вы можете разыграть возврат из +alloc:

touchDelegate = [(TBCTouchDelegate *)[TBCTouchDelegate alloc] initWithSource:self];

Другое решение - переименовать initWithSource:, чтобы избежать конфликта и, возможно, сделать его более наглядным. Вы не говорите, как называется класс в настоящее время, и для чего предназначен «источник», поэтому я не могу выбросить какие-либо возможности.

...