Category Archives: Objective-C

Kashiwasato.com for iPad

お仕事で佐藤可士和さんのポートフォリオアプリを作成しました。タッチ&スワイプでkashiwasato.comがサクサク見れるアプリに仕上がってます。iPadお持ちの方はゼヒ。
ダウンロードはこちらから。

Art Direction: Yugo Nakamura
Design / Programming: Naoki Nishimura

今回は初のObjective-Cでいろいろ勉強になりました。AppleのCocoaTouchのコンポーネント群は素晴らしいですね。

アプリ完成までのお勉強リソースはこっちにメモ
開発中にハマったとこはこっちにメモ

あとこのアプリ、Appleの審査ガイドライン 2.12項に引っかかりリジェクトされてしまい、リリースまで色々と交渉を続けたものの、結果的に半年ほどペンディングされてしまいました。

2.12
Apps that are not very useful or do not provide any lasting entertainment value may be rejected
(2010年9月公開)

アプリのリジェクトに申立てをするためのApp Review Boardという窓口があり、審査担当者と直接やり取りができます。
この窓口から担当者とやり取りをしていたのですが、この交渉中に2.12項がアップデートされ「are simply web sites bundled as apps,」の一文が追加されてしまいました。

2.12
Apps that are not very useful, are simply web sites bundled as apps, or do not provide any lasting entertainment value may be rejected
(2012年4月改定)

このアプリはkashiwasato.comで使用している画像やjsonを起動時に読み込んでいるので、そのへんの仕組みが、simply web sites bundled as apps(既存のウェブサイトをアプリでラップしただけ)に見えてNGだったようです。
今後は既存のウェブサイトのリソースを使いまわしただけのアプリは難しいのかもしれません。担当者いわく、アプリ内にリソースを持っておき、オフラインでも使用できればよいとも言われましたが実際のところどうなのかわかりません。

知識0からiOSアプリ提出までの学習リソースメモ

初のObjective-C案件で自分(ActionScript 5年生)が参考にしたリソースまとめ。


入門Objective-C 2.0

まずこの本でObjective-Cの基礎を理解。言語に関する書籍なのですごい退屈。「詳解Objective-C 2.0」の方が詳しいけど分厚すぎてXcode起動する前に心が折れたからこっちを先に読むほうが楽。

iOS Developer Library

「入門Objective-C 2.0」に並行してAppleの公式のドキュメントを読み砕いてく。PDFでダウンロードできるのでiPhone/iPadに突っ込んでうんこしながらも読む。iOSの開発に関してはここのドキュメント読むだけで十分ってぐらい充実してる。とりあえず最初はこのへんを読んどく。


Xcode 4 入門 for iOS/Mac OS X

図版多めでサクッと読める。Xcode4の使い方、Instrumentsの使い方がサクッと把握できる。


iOS開発におけるパターンによるオートマティズム

実践的な「書き方」が多数掲載されてて勉強になる。安心の木下さん著作。
ぼんやりとCocoa Touchの使い方が見えかけてきたあたりで、効率のよいCocoa Touchの使い方をこの本で学ぶ。

実践! iPhoneアプリ開発 | コラム | エンタープライズ | マイナビニュース

上記「iOS開発におけるパターンによるオートマティズム」の木下さんによる連載。サンプルコードがためになる。


iPhoneプログラミングUIKit詳解リファレンス

UIKit各クラスの基礎的な使い方が網羅されてる。分厚いからパラ見してどんなクラスがあるか把握しといて、いざ使うときになったら該当箇所を読み込むって使い方がよさげ。


詳解Objective-C 2.0

数少ないObjective-Cの仕様を網羅した本。あとはひたすらこの本でObjective-Cの造詣を深めてゆく。分厚いから腕も辛い。

これぐらいの知識とGoogle力でとりあえず動くものは作れるようになった気がする。
あと開発中にハマったとこはこっちにメモ

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の高さを内容に合わせて変化させる | アクトインディ技術部隊報告書

iOSで行間調整、カーニングするメモ

UILabelの行間、カーニング調整できないクソ仕様に悶絶したので代替手段としてCoreTextを調べてみたメモ。

・もろもろパラメータ設定したNSAttributedStringを用意する。指定できるパラメータはCoreText.framework内CTStringAttributes.hを参照。

