- Preference
- Accounts
- View Details
- 今あるやつ全部捨てる(右クリック)
- Xcodeを殺す(← ここ重要)
- 再起動
- Preference > Accounts > View Details で、「Download All」
【iOS】画面の向き(Orientation)を特定のページのみで制限したり許可したりしたい【supportedInterfaceOrientations】
ゴール
たとえば
- 基本的にPortrait(縦向き)のみに制限したいんだけど、特定の画面だけではLandscape(横向き)を許可したい
特定のViewで、強制的に向きを変えることはできる
けど、これは向きを変えるだけであって、ふたたび端末をぐるっとすると縦向きに戻ったりする。かなしい。
override func viewDidLoad() { super.viewDidLoad() // Force Orientation Landscape UIDevice.currentDevice().setValue(UIInterfaceOrientation.LandscapeLeft.rawValue, forKey: "orientation") }
- objective c - How to force view controller orientation in iOS 8? - Stack Overflow
- しかも、あんまり推奨されるものではないっぽい雰囲気がある
Info.plistで、全体的に使うOrientationは制限できる
プロジェクトファイル(file path的にはInfo.plist)で、以下のような項目があるから「これでいーじゃーん」と思ってチェックしても、これはアプリケーション全体で許可非許可の扱いなので、「◯◯というViewだけは横ね」みたいにホワイトリスト的な挙動は設定できない。
supportedInterfaceOrientationsを使う
ViewControllerのメソッド(shouldAutoRotateと)supportedInterfaceOrientationを使えば、ViewControllerごとにサポートするOrientationを明示的に指定できる。
- ios - how to lock portrait orientation for only main view using swift - Stack Overflow
- の、コメント
- shouldAutorotate - UIViewController | Apple Developer Documentation
- supportedInterfaceOrientations - UIViewController | Apple Developer Documentation
class MyViewController: UIViewController { // ... // ここでtrueを返すと、`supportedInterfaceOrientations`が呼ばれる override func shouldAutorotate() -> Bool { // まあでもデフォルトでtrue返すっぽいし、overrideしなくていいっぽい return true } // ここでサポートできるOrientationを明示できる override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return UIInterfaceOrientationMask.Portrait } }
supportedInterfaceOrientationsがなんかうまく動かないときに疑うこと
しかし、これだけだと(だいたいの場合)動かない(と思う)。なぜなら、
When the user changes the device orientation, the system calls this method on the root view controller or the topmost presented view controller that fills the window. supportedInterfaceOrientations #Discussion
「ユーザがデバイスの向きを変えたとき、システムはルートのViewControllerもしくは一番上で画面いっぱいに表示されているViewControllerの supportedInterfaceOrientations
を呼びます。」
とのことで、だいたいの場合、UINavigationControllerとか、TabBarControllerとか、PageViewControllerとかにこれを実装するハメになってくるんではないかと思う。
UINavigationControllerを継承したMyNavigationControllerとかを作ってもいいんですけど
一案として、上記のメソッドを実装した独自のMyNavigationController
を作って、下記のようにするのかもしれない。
class MyNavigationController: UINavigationController { override func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return UIInterfaceOrientationMask.Portrait } } // で、Storyboardなりで、起点になるNavigationControllerの // classをこいつに指定してあげれば、このメソッドが呼ばれるはず
たぶんこれでも動くんだけど、若干のだるさがあるので、標準のUINavigationControllerのextension作っちゃえばいいじゃないか、という結論になった。
最終的に
// TabBarControllerのcontextがメイン extension UITabBarController { override public func shouldAutorotate() -> Bool { return true } // もうちょっとちゃんとやる場合は、子供のViewControllerに // supportedInterfaceOrientationsを実装して // return selectedVC.supportedInterfaceOrientations() // とかすれば、判断を子供に委譲できる override public func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { guard let selectedVC = self.selectedViewController else { return UIInterfaceOrientationMask.Portrait } // TabBarControllerの中でNavigationを使ってるケースがある guard let navigation = selectedVC as? UINavigationController else { return UIInterfaceOrientationMask.Portrait } // Navigationで一番うえのやつを取得して guard let current = navigation.viewControllers.last else { return UIInterfaceOrientationMask.Portrait } // これ!このビューのときだけ横を許可して!! if current is MyCoolViewController { return UIInterfaceOrientationMask.Landscape } return UIInterfaceOrientationMask.Portrait } } // サービスの登録フローとかは、いきなりNavigationが出るので extension UINavigationController { override public func shouldAutorotate() -> Bool { return true } override public func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return UIInterfaceOrientationMask.Portrait } } // サービスのイントロ画面は、いきなりPageViewControllerなので extension UIPageViewController { override public func shouldAutorotate() -> Bool { return true } override public func supportedInterfaceOrientations() -> UIInterfaceOrientationMask { return UIInterfaceOrientationMask.Portrait } }
という感じになった。これを、AppDelegate.swift
のケツにでも追加しとく。今回は明示的に "ここでだけで" まとめたかったので、各々のsupportedInterfaceOrientation
を呼ぶ実装にはしなかったけど、必ず各々に判断を委譲するほうが綺麗なケースもあると思う。
雑感
- swiftのコードをインターネッツでググっても、動いたり動かなかったりする
- swiftという言語が若いからかなと思ったけど、どうやらそうでもない
- 情報の絶対量はAndroidよりも多いし
- Objective-Cの情報でも参考にできることは多いし
- おそらくアプリの要件が人それぞれで、しかもそれがけっこう切り分けられないんだと思われる
- 今回のケースでいうとroot view controllerがTabBarControllerだったり、NavigationControllerだったり、PageViewControllerだったりした
- とかそういうこと
- であるからして、慌てず焦らず、ちゃんと英語読んで、公式も当たって「なぜ動かないか」を環境非依存な知識までかみ砕いて理解していくのが大事だなあ、と思った
- 勉強になります
DRYな備忘録として
【Go言語】ローカルのGoの(継続的な)バージョンアップ【go1.7】
なんかいつの間にこんなrepoあったの
git clone https://go.googlesource.com/go
とりあえず現状確認
% go version go version go1.6.2 darwin/amd64 % echo $GOROOT /Users/otiai10/.go/1.6.2 % ls /Users/otiai10/.go 1.4.3 1.5.3 1.6.2
なるほど、かつての自分はディレクトリを分けて保存していたっぽい。ミラーじゃなくて公式にソースを配布するレポジトリになってるので、これからはgitのrevisionでソースのバージョンを管理できるはず。ということで、以下のような構成にしました。
% cd /Users/otiai10/.go % git clone https://go.googlesource.com/go tip % ls /Users/otiai10/.go 1.4.3 1.5.3 1.6.2 tip
いいかんじ。そして、いざインストール。これ Installing Go from source - The Go Programming Language に従って、
% cd /Users/otiai10/.go/tip % git checkout go1.7 # "go1.7" のリリースタグのリビジョンへ移動 % cd src % GOROOT_BOOTSTRAP=/Users/otiai10/.go/1.6.2 ./all.bash # 1.4以降のバイナリを要求するので、そこへのpathを指定する # 今回は、直前の1.6を使った。今後も1.6でいいだろうと思う
で、
# 中略... +pkg debug/pe, type Section struct, Relocs []Reloc +pkg debug/pe, type StringTable []uint8 +pkg time, func Until(Time) Duration ALL TESTS PASSED --- Installed Go for darwin/amd64 in /Users/otiai10/.go/tip Installed commands in /Users/otiai10/.go/tip/bin *** You need to add /Users/otiai10/.go/tip/bin to your PATH.
と言われるので、~/.zshrc
でGOROOT
の値を/Users/otiai10/.go/tip
に変え、PATH=$PATH:$GOROOT/bin:$GOPATH/bin
は変わらず。別シェルを立ててログインしなおすと、
% go version
go version go1.7 darwin/amd64
良い感じっぽい。エディタの環境設定もちょっといじる必要があるはず。まあ後でいいや。そんで、今後1.8、1.9とかがリリースされたら、
% cd /Users/otiai10/.go/tip % git fetch origin % git checkout {なんかそのバージョン} % cd src % GOROOT_BOOTSTRAP=/Users/otiai10/.go/1.6.2 ./all.bash
とすればいいはず。PATHはtipに通ってるので、もう編集する必要は無いはず。
雑感
- ベルリンで働きはじめて半年が経ちました
- サーバサイドエンジニアのはずが、iOS書いてます
- ビール🍺の飲み過ぎで太りました
DRYな備忘録として
SwfitでTableViewをつかってかっこいいフィードを実装するときに習得したことまとめ
いかんせんスケジュールがギリギリだったので、個別にエントリ書くのは無理でした
- TableView
- TableViewの各Rowの高さを指定したい
tableView.rowHeight
- swiftでtableViewの高さを変更する - Qiita
- TableViewのボーダーを消したい
tableView.separatorStyle = UITableViewCellSeparatorStyle.None
- UITableViewの区切り線(separator)を個別に非表示にする - Qiita
- TableViewCellのUIButtonが反応しない
- cell.contentView.userInteractionEnabledがtrueだと、そっちに奪われるとか
- 直上のUIViewのuserInteractionEnabledがfalseになっちゃってるとか
- その他もろもろ 戦車やスマホを爆散させるブログ subViewのUIButtonが反応しない時に注意する事
tableView.allowsSelection
が怪しかったんだけど、再現しないんだよなあ
- TableViewの各Rowの高さを指定したい
- UINavigationBar
- navigationbarの背景色を変えたい
self.navigationController!.navigationBar.barTintColor = UIColor(...
- navigationbarのタイトル文字を変えたい
- NavigationControllerを持つViewControllerなら、
self.title
で変えれる
- NavigationControllerを持つViewControllerなら、
- navigationbarのタイトルの文字色を変えたい
self.navigationController?.navigationBar.titleTextAttributes = [NSForegroundColorAttributeName:UIColor.orangeColor()]
- なんでここだけObj-Cっぽいの
- navigationbarの背景色を変えたい
- UIView
- AutoLayoutを使いたい
- なんかConstraint追加ダイアログで
Equal Widths
とかが選択できないことがあった - 左側のViewのstructureが出る画面で、Ctrl+うにょーんで子供から親にひっぱると出てくるので、それで追加できる
- [iOS] storyboardのautolayoutでEqual WidthsとEqual Heightsがdisableで選択できないときの対処法 | はやとも工業所
- なんかConstraint追加ダイアログで
- 動的にSubviewを追加したい
- UIView継承クラスをつくって、
myParent.addSubview(child)
- Swift:UIButton を動的に生成する場合のサンプルコード | siro:chro
- UIView継承クラスをつくって、
- AutoLayoutを使いたい
- UIButton
- title Colorが変わらない
- アイコン付きUIButtonをつくりたい
btn.setImage
- UIButtonの画像(imageView)の左寄せ、右寄せ(alignment)の設定 - Qiita
- アイコンとタイトルの間隔をあけたい
btn.titleEdgeInsets = UIEdgeInsetsMake(0, 12, 0, 0)
- iphone - Aligning text and image on UIButton with imageEdgeInsets and titleEdgeInsets - Stack Overflow
- ios - UIButton titleEdgeInsets - Stack Overflow
- UIImageView
- URLから画像をロードしたい
- AlamofireImage使うのが無難
Alamofire.request(.GET, url).responseImage { response in self.imageView.image = UIImage(data: response.data) }
的な感じで
- UIImageViewを角丸にしたい
imageView.layer.cornerRadius = 30
- 画像の大きさを60x60とかにしとけば、真円になる
- UIに枠線、角丸を適用する - Qiita
- UIImageViewにアスペクト比を維持して画像をはめこみたい
imageView.contentMode = UIViewContentMode.ScaleAspectFit
- むしろこれUIViewのプロパティっぽいぞ
- UIImageViewのはみ出した部分は隠したい
imageView.clipsToBounds = true
- URLから画像をロードしたい
- その他の雑感メモ
- iOSっていうかXcodeいいわぁ...
- StoryboardからConstraintの指定と警告、非常に勉強になる
- Xcodeのいろんなペインがそれぞれ便利なので、Xcodeの使いかたを1日みっちり先達に教えてもらうといいかも
- HexからUIColorにするとき UI Color - Convert HEX & RGB colors to UIColor めっちゃ便利だった
- 誰も責任を取らない環境、俺がやるしかないので、自分との闘いに集中できて良い。脳が震える。
なにもしてないのにXcodeがこわれた: An error was encountered while running (Domain = LaunchServicesError, Code = 0)
- ios - Unable to run app in Simulator: An error was encountered while running (Domain = LaunchServicesError, Code = 0) - Stack Overflow
- ios - Installation Failed "Invalid argument" when trying to run Today application extension - Stack Overflow
なおった
- cmd + shift + k
- reset simulator settings
- remove from Xcode
rm -rf myproject git clone git@github.com:otiai10/myproject.git open myproject.xcworkspace
rm -rf
最強説
【追記】XCTAssertEqualが("foo bar") is not equal to ("foo bar")などと寝ぼけたことを言う【NSNumberFormatter】
問題
("Optional("10,00 €")") is not equal to ("Optional("10,00 €")"
とか言われてXCTAssertEqualがコケる。
調査
- Optionalとか
- 文字列型のポインタを比較してEqualじゃないよとか
- そういうのを予想してたけど、どうやら違う
- printしてみた出力をアサーションに使うとテストがパスする
- 文字コードか?ということで、Swiftで文字列→byte列の情報を漁る
原因
NSNumberFormatter
の.CurrencyStyle
で出力された10,00 €
のbyte列
[UInt8]("10,00 €".utf8) [49, 48, 44, 48, 48, 194, 160, 226, 130, 172]
一方、キーボードから入力した 10,00 €
のbyte列
[UInt8]("10,00 €".utf8) [49, 48, 44, 48, 48, 32, 226, 130, 172]
[49, 48, 44, 48, 48]
の部分は10,00
だと思われ、[226, 130, 172]
も共通なのできっと€
だと思うので、それをPlaygroundで以下のように確認
String(bytes: [194, 160], encoding: NSUTF8StringEncoding)// " " String(bytes: [32], encoding: NSUTF8StringEncoding)// " " String(bytes: [226, 130, 172], encoding: NSUTF8StringEncoding)// "€"
ということで、結論としては、
- キーボード入力のスペースは
[32]
- 一方
NSNumberFormatter
が吐いたスペースは[194, 160]
32は分かるんだけど、194,160って何の仕様だろうか
解決
とりあえずだけど、print
でNSUTF8StringEncoding
の出力をコピペしてテストコードに貼った。
雑感
- でも型があるの本当に気持ちいいです
- 8月第2週第3週は帰ります。おもにコミケのために。
追記
@otiai10 c2a0はnbspです。この罠おそろしい・・
— しゃある (@sharlm) 2016年7月29日
-   は半角スペースではないというお話 (フェンリル | デベロッパーズブログ)
- 文字列中の (C2A0) を正規表現で削除 - Qiita
- ソースコード中に0xC2A0(UTF-8のNO-BREAK SPACE)が混ざり実行できなくて困った話 - kk_Atakaの日記
- html - Problems with UTF-8 representation of nbsp in XML - Stack Overflow
- List of Unicode characters - Wikipedia, the free encyclopedia
- HTML Codes - Table of ascii characters and symbols
だいぶややこしそうだ... アプリケーションレイヤーに返す前にreplaceしといたほうがよさそうだと思った。あるいはNSNumberFormatterにそういうプロパティ無いか探してみる// TODO
DRYな備忘録として