ios

A collection of 47 posts
ios

iOS7,8,9のアプリケーションライフサイクル

以前に作ったアプリがiOS9でうまく動かないという連絡を受けたので調査した結果、アプリケーションのライフサイクルが変更されたことによりイベントトリガと描画の関係が前後するというしょぼいミスをしていました。 悔しいので変化をまとめました。 具体的な問題の原因となった箇所はこちら。詳細は下のライフサイクルを見たらわかります。 -[AppDelegate applicationDidBecomeActive:] 検証したアプリの画面構成 1. UINavigationController 2. FirstViewController 3. SecondViewController(FirstViewController.navigationControllerにpushされる) iOS7 (7.1.2 // 起動 -[FirstViewController awakeFromNib] -[AppDelegate application:willFinishLaunchingWithOptions:] -[AppDelegate application:d
1 min read
xcode

Xcode7からのBundle Identifier定義

--- 追記@2016/12/6 こっちにXcode8での設定方法を書きました --- 追記ここまで Xcode6系まではinfo.plistで直接定義する形だったけど Xcode7からはProjectファイルで定義するようになって、info.plistのbundle identifierの項目はこんな感じになっていた(Xcodeのマイグレーションをするとこうなるということで。 $(PRODUCT_BUNDLE_IDENTIFIER) メリット ビルド設定(Build Configuration)でバンドルIDが変更できるようになった。 Debugビルド、Releaseビルド、AdHocビルドなどでバンドルIDが変更できるのでターゲットを無駄に追加する必要が無くなった。 デメリット 理解していない人がinfo.plistを書き換えたら死ねる。 下手に書き換えられたら別アプリになるから。。。
ios

iOS9のFontFamilyName

iOS8系でフォントの一覧を出したので、iOS9でもやっておく。 なんかfamilyNamesの中身が無いものもいくつかあったぽい(たぶんCJKとか言語に依存するものだと思う)。 取得方法 familyNameからfontNameを取得する。 for (NSString *familyName in [UIFont familyNames]) { for (NSString *fontName in [UIFont fontNamesForFamilyName:familyName]) { NSLog(@"%@", fontName); } } 確認環境 iPhone Simulator (iOS9) 結果抜粋 Copperplate-Light Copperplate Copperplate-Bold IowanOldStyle-Italic IowanOldStyle-Roman IowanOldStyle-BoldItalic IowanOldStyle-Bold KohinoorTelugu-Regular
2 min read
ios

GoogleAnalyticsを組み込んだiOSアプリがiOS9実機ビルドできなかった

表題の通りGoogleAnalyticsを組み込んだiOSアプリのiOS9実機ビルドでエラーが出た。 とりあえず何も考えないでGoogleAnalyticsを最新版に更新したが変わらなかった。iOS9対応というかXcode7対応。 https://developers.google.com/analytics/devguides/collection/ios/v3/sdk-download?hl=ja エラー内容 ld: '/Users/xxxx/path/to/app/Libs/GoogleAnalytics/libGoogleAnalyticsServices.a(TAGDataProvider.o)' does not contain bitcode. You must rebuild it with bitcode enabled (Xcode setting ENABLE_BITCODE), obtain an updated library from
1 min read
ios

iOSエンジニアに知っていてほしいブレークポイント

アプリを改修するiOSエンジニアが知っていると得をするブレークポイント。 デバッグするときにブレークポイントを使用しないエンジニアはあまりいないと思う。 アプリを改修することになったとき、元々自分が実装したアプリ以外は画面の構成やイベントハンドリングが自分の思想とは全然違うことがあって、どこで画面遷移が行われているのか。どの画面がいま表示されている画面なのかわからないということはよくある。 そんなときに使うブレークポイントがSymbolicBeakpoint。 Xcodeで「⌘+7」を押してブレークポイントを表示して、ウィンドウ左下の+ボタンから作成する。 [UINavigationController pushViewController:animated:] [UIViewController presentViewController:animated:completion:] こんな感じで設定しておけば、このクラスメソッドやインスタンスメソッドが実行されるときにブレークポイントが作動して止まってくれる。 上記の場合だど実際にはUIKit
1 min read
ios

UITabBarの色を変える

UITabBarControllerのデザインをちょこちょこ調整する必要があった。 またいつか使いそうな気がするのでメモ。 この設定はiOS7.1系以降なら問題なく動くと思う。7.0系は問題があったようななかったような。 + (UIImage *)imageFromColor:(UIColor *)color size:(CGSize)size { CGRect bounds = CGRectZero; bounds.size = size; UIGraphicsBeginImageContext(bounds.size); CGContextRef contextRef = UIGraphicsGetCurrentContext(); CGContextSetFillColorWithColor(contextRef, [color CGColor]); CGContextFillRect(contextRef, bounds); UIImage *image = UIGraphicsGetImageFromCurren
1 min read
program

Xcodeでメソッドにコメント書く

コメントは大事 例えばこんな感じで書くと色々と便利。メソッドだけじゃなくてプロパティとかただの変数でもいい。 /** @method increment: @param i NSInteger 数値 @return 引数iをインクリメントして返す 引数iをインクリメントして返すお仕事 */ - (NSInteger)increment:(NSInteger)i { return ++i; } 気をつけること 1. コメントは/*!ではなく/**で始めた方がいい。Swiftで/*!が無視された(今は違うかも? 2. 説明を書くときは空行を入れる、もしくは@discussionを使う この2つくらい。 使い方 コメントを書いたメソッドをクイックヘルプ(オプション+左クリック、もしくはコントロール+コマンド+ハテナ)するとこうなる(メソッドを呼び出す箇所でも同じ)。 しかしここまで書くのはめんどくさいし、そもそもクイックヘルプを表示するとかダルい。 どうせならメソッド打つときの補完と同じように大事な部分だけ表示できれば十分
1 min read
ios

ifdefとかのマクロ

iOSアプリを開発している人にはおなじみであろうマクロ #ifdef DEBUG // do something #endif Xcodeでプロジェクトを作成するとDebugビルドにはDEBUGがPreprocessor Macrosの初期値として設定されているので使用している人は多いと思う。 この#ifdefとかに混ざって#ifも使われていたりしてマクロがカオスになっているソースがたまにある。 ということで検証 // フラグ作成 #define TEST_FLG 1 // ifdefの場合 #ifdef TEST_FLG NSLog(@"ifdef TEST_FLG Success"); #else NSLog(@"ifdef TEST_FLG Failure"); #endif // TEST_FLG // ifの場合 #if TEST_FLG NSLog(@"if TEST_FLG Success"); #else NSLog(@"if TEST_FLG Failure"
1 min read
objc

iOS8のFontFamilyName

iOS9はこちら 取得方法 familyNameからfontNameを取得する。 for (NSString *familyName in [UIFont familyNames]) { for (NSString *fontName in [UIFont fontNamesForFamilyName:familyName]) { NSLog(@"%@", fontName); } } 確認環境 iPhone Simulator (iOS8.2) 結果抜粋 Marion-Italic Marion-Bold Marion-Regular Copperplate-Light Copperplate Copperplate-Bold STHeitiSC-Medium STHeitiSC-Light IowanOldStyle-Italic IowanOldStyle-Roman IowanOldStyle-BoldItalic IowanOldStyle-Bold CourierNewPS-BoldMT CourierNe
2 min read
objc

IBInspectableを使ったらエラーが出た

IBInspectableを使うとInterfacebuilderがよしなに表示を変えてくれるとかいうのは知ってた(試しに使ったことはあった程度だった)けど、IBInspectableを使っているライブラリがあったので使ってみた。 IB Designables Failed to render instance of XXX: Rendering the view took longer than 200ms. Your drawing code may suffer from slow... こんな感じのエラーが出た。xibファイルが無駄に複雑で巨大なせいでレンダリングが遅い画面だったけど、IBInspectableを使った結果余計なエラーが出るようになった。 もちろんビルドには問題ない。ただ気持ち悪いだけで。
objc

NSLayoutConstraint.constantの値を変更してビューのサイズを取得した

フラグでNSLayoutConstraint.constantの値を変更してscrollViewのcontentSizeを変更する、ということをしようとしたけどうまくいかなかった。 CGRectGetMaxY()の時点では_childView.frameにはconstraintの値が反映されてなかった。 だいたいの処理の流れ(適当) - (void)updateConstraint { if ([self isHidden]) { _childViewConstraint.constant = 100.f; } else { _childViewConstraint.constant = 0.f; } CGRect frame = _mainView.frame; frame.size.height = CGRectGetMaxY(_childViewConstraint.frame); _mainView.frame = frame; CGSize cont
ios

dispatch_sync

dispatch_syncを使う - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // メインスレッドで非同期実行 NSLog(@"1.%@", [NSThread isMainThread]? @"mainThread": @"backgroundThread"); dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // 第一引数でキューを指定して同期実行 NSLog(@"2.%@", [NSThread isMainThread]? @"mainThread": @"backgroundThread"); }); return YES; } 結果 2015-03-04 00:00:00.393 BlockTest[87
1 min read
objc

NSURLSessionでBasic認証する

どうせ1つのアプリで複数のBasic認証することなんて無いっしょ とか思いつつも使い回しがききそうな実装を考えたのでメモ 1. requestのURLはhttp://user:password@example.comみたいにユーザとパスワードも記載しておくとする 2. NSURLSessionTaskのcompletionHandlerは使わないでdelegateを使用する 3. WWW-Authenticateのrealmを取得 4. 認証するURLに対してcurl -vとかリクエストして401レスポンスを取得 5. 今回はこんなレスポンスが来ていたWWW-Authenticate: Basic realm="Login Required" 6. 該当realmはLogin Required 7. delegateメソッド- URLSession:didReceiveChallenge:completionHandler:を実装する 8. - URLSession:didReceiveChallenge:completionHandler: - (void)
1 min read
objc

Xcode6.1.1で実機が選択できなかった

先日買ったiPadに開発中のアプリをインストールしようとしたらデバイス一覧に表示されず2日間ほど無駄をしてしまった。 プロジェクトのバンドルIDもプロビジョニングも問題無いことは確認済みだった(別Macではインストールできた)ので、MacかXcodeの設定に問題があるのだろうと思っていた。 解決方法 * 実機をMacに接続 * ステータスバーのWindow > Devices * Devicesウィンドウの左上DEVICESで該当の実機を[Ctrl+Click] * Show in Run Destinations Menuをクリック(チェックがついたらOK) 参考 Stack Overflow
ios

NSDataのバイトコードをNSStringに変換する

NSString *str = @"hogehoge"; NSMutableString *result = [NSMutableString string]; NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding]; NSLog(@"data: %@", data); // data: <686f6765 686f6765> const unsigned char *bytes = [data bytes]; for (int i=0; i<[data length]; i++) { [result appendFormat:@"%X", bytes[i]]; } NSLog(@"result: %@", result); // result: 686F6765686F6765 デバイストークンの取得をするときに@"<"と@">"と@" "を置換するのよりもイケてる方法があるんじゃないかと思いながら実装していたので変換方法を探してみた。 for文の中で[data getBytes:range:]しようか
ios

APNs証明書を作る(アプリ登録済みの場合)

ザックリとメモする Step.1 Apple Developer CenterでCertificatesの登録リクエストを行う。 * Certificates > +ボタン > 「Apple Push Notification service SSL」 * iOSアプリがDevelopment証明書を使用する場合はSandbox, Distributionビルドを使用する場合はProductionになる * Continue Step.2 APNs証明書が使用するAppIDを選択 Step.3 Certificateの生成 証明書アシスタントでリクエストを作成する * キーチェーンアクセスを起動(/Applications/Utilities/キーチェーンアクセス) * 画面左上のメニューから「キーチェーンアクセス」>「証明書アシスタント」>「認証局に証明書を要求」 証明書アシスタントの入力内容 * メールアドレス > ユーザのメールアドレス * 通称 > 識別情報がわかる名前 * CAのメールアドレス > 空欄 *
1 min read
objc

UIWebView Cache Clear

UIWebViewのキャッシュクリアが地味に面倒だったのでログ iOS7系のキャッシュクリアがなんか変だった。詳しく調査してないけどこれでうまくうごいた。 やること1 UIAppcalation method - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions とか絶対呼ばれる場所に下を書いておく // WebViewのキャッシュを削除 [NSURLCache sharedURLCache].memoryCapacity = 0; [NSURLCache sharedURLCache].diskCapacity = 0; やること2 UIWebViewDelegate method - (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationTyp
ios

Xcode6のシミュレータのディレクトリ構成

アプリケーションがインストールされるディレクトリ ~/Library/Developer/CoreSimulator/Devices/<該当シミュレータのハッシュ値>/data/Containers/Bundle/Application/ アプリケーションのデータが設置されるディレクトリ ここにDocuments, Library, tmpなど入ります ~/Library/Developer/CoreSimulator/Devices/<該当シミュレータのハッシュ値>/data/Containers/Data/Application/<アプリケーションのハッシュ値>/ 該当シミュレータのハッシュ値は下記plistファイルに記載がある ~/Library/Developer/CoreSimulator/Devices/.default_created.plist
objc

iOS8でプッシュ通知を使ったりバッジを使ったり

今までプッシュ通知の利用を宣言するのに使ってたメソッドregisterForRemoteNotificationTypesがiOS8からdeprecatedに変わっていたのでメモ プッシュ通知の利用するとき iOS7以前の場合 [[UIApplication sharedApplication] registerForRemoteNotificationTypes:(UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound | UIRemoteNotificationTypeAlert)]; iOS8以降の場合 [[UIApplication sharedApplication] registerForRemoteNotifications]; UIUserNotificationSettings* notificationSettings = [UIUserNotificationSettings settingsForTypes:(UIUserNot
2 min read