お?いけるくさい?

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

タップ認識

1、「閉じる」ボタンを置いたUIViewがあります。

2、このViewを「表示」ボタンを置いたViewControllerがあります。

3、UIViewをViewControllerにaddして、setHidden:YESにしておきます。

4、「表示」ボタンを押すとViewをsetHidden:NOにします。

5、表示されたViewにある「閉じる」ボタンを押すと、setHidden:YESにして隠します。

  ボタン以外のところに触れてもsetHidden:YESにしたいです。

6、というわけでUIGestureRecognizerをUIviewに追加します。これでタップイベントが拾えます。

7、すると、タップイベントは拾えるようになったのですが、ボタンが押せなくなってしまいました...orz

 

こんなときの解決法は以下。

--------------------------------------------------------------------------------

UIGestureRecognizerをUIViewに組みこむと、ほかのタッチイベントが無効になります。

それを避けるには、UIGestureRecognizerのプロパティ「cancelsTouchesInView」をNOにします。

--------------------------------------------------------------------------------

 

今回はGestureRecognizerをxibで付加してみたので、

その場合、xib画面でGestureRecognizerを選択して、

GestureRecognizerの設定(画面右側のやつです)の

「Events: Canceled in View」のチェックを外すと

このプロパティ指定ができます。

 

 ※例えばこのViewの下にScrollViewとかはさんじゃうとダメぽ(ω・`))キョロ(( ´・ω)

 Scrollviewはタッチイベントを奪ってしまうので..

 このへんはまだまだ勉強が必要!

いろんな学び①〜数字まわり編!〜

最近いろいろなことを知ることがあったので

まとめれるうちにまとめとかないと忘れちゃいそうなのでメモ!

-------------------------------------------------------------------------------------

◎NSNumber型のメリット

今回CoreDataを使ったプログラムを作っていて

managedObjectに使うことになりました。

でもNSNumber型って扱いにくくて嫌いだったので、

なんでもかんでもNSString型でいーや、どーせJSONでやりとりするし!

て思っていたのです。

が、このNSNumber型、メリットもあるらしい。

 

1、コンパクトサイズ

なにやら、ローカルに保存するときに、

String型よりもInteger32(32bit?)であるNSNumberで保存すると

容量がちっさくて済むとのこと。

 

2、数字の役割もちゃんとある

NSString型で足し算ってできないですよね。

(やるとしたら一回intValueして〜とか)

これがNSNumber型だと出来ちゃうとかいう噂。

※あくまでも私はまだ使ったことない。

-------------------------------------------------------------------------------------

 ◎Let's変換

【NSString→NSNumber】

1、まずはint型に変換しましょう(忘れがち)

、そのintをNSNumberに変換するだけ あら簡単!

 

(例)NSString* str = @"123";

NSNumber* number = [NSNumber numberWithInt: [str intValue]];

 

とかでOKね。

これをさらに簡略化できるそうな!!

 

NSNumber* number = @( [str intValue] ); ←これ @( )!!

 

では逆はというと。

【NSNumber→NSString】

 

NSString* str = [@(123) stringValue];

 

これでできるそうな。

(何も知らずこれだけ見たらなんじゃこれって感じの世界やなーと改めて思ったわ。)

-------------------------------------------------------------------------------------

まだまだメモりたいことたくさん!では!

再びiTunesSearchAPIで、AppStoreからアプリのscreenshotを取得する!!

前回のアプリではiTunesから楽曲情報を取得してたのですが、

このAPIのベースは先輩が作ってくれたものだったので、

データを取りに行く肝心な部分はノータッチでした。\( ^ヮ゜)>

 

で、今回のアプリでも

AppStoreからアプリの情報を取りに行って、

スクリーンショットの画像を表示させたい!

というマストな山が!

 

まずはGoogle先生に聞いてみました。

スクリーンショット AppStore 取得 JSON」

なんか登録の方法やら指定のサイズやらは出てくるけど

取得の方法がヒットせず。

英語でも「get screenshot appstore how(howとか必死感うける)」とか入れても

同じような結果..。

むむむ。

 

前回のアプリでは、iTunesから楽曲情報を取得する際に、

iTunes RSS(ランキング表示)

iTunes Search API(楽曲検索)

という2つのデータベースを利用していたのですね。

で、とりあえずiTunes RSShttp://itunes.apple.com/jp/rss/generator/

で条件指定して検索してみたものの、

JSON叩いて中身を見ても"screenshot"らしき値が無いのですよ(ω・`)

iconの画像らしきものはあるのに。

 

で、サーバ側の先輩に聞いてみると、

APIはみた?」と言われ、

