Monthly Archives: December 2011

iOS開発ハマりどころメモ

アプリ開発中にハマったポイントをメモ。下に行くほど古いので初歩的な内容。

ScrollViewのスクロール強制停止
スクロール中のUITableViewを強制的に停止させる時はcontentOffsetに現在地の座標を突っ込む。
[_tableView setContentOffset:_tableView.contentOffset animated:NO];
iphone – Programmatically force a UIScrollView to stop scrolling, for sharing a table view with multiple data sources – Stack Overflow

NSMutableArrayのコピー
[NSMutableArray copy]で返ってくるのはNSArray、NSMutableArrayとしてコピーがしたい時は[NSMutableArray mutableCopy]を使う。
Basilの息子| 「__NSArrayM」と「__NSArrayI」

バックグラウンドでアプリを終了させる
ホームボタンが押されて、アプリがバックグラウンドに送られたときにアプリを完全に終了させる方法。
projectName-Info.plistに「Application does not run in background」という項目を追加してValueをYESにする。
UIApplicationExitsOnSuspend=YES を Info.plist に設定する – Debian GNU/Linux 3.1 on PowerMac G4

イベント一括停止
[[UIApplication sharedApplication] beginIgnoringInteractionEvents]でアプリケーション内のすべてのタッチイベントを停止する。
[[UIApplication sharedApplication] endIgnoringInteractionEvents]でタッチイベントの受信再開。
iOSイベント処理ガイド

プロパティセマンティクス
プロパティの宣言につける型みたいなやつ(セマンティクス)。

  • readwrite: 読み書き可能。デフォルト。
  • readonly: 読み取り専用。
  • strong: 強い参照。
  • weak: 弱い参照。参照先が解放されると自動的にnilが入る。iOS5から。
  • assign: 単純代入。デフォルト。
  • copy: copyを使って参照を保持する。代入前に自動でreleaseを送る。
  • retain: retainを使って参照を保持する。代入前に自動でreleaseを送る。
  • nonatomic: スレッドセーフでない。

Objective-Cプログラミング言語

実行時間計測
ある瞬間からある瞬間の時間を計測する方法。終了タイミングのNSDateオブジェクトのtimeIntervalSinceDate:に開始タイミングのNSDateオブジェクトを渡す。
■[iPhone][Objective-C] 時間を計測する方法

iOS デフォルトサウンド一覧
AudioServicesPlaySystemSoundで鳴らせるプリインストール済みのサウンドファイル一覧。
AudioServices – iPhone Development Wiki

UIViewのアニメーションを停止
UIViewのアニメーションをキャンセルするには、アニメーションしているview.layerにremoveAllAnimationsを送る。
[btn.layer removeAllAnimations];

デフォルト遷移アニメーションの実行時間を指定する
〜:animatedなアニメーションの実行時間はUIViewのanimateWithDuration:animations:で指定できる。その際animetedはNOにしないと反映されないから注意。
SimpleBoxes | ブロックを使ったアニメーション処理 (iPhone/iPad, Objective-C 2.0)

NSArrayのソート
NSArray、NSMutableArrayのソートはsortedArrayUsingDescriptors:を使うとだいぶ楽。
蒼い惑星: NSArrayのソート方法について

CGRectIsEmpty
CGRectが{0,0,0,0}もしくはNULLかどうかを判定する時はCGRectIsEmpty()。
CGRectのメソッド色々メモ 比較編(iOS SDK)|ふぁのれこそは半角カタカナで

Xcodeの補完が効かなくなったら
Xcodeのシンタックスハイライトが消えたり、補完が効かなくなったら、[~/Library/Developer/Xcode/DerivedData]にある該当プロジェクトのキャッシュを削除してXcodeを再起動する。
autocomplete – Xcode 4: Auto-complete & Jump to Definition broken in my Xcode 3 Project – Stack Overflow

UILabelのタッチイベントを取得する
UILabelはデフォルトだとタッチイベントがオフになってるのでuserInteractionEnabledをYESにする。
UIButton – 福井高専IT研究会OfficialWiki

