-1

Objective-C で次のことをしなければならない理由がわかりません。一般的な意味での理由を発見することに興味があります (つまり、言語/コンパイラが私にこのようにすることを強制する理由)。

私はプロトコルを持っています:

// (file: MyObserver.h)
@class TheObserved;
@protocol MyObserver <NSObject>
   - (void)itWasObserved:(TheObserved *)observedInstance;
@end

プロトコルを (周期的に) 使用するインターフェース「TheObserved」があります。

// (file: TheObserved.h)
@protocol MyObserver;
@interface TheObserved : NSObject
   @property id <MyObserver> myObserver;
   - (void)lookAtThisData:(NSString *)someData withObserver:(id <MyObserver>)observer;
@end

つまり、ご覧のとおり、プロトコルにはインターフェイスのインスタンスを取るメッセージがあり、インターフェイスにはプロトコルを実装するインスタンスを取るメソッドがあります。

インターフェイスの私の実装では:

// (file: TheObserved.m)
#import "TheObserved.h"
#import "MyViewController.h" // <-- note this import
@implementation TheObserved
    @synthesize myObserver;

    - (void)lookAtThisData:(NSString *)someData withObserver:(id <MyObserver>)observer {
        self.myObserver = observer;
        // some asynchronous looking at the data is done here.
    }

    - (void)asynchCallback:(NSData *) data {
        // check if the data is as we expect, if so ..
        [self.myObserver itWasObserver: self]
    }
@end

MyViewController.h はプロトコルを実装します。

// (file: MyViewController.h)
#import <UIKit/UIKit.h>
#import "OWLMorphDataObserver.h"
@interface MyViewController : UITableViewController <MyObserver>
@end

そしてその実装では:

// (file: MyViewController.m)
#import "TheObserved.h"
@interface MyViewController () {
  @property TheObserved *observed;
@end

@implementation MyViewController
   @synthesize observed;
   - (void) aMethod:(NSString *)dataString {
       [self.observed lookAtThisData:dataString withObserver:self]
   }
@end

私の質問は、具体的な実装が Observed クラスで明示的に参照されていないにもかかわらず、Observed クラスで @protocol を実装する "MyViewController.h" を #import する必要があるのはなぜですか? そうしないと、コンパイル エラーが発生します。

no known instance method for selector 'lookAtThisData:'

ここでの問題は、もちろん、複数の異なるビュー コントローラーにこのプロトコルを実装させたいということです。では、なぜそれらの 1 つをインポートしてコンパイルする必要があるのでしょうか。

使用したいクラスにプロトコルの具体的な実装をインポートせずに、このコードを構造化して目的の効果を得る別の方法はありますか?

4

3 に答える 3

2

「MyViewController.h」をインポートする必要はありません。

「MyObserver.h」をインポートする必要があります。そうしないと、MyObserver プロトコルが不明になります。プロトコル MyObserver を参照する場合は、プロトコルを定義するファイルをインポートする必要があります。そのファイルは「MyObserver.h」です。

また、メソッドを参照したい場合はlookAtThisData:withObserver:、「TheObserver.h」をインポートする必要があります。これは、そのメソッドが公開されている場所だからです。

于 2013-03-29T01:45:10.530 に答える
1

申し訳ありませんが、あなたの例に従うのに苦労しています。追加のインクルードを必要とせずにこのパターンを使用します...

クラスは、他の人が実装するプロトコルを定義します...

//  Foo.h

@protocol FooDelegate;  // promise to define protocol, so we can refer to it in @interface

@interface Foo : NSObject
@property(nonatomic, weak) id<FooDelegate> delegate;
@end

// now define the protocol
@protocol FooDelegate <NSObject>
- (CGFloat)getFloatForFoo:(Foo *)aFoo;
@end

実装は、デリゲートがそれを実装していることを知って、プロトコルを呼び出すことができます...

// Foo.m

#import "Foo.h"

- (void)anyFooMethod {
    CGFloat aFloatFromMyDelegate = [self.delegate getFloatForFoo:self];
}

別のクラスが自身をプロトコルの実装者として宣言します (公開または非公開ですが、通常は非公開が適切です)。

// OtherClass.m

#import "Foo.h"  // notice only one, intuitive import

@interface OtherClass <FooDelegate>
@end

@implementation OtherClass

- (id)init {

    // normal init jazz
    Foo *aFoo = [[Foo alloc] init];
    aFoo.delegate = self;
}

@end
于 2013-03-29T01:40:13.773 に答える
1

あなたの例は私には不完全に思えたので、問題を説明していると思われる例を自己完結型の方法で作成しまし

MyObserver.h:

#import <Foundation/Foundation.h>

@class TheObserved;

@protocol MyObserver <NSObject>
- (void)itWasObserved:(TheObserved *)observedInstance;
@end

TheObserved.h:

#import <Foundation/Foundation.h>

@protocol MyObserver;

@interface TheObserved : NSObject

@property id <MyObserver> myObserver;
- (void)lookAtThisData:(NSString *)someData withObserver:(id <MyObserver>)observer;

@end

TheObserved.m:

#import "TheObserved.h"

@implementation TheObserved
@synthesize myObserver;

- (void)lookAtThisData:(NSString *)someData withObserver:(id <MyObserver>)observer {
    self.myObserver = observer;
    // some asynchronous looking at the data is done here.
}

- (void)asynchCallback:(NSData *) data {
    // check if the data is as we expect, if so ..
    [self.myObserver itWasObserved: self];
}
@end

MyObserverImplementation.h: (これはあなたの例では MyViewController.h です)

#import <Foundation/Foundation.h>
#import "MyObserver.h"

@interface MyObserverImplementation : NSObject <MyObserver>

@end

MyObserverImplementation.m:

#import "MyObserverImplementation.h"
#import "TheObserved.h"

@interface MyObserverImplementation ()
@property TheObserved *observed;
@end

@implementation MyObserverImplementation

- (void) aMethod:(NSString *)dataString {
    [self.observed lookAtThisData:dataString withObserver:self];
}

@end

TheObserved.h のエラーのため、このプログラムはビルドされません。

セレクター 'itWasObserved:' の既知のインスタンス メソッドはありません

ただし、TheObserved.m から MyObserverImplementation.h をインポートすると、このエラーは修正されます (これは、TheObserved.m から MyViewController.h をインポートする必要があることに似ています)。ただし、MyObserverImplementation.h が MyObserver.h をインポートするため、エラーが修正されるだけです。それ以外の場合、TheObserved.m は MyObserver.h で宣言されたメソッドの可視性を持ちません。これは、プロトコルを前方宣言しただけで、インポートしたことがないためです。

ビュー コントローラーをインポートする代わりに、TheObserved.m 内から MyObserver.h を直接インポートすることで、問題を解決できます。

もちろん、この答えは、あなたの例の再構成の正確さに基づいています。

于 2013-03-29T01:48:23.453 に答える