0

私のアプリのコードの大部分は、MyViewControllerという「m」ファイルにあります。アプリは、UIWebViewオブジェクトを含むカスタムUIViewを実装します。UIViewとUIWebViewのコードは、CustomUIViewと呼ばれる別の「m」ファイルに保存されます。

デリゲートを使用して、UIWebViewオブジェクトのURLハイパーリンクのクリックをオーバーライドすることができました。ただし、これらのクリックで、メインのアプリコードに保存されているメソッドを起動させたいと思います。このメソッドは「popupView」と呼ばれ、「inputArgument」という単一の引数を取ります。inputArgumentは、ユーザーがクリックしたURLのテキストです。実際、このメソッドは、カスタムUIViewを起動させるメソッドとまったく同じです。

とにかく、私がやりたいのは、オーバーライドされたURLクリックによってpopupViewメソッドが起動し、クリックされたものの上に別のUIViewが開くようにすることです。

問題は、URLクリックが検出された「m」ファイルは、MyViewController「m」ファイルに含まれているため、「popupView」メソッドを認識できないことです。別の「m」ファイルからpopupViewメソッドを呼び出すにはどうすればよいですか?

4

2 に答える 2

2

直接

  1. MyViewControllerのメソッドを宣言-popupView:MyViewController.hます。
  2. #import MyViewController.hCustomUIView.m
  3. CustomUIViewの [1] インスタンスへの参照を与えます。MyViewControllerたとえば、@property宣言された in を使用しCustomUIView.hます。

の場合(1)、(の) は次のようになります。@interfaceMyViewControllerMyViewController.h

@interface MyViewController : UIViewController
{
    //....
}
- (void)popupView:(NSString *)urlText;
//....
@end

の場合(2)UIViewController.m上部のどこかに次のものが必要です

#import "CustomUIView.h"
#import "MyViewController.h"

の場合(3)@interfaceinCustomUIView.hは次のようになります

@interface CustomUIView : UIView
{
    //....
}
@property (nonatomic, weak) MyViewController *viewController;
@end

CustomUIViewこのプロパティは、所有者のインスタンスが作成された後、しばらくしてから設定する必要がありますMyViewController。にある場合CustomUIViewは、次のようにプロパティの宣言にMyViewController.xibキーワードを追加することで、このプロパティを設定できますIBOutlet

@property (nonatomic, weak) IBOutlet MyViewController *viewController;

で、このプロパティを「ファイルの所有者」にポイントしXIBます。代わりにCustomUIViewプログラムで作成する場合は、初期化後すぐにこのプロパティを設定できます。

デリゲート

ただし、これはベスト プラクティスとは言えません。デリゲート パターンを使用する方がはるかに優れています。これを行うには、次のことが必要です。

  1. デリゲートプロトコルを定義します。
  2. に「デリゲート」@propertyを追加しCustomUIViewます。
  3. 適切なタイミングでデリゲート オブジェクトのデリゲート メソッドを呼び出します。
  4. でプロトコルを実装しますMyViewController
  5. @propertyインスタンスがCustomUIView所有するインスタンスの「デリゲート」をインスタンスに設定MyViewControllerMyViewControllerます。

デリゲート プロトコルを のような想像上のものと呼びましょうCustomUIViewDelegate。の場合、次のよう(1)に の先頭で宣言しCustomUIView.hます。

@class CustomUIView;

@protocol CustomUIViewDelegate <NSObject>
- (void)customUIView:(CustomUIView *)customView didSelectURLText:(NSString *)urlText;
@end

コンパイラがプロトコル メソッドの最初の引数の型を理解できるように、クラスを前方宣言する必要があることに注意してください。CustomUIViewcustomUIView:didSelectURLText:

については、上記と非常によく似(2)た処理を行います。(3)CustomUIView @interface

@interface CustomUIView : UIView
{
    //....
}
@property (nonatomic, weak) id<CustomUIViewDelegate> *delegate;
@end

繰り返しになりますが、Interface Builder でこのプロパティを設定する場合は、IBOutletキーワードを使用して IB に通知する必要があります。

@property (nonatomic, weak) IBOutlet id<CustomUIViewDelegate> *delegate;

(3) については、適切なタイミングでcustomUIView:didSelectURLText:デリゲート オブジェクトのデリゲート メソッドを呼び出す必要があります。self.delegate

あなたの質問で、あなたは書いた

