Какой самый надежный и читаемый способ обеспечения соответствия объектов интерфейсу / протоколу в Objective C? - PullRequest
2 голосов
/ 18 февраля 2012

Я пытаюсь написать код для интерфейса (или протокола в терминологии Objective C.), а не для его реализации.

Очень важно, чтобы мы проверяли объекты на соответствие протоколу, прежде чем вызывать методы для них, чтобы предотвратить сбои.

Три способа

  1. В компиляторе
  2. Во время выполнения
  3. Оба

Лучшее решение ... Конечно, номер 1?

Я думал, что лучший способ будет в компиляторе:

  • Предупреждения, если вы облажаетесь
  • Устраняет conformsToProtocol: / responsedsToSelector: шаблон
  • Во время выполнения слишком поздно, если вы допустили ошибку - лучшее, что вы можете сделать, - не выполнить код / ​​показать ошибкуувидеть много кода, который делает это во время выполнения.Зачем?

    Это проблема читабельности - нужно id <Protocol> везде?

    Мой вопрос

    Какой самый надежный и читаемый способ обеспечения соответствия объектовинтерфейс / протокол?

    код

    1.Проверка в компиляторе

    @interface ReportController : NSObject {
        id <ReportGenerator> generator;
        id <ReportSender> sender;
        id report;
    }
    
    @implementation ReportController
    
    -(id)initWithReportGenerator:(id <ReportGenerator>)generator_
                    reportSender:(id <ReportSender>)sender_ {
        // Usual init stuff
        generator = generator_;
        sender = sender_;
        return self;
    }
    
    -(void)generateAndSend {
        report = [generator generate];
        [sender sendReport:report];
    }
    
    @end
    

    2.Проверка во время выполнения

    @interface ReportController : NSObject {
        id generator;
        id sender;
        id report;
    }
    
    @implementation ReportController
    
    -(id)initWithReportGenerator:(id)generator_
                    reportSender:(id)sender_ {
        // Usual init stuff
        generator = generator_;
        sender = sender_;
        return self;
    }
    
    -(void)generateAndSend {
        if ([generator conformsToProtocol:@protocol(ReportGenerator)] &&
            [sender conformsToProtocol:@protocol(ReportSender)]) {
            report = [generator generate];
            [sender sendReport:report];
        } else {
            [NSException raise:NSInternalInconsistencyException format:@"Objects didn't respond to protocols..."];
        }
    }
    
    @end
    

Ответы [ 3 ]

4 голосов
/ 18 февраля 2012

Вы должны использовать оба.Например:

@protocol Proto
- (void)someFunction;
@end

@interface C : NSObject
- (void)proto:(id<Proto>)p;
@end

// ...
NSString *s = @"moo";
id i = s;

C *c = [[C alloc] init];
[c proto:s]; // warns
[c proto:i]; // doesn't warn

Objective-C и Cocoa слишком динамичны, чтобы вообще проверять такие вещи во время компиляции (NSProxy standins, классы, динамически добавляющие методы и протоколы, ...).
Itприятно перехватывать как можно больше таких ошибок во время компиляции, но одного этого недостаточно.

3 голосов
/ 18 февраля 2012

Пока вы не используете обычный id в качестве типа, компилятор по крайней мере предупредит вас, если вы допустите ошибку во время компиляции. Так что с вашим примером кода все должно быть в порядке.

Конечно, иногда вас могут заставить работать с id объектом, который вы получаете из подсистемы, которая не находится под вашим контролем. В таких случаях вы можете привести объект обратно к типу, который вы считаете имеющимся у него (например, id <ReportGenerator>), но вам, как правило, лучше, если вы сначала выполните проверку во время выполнения. Лучше быть в безопасности, чем потом сожалеть ...

И последнее замечание: если в вашем протоколе есть необязательные части (объявленные с ключевым словом @optional), то для этих частей вы, очевидно, сможете выполнять только проверки во время выполнения. Ключевое слово @required, упомянутое apurv, необходимо, только если вы хотите быть явным в объявлении протокола (части протокола требуются по умолчанию) или если вы смешиваете необязательные и обязательные части.

0 голосов
/ 18 февраля 2012

Вы должны создать методы с типом @required в протоколе. Поэтому любой класс, желающий получить контракт с этим протоколом, должен будет реализовать эти методы. Это определенно обеспечит доступность необходимых методов только во время компиляции.

...