デバイス回転前に回転後のサイズを取得する
デバイス回転処理前のタイミングで回転後のサイズを取得したい時はUIViewControllerのwillAnimateRotationToInterfaceOrientation:duration:内でself.viewのframe、boundsを参照する。
Bynomial Code » Handling rotations in UIViewController

透過PNGは重い
pngも含めた透過性のviewはスクロール負荷が高い。
[iOS] TableView スクロールパフォーマンスの改善 – iOS 開発ブログ Natsu’s note

viewの階層構造を出力
UIViewのrecursiveDescriptionメソッドでviewの階層構造を出力できる。
ビュー (UIView) の階層構造をダンプする非公開の便利メソッド – 24/7 twenty-four seven

NSTimerはdeallocで解放しない
NSTimerを解放するときのinvalidateはdeallocではなくviewWillDisappear:あたりで行う。
NSTimerのscheduledTimerWithTimeInterval:target:selector:userInfo:repeats:はtarget:で渡されたオブジェクトをretainするからNSTimerをinvalidateするまでtarget:に渡されたオブジェクトは解放されない。よってdealloc外でinvalidateを呼ばないとdeallocが呼ばれなくなってしまうため。
A-Liaison BLOG: NSTimerは基本的にretainせずassignでよい

CALayerの解放
CALayerの初期化は[CALayer layer]だけど解放時はlayer.contents = nilして[layer release]。
CALayerのメモリ解放(メモ)|UA LABO|ユナイティア株式会社

ファイルを右ペインに開く
Xcode4にてOption押しながらナビゲーター内のファイルを選択するとアシスタントエディタにファイルの内容を表示できる。

UIViewControllerのフロー・初期化

  1. alloc
    メモリの確保
  2. init、init〜
    データ類の初期化
  3. loadView
    viewの初期化
  4. viewDidLoad
    viewのレイアウト、データの反映
  5. viewWillAppear:(viewが画面に描画される場合)
    viewが画面に描画される直前の処理
  6. viewDidAppear:(viewが画面に描画される場合)
    viewが画面に描画された直後の処理

・メモリ不足

  1. didReceiveMemoryWarning
    不要なデータの解放
  2. viewDidUnload
    viewの解放(変数にnilを代入してアクセスを防ぐ)

デバイス回転時のUIViewController内のフロー・パターン1

  1. デバイスが回転
  2. shouldAutorotateToInterfaceOrientation:
    サポートする角度の確認
  3. willRotateToInterfaceOrientation:duration:
    view回転直前の処理
  4. viewの回転
  5. didRotateFromInterfaceOrientation:
    view回転直後の処理

・パターン2

  1. デバイスが回転
  2. shouldAutorotateToInterfaceOrientation:
    サポートする角度の確認
  3. willRotateToInterfaceOrientation:duration:
    view回転直前の処理
  4. willAnimateFirstHalfOfRotationToInterfaceOrientation:duration:
    中間角度直前の処理
  5. 中間の角度
  6. didAnimateFirstHalfOfRotationToInterfaceOrientation:
    中間角度直後の処理
  7. willAnimateSecondHalfOfRotationToInterfaceOrientation:duration:
    回転済み直前の処理
  8. viewの回転
  9. didRotateFromInterfaceOrientation:
    回転直後の処理

iOS View Controller プログラミングガイド

いろんなブレイクの種類
設定したブレイクポイントを右クリックして開いたメニューの[Edit Breakpoint]からブレイクさせる条件を設定できたり、ブレイクさせずにNSLogしたり、音を鳴らしたり、AppleScriptを実行したりできる。
Xcode4でNSLogを過去にする | みるくCocoa

実行前コードチェック
static analyzerで実行前に潜在的なメモリリーク等を検出してくれる。
Cocoaの日々: Xcode – Build And Analyze
Cocoaの日々: Xcode – Build And Analyze 〜 問題の例