公式サイト(http://bit.ly/bGaJt4)見ても意味わからんよね、あれ

ってことでけっこう流し読みしかしてなかったんやけど、←

よーく読むと、下のほうに

 

Search Examples

Lookup Examples

 

ていうのがありますね?

これ結構ポイントだったようで、どうやら検索の方法は2種類あるらしい。

http://www.wakatta-blog.com/itune_api.html[参考]

つまり、単語で検索するかidで検索するかってことみたい。

idがわかっている場合はlookup方式で検索すると

早くて情報量もいっぺんにとれて便利みたいです!

 

というわけで道はなんとなく開けた。

つまり前回の楽曲検索ではSearch方式で検索してたけど、

今回のやつではLookup方式を使ったほうが良さげだな。

(しかもLookup方式のほうが簡単そうだしよかった)

さてさてLookup Exampleの中に

 

●Look up Yelp Software application by iTunes ID:

https://itunes.apple.com/lookup?id=284910350

 

ていう項目があって、これを叩くとこのアプリにまつわる情報がだーっと見れます。

ほほー、つまりこの284910350っていうのがアプリidなわけだな。

ていうことで、自社でリリースしてるアプリidをiTunesConnectから検索して、

そのidをid=のあとに入れて叩くと...

 

検索結果:0   ...?

 

えーーーーーーー?(°□°)なんで?

iTunes上にはあるのに。

で他のアプリidも入れてみたところ、

出るやつと出ないやつがある。

登録した順番(古いやつは出ない)とかか?って思ったけど

そんなんやったらそもそもおかしいし(笑)、

再びGoogle先生にきいてみたら、

こちらhttp://www.antun.net/tips/api/itunes.htmlにありました。

真ん中あたり、

 

公式ドキュメントには明示されていませんが、lookup は search と 同じ引数指定ができるようで、逆に言えば指定をしないと 米国版の情報を取りに行ってしまいます。 例えば、太鼓の達人 の情報を取ろうとして、 http://itunes.apple.com/lookup?id=366956158 と指定しても国内でしか提供されていないこのアプリの情報は取れません。 そのため、 http://itunes.apple.com/lookup?country=JP&id=366956158 と引数 country を指定すれば 情報が取れるようになります。

 

なるほど!

というわけで、「ありません」って言われちゃったアプリに関しては、

countryを指定したらとれるようになるんですね。

 

これでスクショがゲットできるはず!

さーやってみよー!

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

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

 

はじめは、カスタムクラスって何..こわい..(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;

}

NSLogを簡単に消しましょ!(マクロ定義)

.pch ファイルに以下のマクロを定義します。

 

#if DEBUG

#if !defined(NSLog)

#define NSLog( m, args... ) NSLog( m, ##args )

#endif

#else

#if !defined(NSLog)

#define NSLog( m, args... )

#endif

#endif

 

 

 

ログを出したくないときは

Build Settings

 > PROJECT

  >  Apple LLVM compiler 4.2 -Preprocessing

   > Preprocessor Macros

の値を、DEBUG=0 にします。

f:id:simamikiii:20130611164706p:plain

これでリリース版のものはデフォルトで0にしておくと

ログを消せて安心\(^o^)/

 

 ***

 

上のやつはちなみに

#ifdef ではなくて

#ifを使っているけど、

ifdef文は開発時に使うとかなり便利!

「テスト中だけ仮でこの値入れておきたいなー」とか

「テスト中だけこのメソッドよびたいなー」とか

そういうときに

 

#ifdef DEBUG(=デバッグ版だったら)

 ほにゃらら

#endif

 

と書くと、DEBUG版だけそこを通ってくれます。

逆に

本番では絶対こっち通ってほしいなーとかっていうときは

 

#ifndef DEBUG(=デバッグ版じゃなければ)

 ほにゃらら

#endif

 

とかって使ったりします。

でも基本はリリース版を前提に、

#ifdef DEBUG で使うことの方が多い。

 

 

 

libxml2をXcodeに組み込むとき

BuildPhase から

libxml2.dylibを追加したにも関わらず、エラーが消えない!

というときは

 

BuileSetting > Search Path > Header Search Pathに 

 

${SDKROOT}/usr/include/libxml2

 

を書かないとエラーが消えませんのでご注意。

NavigationBarの戻るボタン

●ボタン自体表示させたくないとき(表示させたくないViewController内で

    [self.navigationItem setHidesBackButton:YES];

 

●ボタンの 中の文字を変更させたいとき(変更したい1こ前のViewontroller内で

    UIBarButtonItem *backItem = [[UIBarButtonItemallocinit];

    backItem.title = @"戻る";

    self.navigationItem.backButtonItem = backItem;

    [backItem release];

    

    UIViewController *vc = [[UIViewControllerallocinit];

    [self.navigationControllerpushViewController:vc animated:YES];

    [vc release];

 
メモ!