× [PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。 |
シャッター音とか、着信音とかを鳴らす方法。
AudioToolBoxライブラリを追加。
プログラムの参考 鳴らせる音の一覧 ちなみにバイブも鳴らせる
|
iOSで、画像(UIImage)を切り取る方法。
参考 そのまま持ってきたもの
実に簡単。 画像の解像度も考慮してくれているので、 元の(scaleしない)イメージサイズを基準にして、切り取りたい範囲のRectを第2引数に渡せば良い。 Rectは左上が原点。 |
testflightが使えなくなり、iTunesConnectから使用するように変わった。
使い方のイメージとしては、「サブミット前の確認」。 まず、iTunesConnectに行き、最新のAppleの条件をAgreeする必要がある。 これをしなくても先のページに進めるが、アプリを登録するボタン(ヘッダの「+」ボタン)を押しても何も出ない、という妙なところで止められてしまう(不具合に見える。こんなところでも分からないと詰まってしまうようなところ) Agreeしたら、iTunesConnectにアプリを登録する。 DeveloperCenterでDistribution用のProvisioning Profileを作っておく。 このとき、AdHoc用ではなく、Distribution用を作ることに注意。 AdHoc用でもこの先の手順でサブミットできるし、testflightで配布もできるのだが、testflightからインストールできるのが、Provisioning Profileに登録されているデバイスだけに限定されてしまうので不便なだけ。 で、Distribution用のProvisioning ProfileでアプリをXcodeでアーカイブする。 できたらSubmit。 少し待つと、iTunesConnectにアプリが載る。 ここで「プレリリース」をクリック。 内部テスターの欄に、testflightで配布したいメンバーのappleIDを登録する。 (開発メンバーは基本的に内部テスター。外部テスターというのもあるが、これは実際の顧客など外部の人に使ってもらうことを想定しており、外部テスターに配布するためにはAppleの審査を通した後配布するという手順を踏むことになるようだ) で、「TestFlightベータ版テスト」のスイッチをONにし、 招待メールを送信。 これで、内部テスターのappleIDのアドレスにメールが届く。 iPhone、iPadなどでそのメールのリンクを踏むと、testflightのアプリに飛び、件のアプリがインストールできるページになる。 晴れてインストールできるというわけ。 たまにメールが飛ばないことがあるので、「TestFlightベータ版テスト」をOFF→ONにしたらメールが行ったということがあった。 また、上げ直す際は必ずビルド番号を上げておくこと。 あくまでサブミットへの手順の一部なので、ビルド番号をあげておかないと、XcodeからiTunesConnectへのアップロードができない。 再度アーカイブし直しという面倒なことになるので注意。 バージョンはあげなくていい。 というか、上げるとストアの情報など再設定が必要になったりtestflight的にも新しいもの扱いに鳴って再度招待メールを飛ばす必要があったりと面倒。 本当にアプリとしてバージョンをあげるときだけにとどめよう。 |
iOSでYouTubeの動画を再生するときの方法。
画面でボタンをクリック→全画面で動画再生→完了ボタンを押したら元の画面に戻る という流れにしたい。 WebViewを使うのが早い、という記事が多いが、WebViewだと完了ボタンを押したときに画面を閉じるということができない。 WebViewはhtmlを表示しているだけなので、動画コンテンツを再生しているかどうかは感知できない。だから完了ボタンを押したときに、明示的にWebViewを閉じる命令を出す必要があるが、そもそも完了ボタンを押したことを知ることができない。 そこで、MPMoviePlayerViewControllerを使う。 モーダルビューコントローラを表示し、そこで動画(URLで指定)を再生できる。完了したらモーダルは閉じる。これだ! ただし注意。YouTubeのURLそのままだとiOSで再生できない。 再生可能な形式のURLを取得してくる非公式ライブラリがあるのでそれを使う HCYoutubeParser 以下のようになる。
その他、WebViewでいい場合は 参考 |
applicationDidEnterBackgroundの中とかでローカル通知のスケジューリングを行う。
アプリを起動したときにスケジュール済みの通知を全削除したりするが、そのタイミングは applicationWillEnterForeground ではいけない。 必ず通るとは限らないからである。 起動 →バックグラウンドへ(ここで通知スケジューリング) →他のアプリを起動するなどしているうちに、アプリが自然にシャットダウンする →アプリを起動 →バックグラウンドへ(ここで通知が2重にスケジューリングされる!) というわけで、通知を全削除する( [[UIApplication sharedApplication] cancelAllLocalNotifications]; )箇所は、 - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions; - (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation; - (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url; - (void)applicationWillEnterForeground:(UIApplication *)application; の4つ…とかはめんどいので、 applicationDidEnterBackground でスケジューリング登録する直前に全削除、が一番楽であろう。 |
adcropsを導入したときの話。
かなり変な癖があって行儀が悪いSDKだったので、今後のために書いておく。 公式 今回実装した広告は、全部ウォール型。正しい名前は確認していないが ・リストウォール ・バナーウォール ・スロットウォール ◯広告設定 ID的なものは2つ。 サイトIDとサイトキー。 1つのアプリに複数種類の広告を置いても、このIDは増えない。 どの種類の広告もこの2つのIDを用いて表示する。 ここが他の広告媒体と違うので注意。 1つで何でも表示できるので便利…といえないこともない。 でも表示箇所ごとに広告を管理(フィルタリングなど)することができないのでどうなんだ。 ◯SDKインストール まずはSDKをインストールする。 header,resourceをまるっとプロジェクトに追加 リンカオプションに -ObjC を追加する。 なぜこのオプションが必要か。 このSDKは、categoryファイルを含んでいる。 そもそもUNIXでC/C++をビルドしたとき、 オブジェクトファイル(ソースファイルから作られるバイナリファイル)内に見つからないシンボルがあるとき、リンカがそれを解決する。つまり、そのシンボル(メソッド)を含む別のオブジェクトファイルをインクルードする。 だが、ObjCのstatic library の categoryはそうならない。 未定義シンボルは未定義のままで、実行時に"selector not recognized"例外が発生してしまう。 そこで-ObjCオプションを付けると、すべてのcategoryのメソッドが実行可能ファイルに含まれるようになる。 ただし、不要なメソッドも含んでしまうので、実行可能ファイルが膨大になることがある。(だからデフォルトオプションになっていない) また、コード中にC/C++で書かれている部分がコンパイルエラーになることがある。 特にcocos2dのライブラリ内でよく起きるのだが、 その場合は、そのファイル全体をコメントアウトしてしまうのが早い。 (大抵ムービーとかゲームコントローラとかあんまり使わないところでしか起きないからだ) 公式のQ&A ◯サンプル さて、この状態ではまだ広告は出ない。 adcropsのSDKはかなり基本的なところしか対応していなくて、 ウォールを表示しようとしたら自分でテーブルビューとか作らないといけない。 これを自分でやるとなると不親切極まりないと憤慨するところだが、 サンプルコードがいろいろ付いている。 サンプルコードをみると、SDKの他に Chk***.h/m/mm というファイルがたくさん入っている。 これらがテーブルビューとかを用意している。いわばヘルパークラスで、アプリ側とSDKを繋ぐ位置にいる。 これらのヘルパーファイルをコピーして、自分のプロジェクトに追加する。 で、アプリ側からはこれらのヘルパーを呼び出す形にする。 複数の広告種類を出すなら、それぞれのサンプルからヘルパーをコピーしてくる。 これで動くようになる。 初めからこのヘルパーもSDKに入れておけ、というところだ。 |
Xcodeでデバッグする便利機能いくつか
【メモリのアクセス違反を検知】 Guard Malloc という機能を使う。 これはXcodeにデフォルトで入っている。 使い方は以下のとおり。スキームの設定をする。 参考 その他の機能の説明 Enable Scribble. Fill allocated memory with 0xAA and deallocated memory with 0x55. Enable Guard Edges. Add guard pages before and after large allocations. Enable Guard Malloc. Use libgmalloc to catch common memory problems such as buffer overruns and use-after-free. 引用元 zombie objectとは、解放されたメモリをNSZombieObjectにリプレースする機能。 解放済みメモリにアクセス違反したとき、どこにアクセスしたのかなどの情報が分かりやすくなる。 NSZombieObjectの説明 さらにいろんな便利機能 参考 うう〜ん、べんり! なお、注意点として、Guard Mallocを有効にした状態で実機実行はできない。 以下のエラーが出る。
面倒だが、シミュレータのときと実機のときで、スキームから設定を変更しよう。 参考 |
公式ドキュメント
を参照。 26ページから(特に28ページ冒頭)を要チェック。 引用----------
リスト 2-8 アクションをカテゴリにまとめるコード例
リスト 2-9 通知カテゴリを登録するコード例
リスト 2-11 ローカル通知に用いるアクションのカテゴリを定義するコード例
引用ここまで------------- つまり まずアクションを作成する。 UIUserNotificationActionクラス identifier title activationMode authenticationRequired destructive などの設定をする。 通知において、ひとつのボタンの操作に対応。 次に、アクションをまとめてカテゴリーを作る。 UIMutableUserNotificationCategory カテゴリーはアクションの配列を格納し、識別子を持つ。 ひとつの通知におけるビューがこれで作られる。 カテゴリーは別に1アプリ1つではない。通知の種類によっていくらでもカテゴリーは作れる。 ただし、コンテキストによって2種類の配列を登録する必要がある。 UIUserNotificationActionContextDefault …これはモーダルビューで見た時 UIUserNotificationActionContextMinimal …これはロック画面で見た時。こちらは最大2つしかアクションを持てない さらに、カテゴリーをセッティングにまとめる。 UIUserNotificationSettings セッティングは、通知種別(アラート、バッジ、サウンドなど)を持つ そして、このセッティングをアプリケーションに登録する。 [[UIApplication sharedApplication] registerUserNotificationSettings:settings]; これにて通知が仕えるようになる。 実際に使うためには、通知をスケジューリング登録する。 UILocalNotification *notification = [[UILocalNotification alloc] init]; ... notification.category = @"INVITE_CATEGORY"; [[UIApplication sharedApplication] scheduleLocalNotification:notification]; |
今やiOSでは当たり前となったAutoLayout。
制約(NSLayoutConstraint)を適切に指定することで、レイアウトを指定することができ、画面サイズの違う端末でも意図通りに表示できるようになる。 AutoLayoutによる位置・サイズの決定は、viewWillAppearとviewDidAppearの間で行われる。 【画面初期化の流れ】 viewDidLoad実行 ↓ viewWillAppear実行 ↓ AutoLayout実行(内部) ↓ ビューのlayoutSubviews実行 ↓ viewDidLayoutSubviews実行(もう一度呼ばれる) ↓ 画面が構成される(内部) ↓ 画面遷移開始(ここからユーザの眼に触れる) ↓ 画面遷移終了 ↓ viewDidAppear実行 間違って(あるいは面倒くさがって)ビューコントローラ上のコードで画面レイアウトを作ろうとして、画面表示前(viewDidLoadなど)でビューのframeを直接いじっても、 その後にAutoLayout制約が適用されて上書きされてしまう。 (じゃあviewDidAppearの後にframeをいじろう、と考えたくなるところだが、それだとちょっと間に合わない。画面遷移をしながら表示するビューの場合、frameをいじる前のビューが画面に映ってしまう(=手遅れ)なのだ。 だから、レイアウトを処理・変更する必要があるビューは、必ずカスタム定義をして layoutSubviews メソッドを実装しておく必要がある。 このメソッドは、viewWillAppearの後に呼ばれる。 また、画面を再構成する必要があると自動的に判断されたときにも呼ばれるし、明示的に呼びたい場合は、ビューコントローラで [view setNeedsLayout]; を実行すればよい。 じゃあどうするか。 制約適用直後に画面が映ってしまうのはさけられない。 ということはつまり、制約適用時に求める画面が構成されるようにしておけばいい。 だから、、、 【制約を動的に作成する】 ということになる。 つまり、AutoLayoutを使うようになった時点で、画面構成はすべて制約で作るようにするべきなのだ。 frameとかboundsとかを直接いじることはなくなってくるはずだ(少なくとも、定数値を代入するようなことはないはずだ。せっかくAutoLayoutを指定していても台無しになる)。 さて、そうすると、どうやってコード上で制約を記述するのか、ということを覚えなければならない。ストーリーボードではいつも作ってるけど、コーディングはどうやって…? 公式のAutoLayoutマニュアル 制約クラスは NSLayoutConstraint 制約のインスタンスを作るメソッドは2種類ある 1.constraintsWithVisualFormat: options: metrics: views: VisualFormat VisualFormatとは、制約を人間に見やすく記述できるDSL。 これを使用して、ビューのサイズや位置を指定する。storyboardとほぼ同じことができる 公式のVisual Format Language仕様 いくつか例示する。 なお、view1,view2などは、制約を作りたいビューのメンバ変数名(詳細は後述) view1の横幅を10にする H:[view1(==10)] view1の高さを20以上にする V:[view1(>=20)] view1の高さを20以上100以下にする V:[view1(>=20,<=100)] view1とview2の幅を同じにする H:[view1(==view2)] ※比較演算子は、==,>=,<= の3つしか使えない ※カッコで囲わないと、パーサーがビュー名の区切りを判断できない。 ※HもVも書かないときはH(水平方向)になる view1とview2を12px空けて横に並べる H:[view1]-12-[view2] view1とview2をデフォルトの間隔を空けて縦に並べる V:[view1]-[view2] view1とview2を間隔無しで並べる H:[view1][view2] superviewとの間隔を指定する。パイプ(|)がsuperviewを表す H:|-50-[view1]-50-| options 指定できる内容は以下 NSLayoutFormatAlignAllLeft NSLayoutFormatAlignAllRight NSLayoutFormatAlignAllTop NSLayoutFormatAlignAllBottom NSLayoutFormatAlignAllLeading NSLayoutFormatAlignAllTrailing NSLayoutFormatAlignAllCenterX NSLayoutFormatAlignAllCenterY NSLayoutFormatAlignAllBaseline NSLayoutFormatAlignAllLastBaseline NSLayoutFormatAlignAllFirstBaseline NSLayoutFormatDirectionLeadingToTrailing NSLayoutFormatDirectionLeftToRight NSLayoutFormatDirectionRightToLeft 何もいらなければ0を指定。 metrics 調べてない views VisualFormat内に登場したビュー名と、ビューへの参照を格納したNSDictionary。 上記の例だと、 NSDictionary viewsDictionary = [[NSDictionary alloc]initWithObjects:@[view1,view2] forKeys:@[@"view1",@"view2"]]; のような感じ。 ちなみにこれと同じことが NSDictionaryOfVariableBindings(view1, view2); と書くことができる。 戻り値 記述した制約をすべて満たせるNSLayoutConstraintの配列が返ってくる。 最終的なコード例 view1の横幅を40にし、view2を水平に12px空けて並べ、それぞれsuperviewと左右端を合わせる。(制約が4つ作られる)
例外を捕まえる VisualFormatは実行時にパースされるので、書き間違えていると例外が飛んでくる。 ちゃんとキャッチしてチェックしよう。
2.constraintWithItem:attribute:relatedBy:toItem:attribute:multiplier:constant: item 制約を付けるビュー。 attribute 以下のものがある。 実態は前のメソッドのoptionに指定するNSLayoutFormat***と同じ。 NSLayoutAttributeLeft = 1, NSLayoutAttributeRight, NSLayoutAttributeTop, NSLayoutAttributeBottom, NSLayoutAttributeLeading, NSLayoutAttributeTrailing, NSLayoutAttributeWidth, NSLayoutAttributeHeight, NSLayoutAttributeCenterX, NSLayoutAttributeCenterY, NSLayoutAttributeBaseline, NSLayoutAttributeLastBaseline = NSLayoutAttributeBaseline, NSLayoutAttributeFirstBaseline NS_ENUM_AVAILABLE_IOS(8_0), NSLayoutAttributeLeftMargin NS_ENUM_AVAILABLE_IOS(8_0), NSLayoutAttributeRightMargin NS_ENUM_AVAILABLE_IOS(8_0), NSLayoutAttributeTopMargin NS_ENUM_AVAILABLE_IOS(8_0), NSLayoutAttributeBottomMargin NS_ENUM_AVAILABLE_IOS(8_0), NSLayoutAttributeLeadingMargin NS_ENUM_AVAILABLE_IOS(8_0), NSLayoutAttributeTrailingMargin NS_ENUM_AVAILABLE_IOS(8_0), NSLayoutAttributeCenterXWithinMargins NS_ENUM_AVAILABLE_IOS(8_0), NSLayoutAttributeCenterYWithinMargins NS_ENUM_AVAILABLE_IOS(8_0), relatedBy 比較演算子。以下の3つ NSLayoutRelationLessThanOrEqual = -1, NSLayoutRelationEqual = 0, NSLayoutRelationGreaterThanOrEqual = 1, toItem 対象となるビューを指定する。 align系なら、どのビューからの距離か、を指定するときに使う。 size系なら、あのビューのサイズの○倍、というような指定の時に使う。 不要ならnilを指定。 attribute toItem側のattribute。 itemのtopとtoItemのtopが○○px離れてる、というような制約のときに使用。 なければ0。 multiplier 係数。計算式に使う。後述 constant 定数。計算式に使う。後述 コード例 view1の高さを123にする場合。
view1の上端をview2の上端から25px以上空ける制約
view1の幅をview2の高さの2倍より10大きいサイズにする制約
|