NSZombie
[Product]→[Edit Scheme…]→[Run {プロジェクト名}]→[Diagnostics]→[Memory Management]→[Enable Zombie Objects]にチェックを入れると実行時エラーが発生したその場で停止してその場所でエラーを吐いてくれるようになる。
EZ-NET: Xcode4 のデバッグ環境を整える

リファクタリングショートカット
control+command+Eで[Edit All in Scope]が実行できる

公式ドキュメントのオフラインキャッシュ
Documentをオンラインで見ると遅いからローカルに保存しておく。
[xcode]→[Preferences…]→[Downloads]→[Documentation]→[Check and Install Now]

Xcodeのカラーの変更
xcode4でカラーテーマの変更は[xcode]→[Preferences…]→[Fonts & Colors]→[Theme]

Xcode4のRefactor機能
・Renameで変数名の一括変更
・Extractで一部のコードをメソッドに変換
・Create Superclassでスーパークラスの作成→継承
・Move Upで変数、メソッドをスーパークラスに移動
・Move Downでサブクラスに移動
・Encapsulateで変数をプロパティー化
Xcode 4 移行ガイド:テキストの置換とリファクタリング

UIWebViewの解放
UIWebViewをdeallocする時はwebView.delegateにnilをつっこんどく。
アプリが落ちないUIWebViewの使い方: iPhoneアプリ開発備忘録

擬似グローバル
グローバルっぽいところにいろんなもの突っ込んで受け渡しする初心者実装のススメ。
iOSゆとりプログラミングのススメ – 仕事人の開発日誌

戻るボタンを消す
ナビゲーションバーにデフォルトで表示される戻るボタンを非表示にする方法。UINavigationControllerにpushするcontroller内のviewDidLoadで[self.navigationItem setHidesBackButton:YES animated:NO]する。
チーズくんの備忘録 [iOS]戻るボタンを消す方法

オリジナルフォントを使う
プリインストールされていないフォントを使う方法。プロジェクトにttf、otfを読みこんでxxx-Info.plistに「Fonts provided by application」という項目を追加して各ファイル名をStringとして加える。あとはUIFontにフォント名をしてする。フォント名の取得はplistに追加したあと下記のコードを実行してインストール済みのフォントを出力して確認する。

NSEnumerator *e = [[UIFont familyNames] objectEnumerator];
NSString *font;
while(font = [e nextObject])
{
    NSLog(@"%@: %@", font, [UIFont fontNamesForFamilyName:font]);
}

そうだ、プログラミングしよう  フォントを組み込む方法

デフォルトUIのグラデーションを消す
UINavigationBarのグラデーションを消したい時はカテゴリからdrawRect:を上書きしてCGContextSetFillColorで塗りつぶす。iOS5以降の場合は[navigationBar setBackgroundImage:]で背景に無地の画像を敷き詰める。

UIImage* bgImage = [UIImage imageNamed: @"black.png"];
[bgImage drawInRect:CGRectMake(0, 0, self.view.frame.size.width, self.view.frame.size.height)];
[self.navigationBar setBackgroundImage:bgImage forBarMetrics:UIBarMetricsDefault];

iphone – Remove Gradient on UINavigationBar – Stack Overflow

デフォルトのタイトルフォントを変更する
UINavigationBarのタイトルのフォント等のスタイルを変えたいときは、好きなUILabelを作ってnavigationItem.titleViewにつっこむ。iOS5以降の場合は[navigationBar setTitleTextAttributes:]で設定できる。
uinavigationbar – iPhone Navigation Bar Title text color – Stack Overflow

scrollViewDidScroll:の呼ばれるタイミング
UIScrollViewのscrollViewDidScroll:はcontentSize、contentOffsetが変化した時も呼ばれる。
Cocoaの日々: 簡易スライドビューア [17] モードの切り替え

NSTimerの解放
NSTimerにscheduledTimerWithTimeInterval:のtargetにselfを渡すと、selfがretainされる。NSTimerのinvalidateを呼ぶとreleaseしてくれる。
NSTimerインスタンスは、生成元viewControllerを保持するのは分かっていたのに、
それではまった。

A-Liaison BLOG: NSTimerは基本的にretainせずassignでよい

