お?いけるくさい?

iPhoneアプリエンジニアのたまごです。いっちょまえエンジニア目指してちいさな発見や学んだことを覚え書きしていきます!Objective-C/iOS/開発

カスタムボタンの落とし穴

最近ちょっとずつカスタムクラスの作成に慣れてきましたヽ(´ω)ノ

 

はじめは、カスタムクラスって何..こわい..(gkbr)

って思ってたけど、

要は拡張機能(オリジナル機能)をつけたいなあヽ(´ω)ノ」

ってだけなんで、

そんなにわちゃわちゃいちから自分で作成しなくても

ちょろっとのメソッドを書き足すだけで成り立つもんなんだなあと

最近は実感しております。

 

で、今日はUIButtonを継承したカスタムボタンを作ってハマったのでメモ。

構成としては、

ViewController

 ∟カスタムView

  ∟カスタムButton(そいつのimageにアイコン画像をセットする)

てことがやりたかった。

 

カスタムボタン自体はカスタムViewにaddしていたので

今回はViewの中でボタンの呼び出しを行ったけど、

別にViewControllerの中で呼び出すとしてもやり方は一緒ね。

 

◇カスタムボタン(呼び出される側)のメソッド

- (id)initWithFrame:(CGRect)frame

{

    self = [super initWithFrame:frame];

    if (self) {

        //初期化

        _imageStore = [[ImageStorealloc]initWithDelegate:self];

    

        self = [UIButtonbuttonWithType:UIButtonTypeCustom];

    }

    returnself;

}

 

//アイコンセット

-(void)loadIconImage:(NSString*)url

{

    [_imageStore getImage:url];

}

 

#pragma mark -ImageStore Delegate

- (void)imageStoreDidGetNewImage:(ImageStore*)sender url:(NSString*)url

{

    UIImage* imagePre = [sender getImage:url];

//ここでRetina対応の64x64px画像に成形

UIGraphicsBeginImageContextWithOptions(CGSizeMake(64, 64), NO, 0.0);

[imagePre drawInRect:CGRectMake(0, 0, 64, 64)];

UIImage* image = UIGraphicsGetImageFromCurrentImageContext();

UIGraphicsEndImageContext();

    

    [selfsetImage:image forState:UIControlStateNormal];

}

 

はい。これがカスタムボタンに書いた全メソッドです。

ここですでにミスったことに気づいた方はさすがです。

_imageStoreっていうのは非同期でURLから画像を生成してくれるライブラリです。

成功するとdelegateくんがdidGetNewImageメソッドをcallBackしてくれるので、

そこで自分自身のimageに生成したアイコンをセットしています。

 

◇カスタムView(呼び出す側)

-(void)createIcons

{

    //NSLog(@"ロード self.urlsの中身%@",self.urls);

    if (0 <[self.urls count]) {

        for (int i = 0; i < [self.urls count]; i++) {

            IconButton* btn = [[IconButton alloc]initWithFrame:CGRectMake(10+i*74, (self.frame.size.height-64)/2, 64, 64)];

            NSString* url = [self.urls objectAtIndex:i];

            [btn loadIconImage:url];//画像ロードさせる

            btn.tag = i;//タグ付け

            [btn addTarget:selfaction:@selector(selectItem:) forControlEvents:UIControlEventTouchUpInside];

            [self addSubview:btn];

            [btn release];

        }

    }

}

 
でこっちが呼び出し側です。
self.urlsっていう配列には、画像のURLだけがだーっと格納されているので、
for文で回してカスタムボタンを生成すると同時に、
配列のi番目のurlを取り出したものをloadIconImage:に渡してあげます。
するとうまくImageStoreが働いて全てハッピー!\( ^ヮ゜)>
と思ったら....
 
[btn loadIconImage:url]で落ちる......
 
 
なぜだーーー!!!
エラーメッセージを見ると
unrecognize selector send Instance....うんたらかんたら [UIButton loadIconImage:]
みたいな感じだったよーな。
「UIButtonにはloadIconImageなんてメソッドねーよ!」
って落ちてるとのこと。
うー、なぜだ、IconButtonで呼び出しているはずなのに...。
というわけで、IconButtonのinitがちゃんと呼ばれているかを確認するために
breakPointを仕込むと......呼ばれてる。
うおおおおおおおなんでだああ
とそのときに、先輩が発見。
 
「これinitの中で 
  self = [UIButton buttonWithType:UIButtonTypeCustom]; って書いてるけど、
 これでUIButtonになっちゃってるんじゃない?」
 
!!!....それだああああああああああ
 
というわけで、
ふつーにUIButtonを呼び出すときはこうやって呼び出すけど、
カスタムのときはframeでサイズ指定するだけでカスタムボタンになるから
こんなアホな指定はしちゃいけませんよ。ちゃんちゃん。
という今日の学びでした。
↓正しくは これですからね。気をつけてーーっ
 

- (id)initWithFrame:(CGRect)frame

{

    self = [super initWithFrame:frame];

    if (self) {

        //初期化

        _imageStore = [[ImageStore alloc]initWithDelegate:self];

    

        //self = [UIButton buttonWithType:UIButtonTypeCustom];

    }

    return self;

}