面白きことは良きことなり

拙く未熟なiOSエンジニアの備忘録と戯言

UIButtonが青色一色のベタで表示された時の対処

初歩的ミス

IBOutletで紐づけていたUIButtonにコードでimageをセットしてあげるも、青色一色でベタ塗りされた表示になっていた。

理由としては、UIButtonのTypeがSystemだったために画像をセットしても青色で表示されていた。

Customに変えて正常に表示されたので、解決。

tak-lab.net

URLComponentsは、`+`をPercent Encodingしてくれない

経緯

APIを叩く際にランダムに生成しな内容をBASE64化してQueryにつけて送信しようとしていたが、5割ぐらいのエラーになっていた。
調査した結果、+がPercent Encodingされていないためだったが、なぜこんなことが起きたのか…。

便利なURLComponentsの罠

qiita.com

この記事でURLComponentsという便利なものがある!自前でPercent EncodingしてQuery作らなくていいんだ!とうっきうきで使っていたわけだが、+はPercent Encodingしてくれない。(ちなみに+をPercent Encodingすると%2Bになる)

stackoverflow.com

なぜ起こったか

今回のようなことが何故起こったのか。

URLComponentsは、説明にRFC 3986に準拠していると記載されている。サーバ側がRFC 3986に準拠していない作りが理由とも言えるし、自分がそこを確認怠り、URLComponentsを使用したのが理由とも言える。

URLComponents - Foundation | Apple Developer Documentation

サーバの作り次第で、このあたりはいくらでも変わるので、気をつけたいところ。

今回は、時間やコードの手戻りが厳しいこともありURLComponentsでQueryを付けた後、+%2Bに置換する力技で解決した。

URLComponentsに頼らない自作URLComponentsのようなものを作ってもいいかもしれないと思った。

WebView実装してリロードしまくったら出るNSURLErrorDomain エラー -999

前説

業務が忙しかったこともあり、色々ネタはありつつも書いてなかったので、落ち着いてきた今日あたりから徐々にまた書いていく。軽めにね。

NSURLErrorDomain エラー -999

WKWebViewを実装して特に制御せず、back, forward, reloadボタンと処理を紐づけていたがため、reload連打したらエラーなんか出たというバグ報告が上がった。

エラー内容は、 操作を完了できませんでした。(NSURLErrorDomain エラー -999。)

特にパッとなんでこのエラーが出たのか説明できなかったので、改めて調べた。

これは、発行したリクエストをキャンセルした際に返るエラーとのことで、reload連打によりリクエストがキャンセルされてエラーとして返ってきてるために出ているものと判明。

captainshadow.hatenablog.com

ちなみにerror codeは、NSURLErrorCanceledとして定義されている。

NSURLErrorCancelled - Foundation | Apple Developer Documentation

UIBarButtonItemで画像の見たを変えずに使用するやり方

UIBarButtonItem

UIBarButtonItemは、UINavigationControllerとかと併せてよく使うButtonですが、そのまま使用すると下記のように透過じゃない部分は単色でTint Colorによって塗りつぶされます。

f:id:aryzae:20180211211616p:plain
この画像を使用すると…

f:id:aryzae:20180211211808p:plain
こうなる

これを画像を加工せずそのまま表示したいと思ったので、いいやり方ないか調べた際のメモです。

init(customView:)を使う

UIBarButtonIteminit(customView:)という初期化方法にUIButtonを設定することで簡単に実現できる。

流れとしては、

  1. Storyboardで、UIButtonを用意する
  2. IBOutletで紐づける
  3. そのButtonを使用してコードでUIBarButtonItemを作成する
  4. UIBarButtonItemをセットする

f:id:aryzae:20180211212238p:plain

そうすると、このようになる、

f:id:aryzae:20180211212353p:plain

このやり方のメリットとして、StoryboardのUIButtonからIBActionを設定できるのでaddTargetとかを使って#selectorで押下時の挙動を設定してあげる必要がない。

Storyboardを使わない場合

この場合、コードでUIButtonを生成して同じようにUIBarButtonIteminit(customView:)でセットしてあげればよい。

AutoLayoutでmarginを画面比率によって変更したい時の対処

経緯

ふと前にも調べた気がするが、覚えていないなら覚えるまで同じ記事であろうか書くしかない。

AutoLayoutで制約をつけていると、固定のものは問題ないが、画面サイズによって可変にしたい場合、Viewのwidthheightであれば、superviewとequal widthやequal heightしてから、割合で入力してやれば簡単にできるので困らない。

一方で、safeAreaのtopからのmarginとなると素直にやる方法がなくて困る。

UINavigationBarがないStoryboardなら使える方法

ものによっては、Vertically in Containerをつけて調整することで対応できるものもある。(具体的に言えば、UINavigationBarの影響がないStoryboard、LaunchScreen等)

ただ、これも万能ではなく、Storyboard上で上手く作れた様に見えて、実機で確認するとstatusBarやNavigationBarの高さが余分に含まれた見た目になることがある。

Storyboardを捨てるかどうか

marginを画面サイズから割合で出す方法は2つある。

1. Storyboardを使わない場合

UILayoutGuideというものがあるので、これを使いましょう。

詳しくはこちら

Goodbye Spacer Views Hello Layout Guides

2. Storyboardを使う場合

これは、もう色々諦めの境地で空のUIViewをSpacerとして配置しましょう。

ViewとView、safeAreaとViewの間に置き、TopやBottom等を0marginでくっつけ、SpacerのViewのwidthheightをsuperviewとの割合で調整します。調整が終わったら、hiddenにチェックをつけ、画面から見えないようにします。

これは意味もなくViewを置く無駄加減にモヤっとしますが、他に方法がないです。

UILayoutGuideがInterface Builderに対応してくれれば、可能ですが、Xcode9の時点では無理です。(Xcode7時代からずっと今まで無理)