1. ホーム
  2. ios

[解決済み] iOSのカスタムビュークラスを作成し、その複数のコピーを(IBで)インスタンス化するにはどうすればよいですか?

2022-09-18 14:19:17

質問内容

現在、複数のタイマーを持つアプリを作っているのですが、基本的にどれも同じようなものです。

私は、タイマーのすべてのコードとレイアウト/アニメーションを使用するカスタム クラスを作成したいと思います。

私は IB (xcode 4.2) を使用してレイアウトを作成し、タイマーのすべてのコードは現在 viewcontroller クラスにのみあります。

私は、カスタムクラスにすべてをカプセル化し、それをビューコントローラに追加する方法について、私の脳を包むのに苦労しています。

どのように解決するのですか?

概念的にお答えすると、タイマはおそらく UIView のサブクラスで、代わりに NSObject .

IBでタイマーのインスタンスを生成するには、単に UIView をドラッグしてビューコントローラーのビューにドロップし、 そのクラスをタイマーのクラス名に設定します。

を忘れないでください。 #import を追加してください。

編集:IB設計のため(コードのインスタンス化については改訂履歴を参照)

私はstoryboardにはあまり詳しくないのですが、IBでインターフェイスを構築する際に .xib ファイルを使って、IBでインターフェイスを構築することができることは知っています。 .xib ファイルにコピー&ペーストすることもできるはずです。

これをテストするために、新しい空の .xib という名前の新しい空のビューを作成しました。そして、ビューを追加し、それにラベルと2つのボタンを追加しました。Like So:

をサブクラスとする新しい objective-C クラスを作成しました。 UIView MyCustomTimer"と名付けました。私の .xib ファイルの所有者 クラスを マイカスタムタイマー . これで、他のビュー/コントローラと同じように、アクションとアウトレットを自由に接続できるようになりました。その結果 .h ファイルはこのようになります。

@interface MyCustomTimer : UIView
@property (strong, nonatomic) IBOutlet UILabel *displayLabel;
@property (strong, nonatomic) IBOutlet UIButton *startButton;
@property (strong, nonatomic) IBOutlet UIButton *stopButton;
- (IBAction)startButtonPush:(id)sender;
- (IBAction)stopButtonPush:(id)sender;
@end

残るハードルは、この .xib を私の UIView のサブクラスを作成します。を使うと .xib を使うことで、必要なセットアップを劇的に減らすことができます。また、タイマーを読み込むためにストーリーボードを使っているので -(id)initWithCoder: が呼び出される唯一のイニシャライザーであることがわかります。というわけで、実装ファイルはこんな感じです。

#import "MyCustomTimer.h"
@implementation MyCustomTimer
@synthesize displayLabel;
@synthesize startButton;
@synthesize stopButton;
-(id)initWithCoder:(NSCoder *)aDecoder{
    if ((self = [super initWithCoder:aDecoder])){
        [self addSubview:
         [[[NSBundle mainBundle] loadNibNamed:@"MyCustomTimerView" 
                                        owner:self 
                                      options:nil] objectAtIndex:0]];
    }
    return self;
}
- (IBAction)startButtonPush:(id)sender {
    self.displayLabel.backgroundColor = [UIColor greenColor];
}
- (IBAction)stopButtonPush:(id)sender {
    self.displayLabel.backgroundColor = [UIColor redColor];
}
@end

というメソッドは loadNibNamed:owner:options: という名前のメソッドは、まさにその通りのことをします。Nib をロードして、"File's Owner" プロパティを self に設定します。配列の最初のオブジェクトを抽出し、それが Nib のルート ビューになります。このビューをサブビューとして追加すると、画面上に表示されます。

もちろん、これはボタンが押されたときにラベルの背景色を変更するだけですが、この例で十分に理解できるはずです。

コメントによるメモ。

もしあなたが無限再帰の問題を抱えているならば、おそらくこの解決策の微妙なトリックを見逃すことになる、ということは注目に値します。それは、あなたが考えているようなことを行っているわけではありません。ストーリーボードに配置されたビューは見られず、代わりにサブビューとして別のビューがロードされます。読み込まれるビューは、nibで定義されているビューです。nibの中のquot;file's owner"は、その見えないビューです。この未公開ビューは、Objective-Cのクラスであり、nibから読み込んだビューのコントローラーのようなものとして使用することができます。例えば IBAction のメソッドは MyCustomTimer クラスのメソッドは、ビューよりもビューコントローラに期待されるものです。

余談ですが、これによって MVC を壊していると主張する人がいるかもしれませんが、私も多少は同意します。私の観点では、これはより密接にカスタム UITableViewCell に近いもので、これも時にはパートコントローラである必要があります。

この回答は、非常に具体的な解決策を提供するものであったことも特筆すべきです。 同じ意見 のように、ストーリーボードにレイアウトされます。例えば、6つのタイマーをiPadの画面上に一度に表示することは容易に想像がつくでしょう。もし、アプリケーション全体で複数回使用されるビューコントローラのビューを指定するだけなら この質問に対してjyavenardが提供した解決策 があなたにとってより良い解決策であることはほぼ間違いないでしょう。