Autosynthesized property 'delegate' будет использовать синтезированную переменную экземпляра '_delegate', а не существующую переменную экземпляра 'delegate'

17

Я следую руководству здесь , чтобы создать пользовательский делегат. Он работает нормально, но я получаю следующее предупреждение в xcode

  

DetailViewController.m: 23: 1: Autosynthesized свойство 'delegate' будет   использовать синтезированную переменную экземпляра '_delegate', не существующий экземпляр   переменная 'delegate'

Может ли кто-нибудь посоветовать, как избавиться от предупреждения

    
задан totalitarian 06.01.2013 в 18:22
источник

2 ответа

39

Самый идиоматический способ справиться с этой ситуацией - просто удалить свою декларацию delegate ivar. Если вы использовали delegate ivar, вы должны использовать неявный ivar _delegate .

Почему это работает?

Как Xcode 4.4 (LLVM Compiler 4.0) , переменные экземпляра и методы доступа автоматически синтезируются для свойства , если директива @synthesize не используется явно для этого свойства . Как документация Apple по инкапсуляции утверждает

  

По умолчанию [...] методы доступа автоматически синтезируются для вас компилятором, поэтому вам не нужно ничего делать, кроме объявления свойства, используя @property в интерфейсе класса.

Ивар, который используется для свойства (который получил и задан с помощью методов автоматизированного синтезатора свойств), называется _<propertyName> (то есть имя ivar является именем свойства с префиксом подчеркивания).

В этом случае имя свойства delegate , поэтому используемый ivar равен _delegate . Это уже происходит в вашем коде. Когда вы вызываете -delegate и -setDelegate: , этот ivar _delegate будет получен и установлен.

Однако вы также указали свой собственный ivar delegate . Конечно, ivar, который вы явно объявили ( delegate ), не будет получен и установлен методами экземпляра -delegate и -setDelegate: , поскольку автоматически синтезированный ivar ( _delegate ) будет получен и установлен. Однако (почти всегда - если это не так, ваш код неоднозначен), ваше намерение заключалось в том, что ваш ivar delegate будет тем, что ваши аксессуры вашей собственности будут получать и устанавливать. К счастью, компилятор достаточно умен, чтобы заметить, что вы сделали, и именно поэтому он излучает это предупреждение:

  

warning: autosynthesized property ' delegate ' будет использовать синтезированную переменную экземпляра ' _delegate ', не существующую переменную экземпляра ' delegate ' [ -Wobjc-autosynthesis-property-ivar-name-match ]

Это говорит вам, что ваше свойство delegate будет использовать автоматически синтезированный ivar _delegate , а не ivar, который вы явно объявили, delegate .

Итак, если вы просто удалите delegate ivar, компилятор прекратит выдавать это предупреждение. Если вы использовали delegate ivar напрямую (не через свойство), вместо этого используйте _delegate .

Небольшой вариант этой опции заключается в том, чтобы явно объявить тот же ivar ( _delegate ), что создается автоматический синтез свойства delegate . Вы можете сделать это, заменив

@interface TheClass : TheSuperclass
{
    //...
    id<TheDelegateProtocol> delegate
    //...
}
@end

с

@interface TheClass : TheSuperclass
{
    //...
    id<TheDelegateProtocol> _delegate
    //...
}
@end

Это работает, потому что автоматический синтез свойства всегда будет использовать ivar, чье имя является именем свойства с префиксом подчеркивания. Если такой ivar не существует, будет создан ivar. Если он существует, он будет использоваться.

Если вместо этого вы предпочтете, чтобы аксессоры вашего свойства были установлены и получили ваш ivar delegate , вы можете добавить директиву @synthesize в свой класс @implementation , чтобы сообщить компилятору сделать именно это:

@implementation TheClass
//...
@synthesize delegate = delegate;
//...
@end

Строка @synthesize delegate = delegate; сообщает компилятору использовать ivar delegate (правую часть назначения) в аксессуарах для свойства delegate (левая сторона задания).

Вы также можете опустить правую часть задания @synthesize и просто написать

@implementation TheClass
//...
@synthesize delegate;
//...
@end

Это работает, потому что свойство с ручным @synthesize , которое явно не указывает, что ivar, который должен быть получен и установлен его аксессуарами (например, @synthesize delegate; ), будет использовать ivar с тем же именем, что и свойство, NOT prefixed под знаком подчеркивания. Это связано с обратной совместимостью.

    
ответ дан Nate Chandler 06.01.2013 в 18:28
источник
2

Есть еще один метод, и это помогло мне:

@property (nonatomic, unsafe_unretained) id <MyDelegate> delegate;

Затем вы можете добавить это в реализацию без ошибок:

@synthesize delegate;

Также: это совместимо с ARC.

    
ответ дан mpemburn 21.02.2013 в 15:51
источник