・CTFramesetterCreateWithAttributedString(CFAttributedString*)でCTFramesetterRef取得する。

・CoreFoundationとObjective-Cのデータ型はだいたい互換性があるらしく、引数がCF~のとこに、同名のNS~を(CF~)NS~みたいにキャストしてつっこめれる。

・CGPathCreateMutable()でCGMutablePathRef取得する。

・CGPathAddRect(CGMutablePathRef, NULL, self.bounds)で描画範囲を設定。

・取得したCTFramesetterRefとCGMutablePathRefからCTFramesetterCreateFrame(CTFramesetterRef, CFRange, CGPathRef, NULL)を使ってCTFrameRefを作る。

・UIViewのdrawRect:(CGRect)rect内でUIGraphicsGetCurrentContext()使ってCGContextRef取得。

・CTFrameDraw(CTFrameRef, CGContextRef)でテキスト描画。

・UIViewとCoreGraphicsで座標系が違うので、
CGContextTranslateCTM(CGContextRef, 0, self.bounds.size.height);
CGContextScaleCTM(CGContextRef, 1, -1);
で上下反転させておく。

CoreFoundationとかガチのC言語な上、手続きがめんどすぎるのでよっぽどのことがない限りUIWebViewで描画した方がよい。
あとCoreTextの日本語資料少な過ぎで死ぬ。

参考:
Core Text Programming Guide: Introduction
Text Layout With Core Text
CoreText.framework – iPhone Development Wiki

Objective-C を強引に AS3 で例えるメモ

全部雰囲気で理解してるので間違ってる可能性大です。

変数宣言

プリミティブ型
int num → var num:int

クラス型
MyClass *myClass → var myClass:MyClass

※プリミティブ型以外の型は変数宣言で*付ける

ディスプレイオブジェクト的な概念

UIView → DisplayObject
UIResponder → InteractiveObject
addSubView → addChild
CGContextRef → Graphics
UIImage → BitmapData
UIImageView → Bitmap

座標指定
view.center = CGPointMake(100, 200)

view.x = 100;
view.y = 200;

リサイズ
view.size = CGSizeMake(100, 200)

view.width = 100;
view.height = 200;

メソッド

[instance method] → instance.method()
method:は:までがメソッド名

イベントハンドラ

[obj addTarget:self action:@selector(nullEventHandler:) forControlEvents:NullEventNull]

obj.addEventListener(NullEvent.NULL, nullEventHandler)

ヌル

nil → null

タイマー

NSTimer → Timer

文字列

@”This is text” → “This is text”

関数の定義

– (void)func: (NSString)arg1 argument2:(NSString)arg2 argument3:(NSString)arg3
{
}
※argument2とargument3は引数名(ラベル)で省略可。

private function func(arg1:String, arg2:String, arg3:String):void
{
}

関数の呼び出し

[obj func:@”引数1″ argument2:@”引数2″ argument3:@”引数3″];

obj.func(“引数1″, “引数2″, “引数3″);

コンストラクタ呼び出し

[[Class alloc] init] → new Class()

用語

プロトコル → インターフェイス

デリゲート

//インターフェイス(プロトコル)で通知用の関数定義
interface IHoge
{
function onHoge():void;
}

//デリゲートされるクラス
class Hoge implements IHoge
{
public function onHoge():void
{
trace(“called Hoge”);
}
}

/*
イベント(この場合は初期化)が起こったらインターフェイス(プロトコル)に対して通知関数を呼ぶ

デリゲート?
*/
class Main()
{
public Main(hoge:IHoge)
{
hoge.onHoge();
}
}

実行順序

アプリ起動

main()実行

UIApplicationMain()実行

アプリケーションデリゲートオブジェクトを呼び出し
– アプリケーションデリゲートオブジェクト = UIApplicationDelegateプロトコルを採用(継承)したオブジェクト
– didFinishLaunchingWithOptions:

イベントループ
– ユーザーの操作等々
– アプリケーションデリゲートオブジェクト経由で各メソッドを呼び出す

アプリ終了準備 → applicationWillResignActive:

アプリ終了 → applicationDidEnterBackground:

参照:
http://developer.apple.com/jp/devcenter/ios/library/documentation/iPhoneAppProgrammingGuide.pdf