デリゲートを使用して、UIWebView オブジェクトの URL ハイパーリンクのクリックをオーバーライドすることができました。

CustomUIViewそれで、インスタンスメソッドがあるとしましょう

- (void)didSelectURL:(NSURL *)url
{
    //....
}

ユーザーが UIWebView でリンクを選択したときに呼び出すものです。CustomUIViewデリゲートには、次のことを通知する必要があります。

- (void)didSelectURL:(NSURL *)url
{
    //...
    if ([self.delegate respondsToSelector:@selector(customUIView:didSelectURLText:)]) {
    {
        [self.delegate customUIView:self didSelectURLText:url.absoluteString];
    }
}

CustomUIViewインスタンスのデリゲート オブジェクトが対象のセレクター ( customUIView:didSelectURLText:) を呼び出して実装しているかどうかを最初に確認することに注意してくださいrespondsToSelector:

の場合、最初にの宣言を追加し、シンボルを使用するファイルに必ず追加する(4)必要があります。は次のようになります。<CustomUIViewDelegate>MyViewController@interface#import CustomUIView.hCustomUIViewDelegateMyViewController@interface

#import "CustomUIView.h"

@interface MyViewController : UIViewController <CustomUIViewDelegate>
{
    //....
}
//....
@end

さらに重要なことに、の;にプロトコルを実装する必要があります。これまでのところ、がそれを採用していると宣言しただけです。CustomUIViewDelegateMyViewController@implementationMyViewController

これを行うには、プロトコルが 1 つのメソッドのみで構成されているため、独自の実装を追加するだけで済みます-customUIView:didSelectURLText:MyViewControllerは次の@implementationようになります。

#import "MyViewController.h"

@implementation MyViewController

//....

- (void)popupView:(NSString *)urlText
{
    //....
}

#pragma mark - CustomUIViewDelegate

- (void)customUIView:(CustomUIView *)customView didSelectURLText:(NSString *)urlText
{
    [self popupView:urlText];
}

//....

@end

最後に、インスタンスが所有するインスタンスのプロパティ(5)を設定する必要があります。とそのインスタンスとの関係について、これを決定的に行う方法を説明するのに十分な知識はありませんが、例を示します。したがって、の実装は次のようになります。delegateCustomUIViewMyViewControllerMyViewControllerCustomUIView-[MyViewController loadView]CustomUIViewMyViewController-loadView

- (void)loadView
{
    [super loadView];
    
    //....
    
    CustomUIView *customView = //....        
    //....
    [self.view addSubview:customView];
    
    //....
    
}

この時点で行うことdelegate @propertyは、ローカル変数のcustomViewをに設定することだけselfです。

customView.delegate = self;

編集CustomUIView:との関係に関する新しい情報に照らして (5) を更新しましたMyViewController

CustomUIViewあなたのコメントでは、あなたのサブビューとしてあなたが追加されたと書いていますcvc.viewwhere cvcis an instance of CustomUIViewControllerin CustomUIView's method -[CustomUIView show]customView.delegate = self;このため、書き込みは書き込みと同じであることに注意してself.delegate = selfください。これは明らかにあなたがやりたいことではありません。

CustomUIViewdelegateプロパティを のインスタンスに設定しますMyViewController。したがって、メソッド-[CustomUIView show]は次のようになります

- (void)show
{
    //....
    [cvc.view addSubview:self];

    self.delegate = mvc;
}

mvcのインスタンスはどこにありますかMyViewController

于 2012-10-31T00:35:35.490 に答える
0

さて、あなたは を書いているのでCustomUIView、コンストラクタのようなものを実装initWithPopupDelegate:(MyViewController *)delegateし、インスタンスへの参照をMyViewControllerインスタンス変数に保持してから、そのメソッドを呼び出してみませんか。

@class MyViewController;(先頭CustomUIView.hに と#import "MyViewController.h" を追加してCustomUIView.m、コンパイラが使用しているクラスを認識できるようにします。)

または、インスタンスが 1 つしかない場合は、たとえばMyViewControllerのクラス メソッドを定義して、1 つのインスタンスへの参照を返すようにすることができます (これをクラス変数に格納し、インスタンスを作成するときに最初に設定します。 「シングルトンパターン」を参照してください)。ただし、コードの詳細を知らなくても、最初のソリューション (デリゲート) をよりシンプルで柔軟なものとしてお勧めします。MyViewController+ (MyViewController *)instance

于 2012-10-31T00:35:15.333 に答える