hachinoBlog

hachinobuのエンジニアライフ

NSURLConnectionでオレオレ証明書(自己署名証明書)を許可する方法

背景

オレオレ証明書を使用している開発機にNSURLConnectionでhttps接続しようとしたら下記エラーが出力された。

NSURLConnection/CFURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9813)

解決方法

NSURLConnectionのデリゲートの - (void)connection:(NSURLConnection )connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge )challenge を実装してやる。

#pragma mark - NSURLConnection Delegate
//開発環境のオレオレ証明書(自己署名証明書)を許可するため
- (void)connection:(NSURLConnection *)connection willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
    //SSL認証だった場合の処理(NSURLAuthenticationMethodHTTPBasicやNSURLAuthenticationMethodHTTPDigestもある)
    if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
        // "hachinobu-test.elasticbeanstalk.com"か確認
        if ([challenge.protectionSpace.host isEqualToString:@"hachinobu-test.elasticbeanstalk.com"]) {
            [challenge.sender useCredential:[NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust] forAuthenticationChallenge:challenge];
        }
    }
    [challenge.sender continueWithoutCredentialForAuthenticationChallenge:challenge];
}

こうすることでオレオレ証明書を使用している開発機にもアクセスできる。

CocoaPodsで[overrides the `HEADER_SEARCH_PATHS` build setting defined in `Pods/Pods.xcconfig'.]の対処方法

背景

CocoaPodsでライブラリをインストールしようとしてpod installコマンドを叩いた際に下記が出力されたので調べた。

[!] The target `MyProject [Debug]` overrides the `HEADER_SEARCH_PATHS` build setting defined in `Pods/Pods.xcconfig'.
    - Use the `$(inherited)` flag, or
    - Remove the build settings from the target.

[!] The target `MyProject [Debug - Release]` overrides the `HEADER_SEARCH_PATHS` build setting defined in `Pods/Pods.xcconfig'.

対処方法

対処方法は出力されている通りで自分のprojectの[TARGETS]-[Build Settings]-[Header Search Paths]に$(inherited)を追加してやれば良い。

f:id:hachinobu:20140423141524p:plain

ここで注意すべきは上記画像のように[Header Search Paths]の一番上に$(inherited)を追加すること。

そうしないとビルドしても継承が読み込まれずエラーとなる。

ちなみに今回はoverrides the HEADER_SEARCH_PATHS だったがOTHER_LDFLAGSの場合がある。

この場合でも今回と同じように[Other Linker Flags]に$(inherited)を適宜追加してやることで対処できる模様。

iOS7でステータスバーの領域が黒く塗りつぶされてしまう場合の対処方法

背景

iOS7でNavigationControllerのNavigationBarを使用しているにも関わらず下記のようにステータスバーが黒く塗りつぶされてしまい対応するのに時間を要してしまったのでメモ。

f:id:hachinobu:20140417134442p:plain

原因

この現象になる原因としてはiOS6以前でUINavigaitonBarに画像を下記のように設定していた。

[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:@"header-44.png"] forBarMetrics:UIBarMetricsDefault];

header-44.pngは名前の通り高さが44ptなので、iOS7からはステータスバー領域も含めてsetBackgroundImage:に指定した画像が適用されるためステータスバー領域が黒く塗りつぶされていた。

setBackgroundImage: forBarPosition: barMetrics:の検証

iOS7用に setBackgroundImage: forBarPosition: barMetrics: メソッドが新しく使えるようになりforBarPosition:に指定するUIBarPositionを適切に設定することで背景がステータスバー領域の上まで延びて表示されるようになるとドキュメントに記載されていたので試してみた。

しかしどれも変わらずステータスバー領域が黒く塗りつぶされたまま。。

UIBarPositionBottomを指定した場合には画像を認識してくれなかった。

対応方法

結局のところ素直にUINavigaitonBarに設定する画像の高さをステータスバー領域も含めた64ptの画像を作成してOSのバージョンによってsetBackgroundImage: forBarMetrics:メソッドで指定する画像を切り替えて対応した。

NSString *headerImageName = @"header-64";
//iOS6以下である場合は高さ44ptの画像を設定
if ([[[UIDevice currentDevice] systemVersion] floatValue] < 7.0f) {
    headerImageName = @"header-44";
}
[self.navigationController.navigationBar setBackgroundImage:[UIImage imageNamed:headerImageName] forBarMetrics:UIBarMetricsDefault];

f:id:hachinobu:20140417140538p:plain

NSDateで取得したGMT時間のままNSStringに変換する方法

背景

NSDateのdateメソッドで時刻を取得すると日本時間とは9時間差のGMT時間が返されることは知っていたのだがNSDateFormatterで取得した時間をNSString型に変換したらGMT時間でなく現地時間に変換されてしまっていたので調べた。

現象

NSDate *now = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
NSString* dateString = [formatter stringFromDate:now];
NSLog(@"now:%@", now); //now:2014-04-04 11:16:16 +0000
NSLog(@"dateString:%@", dateString); //dateString:2014-04-04 20:16:16

GMT時間のままNSStringに変換されない。

解決方法

NSDate *now = [NSDate date];
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"];
[formatter setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0]];
NSString* dateString = [formatter stringFromDate:now];
NSLog(@"now:%@", now); //2014-04-04 11:22:48 +0000
NSLog(@"dateString:%@", dateString); //dateString:2014-04-04 11:22:48

このようにNSDateFormatterにタイムゾーンを設定してやることでGMT時間でNSStringに変換できる。 タイムゾーンはNSTimeZoneクラスのtimeZoneForSecondsFromGMTというGMT時間からの経過秒数を引数にもつメソッドに0を指定したタイムゾーンをセットしてあげる。

NSDictionaryの配列からNSPredicateを使って該当のNSDictionaryを抜き出す方法

背景

NSDictionaryの配列から該当のNSDictionaryを取得する際に今まではforループで1つ1つ判定して取得していたのだが速度が遅いのでNSPredicateを使って該当のNSDictionaryを取得する方法を調べた。

やり方

NSArrayのfilteredArrayUsingPredicateで取得したいNSDictionaryのKeyとValueを検索条件に入れて抽出できる。

NSDictionary *personDic1 = @{@"name": @"hachinobu", @"age": @28};
NSDictionary *personDic2 = @{@"name": @"suzuki", @"age": @40};
NSDictionary *personDic3 = @{@"name": @"honda", @"age": @27};
NSDictionary *personDic4 = @{@"name": @"samuragochi", @"age": @50};
NSArray *personArray = @[personDic1, personDic2, personDic3, personDic4];
NSPredicate *predicate = [NSPredicate predicateWithFormat:@"%K == %@", @"name", @"hachinobu"];
NSDictionary *resultDic = [[personArray filteredArrayUsingPredicate:predicate] firstObject];
NSLog(@"results:%@", resultDic);

出力

results:{ age = 28; name = hachinobu; }

関連記事

配列からNSPredicate条件を使ってデータを抽出する方法

16進数のカラーコードをもとにUIColorを作成する

背景

カラーコードは大体16進数表記なのでiOSのUIcolorを作る際に16進数表記のカラーコードを10進数に変換してUIColorを作成したかったので調べた。

やり方

下記メソッドをUIColorのカテゴリに追加した。

+ (UIColor *)colorWithHexString:(NSString *)hex
{
    //先頭に#がついていた場合は#を削除
    if ([hex hasPrefix:@"#"]) {
        hex = [hex substringFromIndex:1];
    }

    unsigned int rgb[3];
    for (int i = 0; i < 3; i++) {
        NSString *component = [hex substringWithRange:NSMakeRange(i * 2, 2)];
        NSScanner *scanner = [NSScanner scannerWithString:component];
        [scanner scanHexInt:&rgb[i]];
    }
    return [self colorWithRed:rgb[0]/255.0 green:rgb[1]/255.0 blue:rgb[2]/255.0 alpha:1.0f];
}

これで16進数のカラーコードに対応したUIColorを取得することができる。

WebViewで表示しているHTMLのソースを表示する方法

背景

プログラム内で動的に生成したHTMLをWebViewで表示した際にデバッグ目的としてHTMLのソースを表示したくて調べた。

やり方

表示終わりのwebViewDidFinishLoad:メソッドあたりに下記コードを追加。

- (void)webViewDidFinishLoad:(UIWebView *)webView 
{
  //全文表示
  NSString *fullHtml = [webView stringByEvaluatingJavaScriptFromString:@"document.getElementsByTagName('html')[0].outerHTML"];
  NSLog(@"html:%@", fullHtml);

 
  //bodyタグ内のみ
  NSString *bodyHtml = [webView stringByEvaluatingJavaScriptFromString:@"document.body.innerHTML"];
  NSLog(@"html:%@", bodyHtml);
}

これでHTMLのソースを表示することができます。