Відмінності між інтерфейсами Java та протоколами Objective-C?


93

Я знаю Java, і тепер я навчаюсь Objective-C. Які саме відмінності між інтерфейсами Java та протоколами Objective-C?

Відповіді:


82

По-перше, трохи історичного погляду на цю тему , від одного із творців Java. Далі у Вікіпедії є помірно корисний розділ про протоколи Objective-C . Зокрема, розумійте, що Objective-C підтримує як формальні протоколи (явно декларовані за допомогою @protocolключового слова, еквівалент інтерфейсу Java), так і неформальні протоколи (лише один або кілька методів, реалізованих класом, які можна виявити за допомогою відображення).

Якщо ви приймете офіційний протокол (термінологія «Objective-C» для «реалізації інтерфейсу»), компілятор надсилатиме попередження щодо нереалізованих методів так само, як ви очікували в Java. На відміну від Java (як згадував скаффман ), якщо клас Objective-C реалізує методи, що містяться в офіційному протоколі, кажуть, що він "відповідає" цьому протоколу, навіть якщо його інтерфейс прямо не приймає його.Ви можете перевірити відповідність протоколу в коді (використовуючи -conformsToProtocol:) таким чином:

if ([myObject conformsToProtocol:@protocol(MyProtocol)]) {
    ...
}

ПРИМІТКА. У документації Apple зазначено:

"Цей метод визначає відповідність виключно на основі формальних декларацій у файлах заголовків, як показано вище. Він не перевіряє, чи реалізовані методи, заявлені в протоколі, реально - це відповідальність програміста."

Як і для Objective-C 2.0 (в OS X 10.5 "Leopard" та iOS), формальні протоколи тепер можуть визначати необов'язкові методи , і клас відповідає протоколу, якщо він реалізує всі необхідні методи. Ви можете використовувати @required(за замовчуванням) та @optionalключові слова, щоб увімкнути, чи слід або можуть бути реалізовані декларації методу для відповідності протоколу. (Див. Розділ посібника з мови програмування Apple Objective-C 2.0, який обговорює необов'язкові методи протоколу .)

Необов’язкові методи протоколу відкривають велику гнучкість розробникам, особливо для впровадження делегатів та слухачів . Замість того, щоб розширювати щось на зразок MouseInputAdapter (що може дратувати, оскільки Java також є однонаспадковим ) або впроваджувати безліч безглуздих, порожніх методів, ви можете прийняти протокол і реалізувати лише необов’язкові вами важливі методи. За допомогою цього шаблону абонент перевіряє, чи реалізований метод, перш ніж викликати його (використовуючи -respondsToSelector ) так:

if ([myObject respondsToSelector:@selector(fillArray:withObject:)]) {
    [myObject fillArray:anArray withObject:foo];
    ...
}

Якщо накладні роздуми стають проблемою, ви завжди можете кешувати булевий результат для повторного використання , але протистояти позиву до оптимізації передчасно. :-)


4
"Якщо ви приймаєте офіційний протокол (термін" Objective-C "для" реалізації інтерфейсу "), компілятор надсилатиме попередження щодо невтілених методів так, як ви очікували в Java." У цьому випадку Java видасть помилку, а не попередження.
Раффі Хатчадуріан

3
"якщо клас Objective-C реалізує методи, що містяться в офіційному протоколі, кажуть, що він" відповідає "цьому протоколу, навіть якщо його інтерфейс прямо не приймає його. Ви можете перевірити відповідність протоколу в коді (використовуючи -conformsToProtocol: ) на кшталт цього "Це ЛЮДИНО. -conformsToProtocol:поверне YES лише тоді, коли клас явно приймає протокол. Ви навіть пробували це?
користувач102008

2
Ви прав, -conformsToProtocol:чи дійсно вимагає, щоб клас (або пращур) офіційно заявив, що він приймає протокол. Не впевнений, як я помилився, дякую за виправлення!
Квінн Тейлор

18

Вони майже однакові. Однак одне, що мене застало, це те, що якщо ви прямо не заявите, що об'єктивний протокол C також реалізує NSObject, посилання на цей протокол не отримують доступу до методів, які NSObject оголошує (без попередження компілятора). З java ви можете мати посилання на інтерфейс і все ще дзвонити на toString () тощо на ньому.

напр

Завдання C:

@protocol MyProtocol
// Protocol definition
@end

id <MyProtocol> myProtocol;

 [myProtocol retain] // Compiler warning

Java:

public interface MyInterface {
// interface definition
}

MyInterface myInterface;

myInterface.toString();  // Works fine.

Завдання C (фіксовано):

@protocol MyProtocol <NSObject>
// Protocol definition
@end

id <MyProtocol> myProtocol;

[myProtocol retain] // No Warning

25
Це тому, що id та NSObject не є однаковими . У Java кореневим об'єктом є Object. У Objective-C, NSObject є кореневим об'єктом, але не кореневої об'єкт. Якщо ви хочете отримати доступ до всіх методів NSObject (методів класу, а також протоколів), констатуйте це явно: NSObject <MyProtocol> myProtocol; замість: id <MyProtocol> ... Коли ви використовуєте id, ви говорите: Мене не цікавить об'єкт, лише протокол, який у вашому випадку не відповідає дійсності.
Джейсон Коко
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.