数値型と文字型のキャスト
NSStringからintへは[@”123″ intValue]。
intからNSStringへは[NSString stringWithFormat:@”%i”, 123]。
Objective-Cのキャスト(数値⇔文字): iphoneアプリ開発の虎の巻ブログ

BOOLの出力
BOOLは内部的にはint型なのでNSLogで出力するときはintにキャストして判定
NSLog(@”%i”, (int)b);
Objective-Cでのデバック NSLogについて – k2ダイアリー

NSArrayとNSMutableArrayのコピーの違い
copyメソッドを使った時、NSArrayは浅いコピー(shallow copy)、NSMutableArrayは深いコピー(deep copy)が実行される。要はNSArrayは参照を返して、NSMutableArrayは完全にコピーされた実オブジェクトが返される。
iPhoneアプリ開発時のメモリ管理で気をつけること – A Day In The Life

イニシャライザの種類による解放の仕方の違い
alloc、alloc+init〜、copy〜以外のメソッドで生成したオブジェクトをreleaseすると潜在的に実行されてるautoreleaseが走った瞬間に落ちる。
UIButtonはrelease不要 – 全力で気まぐれ

非同期通信ライブラリ
jsonとかxml、画像なんかを読み込んでblocksで非同期処理が書けるライブラリ。
AFNetworking/AFNetworking – GitHub
Cocoaの日々: [Info] AFNetworking

細かいレイアウトはUIWebViewを使う
処理速度求めないシチュエーションならUIWebViewで極力回避。
UIWebViewでつくるUI – yidevで発表してきました | DOTAPON Blog

Blocks
^から始まる関数はblocksというクロージャ、jsでいうとこの無名関数。
C/Objective-C + Blocks でクロージャ – TrashSUITE
Blocks Programming Topics: Getting Started with Blocks

releaseの仕方
中身がnilのオブジェクトにメッセージ送ってもEXC_BAD_ACCESSにならないので、releaseしたらすぐにnil突っ込んどく。

[view release], view = nil;

テキストの行の高さを取得する
NSStirngのsizeWithFont:forWidth:lineBreakMode:は一行の高さを取得、sizeWithFont:constrainedToSize:lineBreakMode:が複数行の高さを取得。
constrainedToSize:にheightをおっきめに設定したCGRectを突っ込む。
UITableViewCellの高さを内容に合わせて変化させる | アクトインディ技術部隊報告書

CIDから対応する文字を取得する

わけあってCIDをもとに対応する文字を取得したい。
ざっと調べてみたら、CIDと文字が対になった一覧表はこのへんにあるんだけどプログラムからは使いにくい。

プログラムから使いやすそうな資料を探してみたところ、どうもAcrobat内部ではCIDをUnicodeに変換するようなことをしてるらしいことがわかった。その変換に関する資料がこれ

すかさずこの資料の後半のMapping Fileを拝借。
CIDを投げたらCID→Unicode→String.fromCharCode()で文字を取得ってクラスを作ったんだけど、どうも取得したUnicodeが期待した文字に変換できてない。

この「Unicode」はString.fromCharCodeで変換できる「Unicode」じゃないのかなぁ?

うーん…

と思ったら、FontForgeで使ってるcidmapっていうCIDのマッピングファイルに「Adobe-Japan1-6.cidmap」ってのがあった。これをコンバートして使ってみたらうまく変換できた。ワーイ。
どうも上記のデータはAdobe-Japan2のマッピングデータらしい。なるほろ。

package
{
  
  public class CharCodeUtil 
  {
    static private var list:Array;
    
    public function CharCodeUtil() 
    {
      
    }
    
    static public function getCharFromCID(cid:uint):String
    {
      var char:String = "";
      
      init();
      
      for each (var obj:Object in list) 
      {
        if (cid == uint(obj.c[0]))
        {
          char = String.fromCharCode(uint(obj.u));
          break;
        }
      }
      
      return char;
    }
    
    static private function init():void
    {
      if (list) return;
      
      list = [
        //ここに.cidmapをArray化したデータを
      ];
    }
  }
}