【iOS11】UIToolbarの上に乗せたUIButtonやUITextViewのタップイベントが効かない
iOS11対応をしている時にハマったので記録として残しておく。
問題のコード
普通にtoobarの上にボタンを置いているだけ。
iOS10以下なら問題なくボタンのタップイベントを取得できるがiOS11だとボタンのタップが効かなくなる。
UIToolbar *toolBar = [[UIToolbar alloc]init]; [self.view addSubview:toolBar]; UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; [button setTitle:@"push" forState:UIControlStateNormal]; [toolBar addSubview:button]; toolBar.translatesAutoresizingMaskIntoConstraints = NO; [toolBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; [toolBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; [toolBar.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES; [toolBar.heightAnchor constraintEqualToConstant:50]; button.translatesAutoresizingMaskIntoConstraints = NO; [button.topAnchor constraintEqualToAnchor:toolBar.topAnchor].active = YES; [button.leadingAnchor constraintEqualToAnchor:toolBar.leadingAnchor].active = YES; [button.trailingAnchor constraintEqualToAnchor:toolBar.trailingAnchor].active = YES; [button.bottomAnchor constraintEqualToAnchor:toolBar.bottomAnchor].active = YES;
改善
toobarにaddSubViewする前に toobarに対して layoutIfNeededを呼んでやればいいみたい。 サブクラスにしている場合でも、クラス内でtoolbarにaddSubViewする前にlayoutIfNeededを呼べば良い。
ちなみにiOS10以下でlayoutIfNeededを呼んでいても特に問題はなかったのでiOS11用にコードを分岐する必要はなさそう。
toolbarのviewの階層を調べてみたが特に違いはなかったので単純にバグのような気がする。
素直にViewとかで代用した方がいいかもしれない。blur効果が欲しいならUIVisualEffectViewとか。
UIToolbar *toolBar = [[UIToolbar alloc]init]; [self.view addSubview:toolBar]; // 追記 [toolBar layoutIfNeeded]; UIButton *button = [UIButton buttonWithType:UIButtonTypeSystem]; [button setTitle:@"push" forState:UIControlStateNormal]; [toolBar addSubview:button]; toolBar.translatesAutoresizingMaskIntoConstraints = NO; [toolBar.leadingAnchor constraintEqualToAnchor:self.view.leadingAnchor].active = YES; [toolBar.trailingAnchor constraintEqualToAnchor:self.view.trailingAnchor].active = YES; [toolBar.bottomAnchor constraintEqualToAnchor:self.view.bottomAnchor].active = YES; [toolBar.heightAnchor constraintEqualToConstant:50]; button.translatesAutoresizingMaskIntoConstraints = NO; [button.topAnchor constraintEqualToAnchor:toolBar.topAnchor].active = YES; [button.leadingAnchor constraintEqualToAnchor:toolBar.leadingAnchor].active = YES; [button.trailingAnchor constraintEqualToAnchor:toolBar.trailingAnchor].active = YES; [button.bottomAnchor constraintEqualToAnchor:toolBar.bottomAnchor].active = YES;
一応Viewの階層をのせておく。
layoutIfNeededを呼んでいない時のToolbarのViewの階層
// iOS10.2 ( "<UIButton: 0x7feac8d84c20; frame = (0 0; 0 0); opaque = NO; layer = <CALayer: 0x608000423020>>" ) // iOS11.0.1 ( "<UIButton: 0x7ffc36443830; frame = (0 0; 0 0); opaque = NO; layer = <CALayer: 0x60000043e740>>" )
layoutIfNeededを呼んだ後のToolbarのViewの階層
なんか違ってて怖い。
// iOS10.2 ( "<_UIBarBackground: 0x7f9ff6e736d0; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <CALayer: 0x600000220740>>", "<UIButton: 0x7f9ff6e746a0; frame = (0 0; 0 0); opaque = NO; layer = <CALayer: 0x600000425ec0>>" ) // iOS11.0.1 ( "<_UIBarBackground: 0x7f8cc9c98f20; frame = (0 0; 0 0); userInteractionEnabled = NO; layer = <CALayer: 0x600000629da0>>", "<_UIToolbarContentView: 0x7f8cc9c9a090; frame = (0 0; 0 0); layer = <CALayer: 0x60000062a600>>", "<UIButton: 0x7f8cc9c9ce10; frame = (0 0; 0 0); opaque = NO; layer = <CALayer: 0x60000062b380>>" )
UITableViewをスクロールしている時にNSTimerが呼ばれない
UITableViewに限らずUIScrollViewを継承しているクラス全部に言えることだと思うが
以下のような処理だとスクロール中にタイマー処理がスキップされる
- (void)setupTimer { NSTimer *timer = [NSTimer timerWithTimeInterval:3.0 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES]; } - (void)timerUpdate { NSLog(@"timer呼ばれた"); }
改善コード
mainRunLoopにタイマーを追加してやれば良い
- (void)setupTimer { NSTimer *timer = [NSTimer timerWithTimeInterval:3.0 target:self selector:@selector(timerUpdate) userInfo:nil repeats:YES]; [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; } - (void)timerUpdate { NSLog(@"timer呼ばれた"); }
【Fastlane】deliverを使用してストア情報を更新する
環境
- Xcode 8.3.2
- Fastlane 2.45.0
前提条件
- bundlerを使用して
fastlane
をインストール
セットアップ
まずは以下のコマンドを実行して環境を整えます
bundle exec fastlane deliver init
Appfileに記述されているアカウント情報を確認しているようです。
確認出来ない場合は入力を促されると思います
確認される項目
- AppleId (メールアドレス)
- password (一度入力するとkeychainに保存される)
- Bundle Identifier
また、確認されたBundle Identifier
を使用して作成したストアページがない場合はエラーが出ます 。なので作ってない場合は先に作りましょう。
初期化後のディレクトリ構造の例
fastlane/ ┣ AppFile ┣ DeliverFile ┣ FastFile ┣ metadata ┣ copyright.txt ┣ en-US ┣ description.txt ┣ keywords.txt ┣ marketing_url.txt ┣ name.txt ┣ privacy_url.txt ┣ promotional_text.txt ┣ release_notes.txt ┣ subtitle.txt ┣ support_url.txt ┣ ja ┣ description.txt ┣ keywords.txt ┣ marketing_url.txt ┣ name.txt ┣ privacy_url.txt ┣ promotional_text.txt ┣ release_notes.txt ┣ subtitle.txt ┣ support_url.txt ┣ primary_category.txt ┣ primary_first_sub_category.txt ┣ primary_second_sub_category.txt ┣ review_information ┣ demo_password.txt ┣ demo_user.txt ┣ email_address.txt ┣ first_name.txt ┣ last_name.txt ┣ notes.txt ┣ phone_number.txt ┣ secondary_category.txt ┣ secondary_first_sub_category.txt ┣ secondary_second_sub_category.txt ┣ trade_representative_contact_information ┣ address_line1.txt ┣ address_line2.txt ┣ city_name.txt ┣ country.txt ┣ email_address.txt ┣ first_name.txt ┣ is_displayed_on_app_store.txt ┣ last_name.txt ┣ phone_number.txt ┣ postal_code.txt ┣ state.txt ┣ trade_name.txt ┣ screenshots ┣ en-US ┣ xxxxx.png ┣ README.txt
今のストアの状態をそのまま取ってきてくれるみたいなので、後から導入するのも楽そうです。
DeliverFile
DeliverFileに変更したい項目を記載してコマンドを叩きます。
DeliverFileの例
# リリースノート release_notes({ 'en-US' => "Try the new version", 'ja' => "新しいバージョンをお試し下さい" }) # アプリの説明 description({ 'en-US' => "English Description\nEnglish Description\nEnglish Description\n", 'ja' => "日本語の説明文\n日本語の説明文\n日本語の説明文\n" }) # キーワード keywords( 'en-US' => "Keyword1,Keyword2", 'ja' => "キーワード1,キーワード2" ) # HTMLで内容確認を行わない場合'true' # デフォルトは `false`なので内容確認のHTMLが表示されます # force true
こんな感じで変更したい項目を記述していきます。
まぁ後から入れた場合はほぼほぼ'release_notes'だけになると思いますが。。
変更したくない項目は記載しなければ大丈夫です。
以下のコマンドでDeliverFile
の内容でitunesConnectを更新します。
bundle exec fastlane deliver
現在のitunesConnectの情報にmetadata
配下を更新したい場合は以下のコマンドを実行します。
itunesConnectを更新したあと実行するといいと思います。
bundle exec fastlane deliver download_metadata
スクリーンショット
上記のようにscreenshots
配下におきます。
アップロードのルール
- 並び順はフォルダ内の順番と同じ
- サイズは自動判定されて適切な場所にアップロードされる (5.5インチとか4.7インチとかの話です)
名前の付け方で上手く運用できそう。
【Fastlane】The following build commands failed CopySwiftLibs エラーが出た時
ローカル環境では特に問題ないけど、ビルドマシンのmac-miniにsshでログインしてgymを実行したり mac-miniのjenkinsからgymを実行すると 以下エラー等が出て困った。
The following build commands failed:CopySwiftLibs
The following build commands failed:CodeSign
ビルドする端末のキーチェーンアクセスを開いて該当する証明書をログイン
ではなく、システム
に入れればいいみたい。
余談ですが、上記エラーと一緒に以下のエラーが出ていました。
[16:37:53]: [31mExit status: 65[0m [16:37:53]: [33m📋 For a more detailed error log, check the full log at:[0m [16:37:53]: [33m📋 /Users/yamanaka/Library/Logs/gym/MEME-Run-iOS-MEME-Run-iOS.log[0m [16:37:53]: [31mFound multiple versions of Xcode in '/Applications/'[0m [16:37:53]: [31mMake sure you selected the right version for your project[0m [16:37:53]: [31mThis build process was executed using '/Applications/Xcode.app'[0m [16:37:53]: [33mIf you want to update your Xcode path, either[0m [16:37:53]: [16:37:53]: - Specify the Xcode version in your Fastfile [16:37:53]: ▸ [35mxcversion(version: "8.1") # Selects Xcode 8.1.0[0m [16:37:53]: [16:37:53]: - Specify an absolute path to your Xcode installation in your Fastfile [16:37:53]: ▸ [35mxcode_select "/Applications/Xcode8.app"[0m [16:37:53]: [16:37:53]: - Manually update the path using [16:37:53]: ▸ [35msudo xcode-select -s /Applications/Xcode.app[0m [16:37:53]:
僕の環境だと端末内に複数バージョンのXcodeが入っていたため、上記エラーの通りXcodeの指定がちゃんとできていないと思ってこの辺りを中心に調査して盛大に時間をロスしました。(ビルドに使用するXcodeはxcode_select
アクションで指定できます。 )
xcode_select "/Applications/Xcode.app"
上記のアクションを実行するようにしてFastlaneのビルドログを見ると以下のように使用するXcodeのpathが がちゃんと指定されているのにも関わらず Xcode指定してくれエラーが出続けました。
+----------------------+-------------------------------------------------------------+ | Summary for gym 2.36.0 | +----------------------+-------------------------------------------------------------+ | scheme | Demo | | export_method | enterprise | | configuration | AdHoc | | use_legacy_build_api | false | | output_directory | ./fastlane/ipa/enterprise/ | | project | ./Demo.xcodeproj | | destination | generic/platform=iOS | | output_name | Demo | | build_path | /Users/xxxxxxx/Library/Developer/Xcode/Archives/2017-06-07 | | clean | false | | silent | false | | skip_package_ipa | false | | buildlog_path | ~/Library/Logs/gym | | xcode_path | /Applications/Xcode.app | +----------------------+-------------------------------------------------------------+
結局タイトルのエラーを解決したらこのXcode指定してくれエラーは消えて正常にビルドできるようになりました。
端末に複数バージョンXcodeが入っていて、かつThe following build commands failed
が出ている場合に一緒に上記のエラーが出ているような気がします。
このissuesとかもXcodeの指定の問題じゃなくてThe following build commands failed
エラーが出ていることが原因なんじゃないかなー。。
一枚のUIImageViewで画像の入れ替えアニメーションを行う
コードは以下の通りです
let transition = CATransition() transition.duration = 0.75 transition.type = kCATransitionFade self.myImageView.image = UIImage(named: "image2.png") self.myImageView.layer.add(transition, forKey: nil)
また以下のコードでアニメーションの終了タイミングを取得することができます
CATransaction.begin() CATransaction.setCompletionBlock({ // 終了時に呼ばれる }) let transition = CATransition() transition.duration = 0.75 transition.type = kCATransitionFade self.thumbnailImage.image = UIImage(named: "image2.png") self.thumbnailImage.layer.add(transition, forKey: nil) CATransaction.commit()
delegateも用意されている
class Myclass { func startAnimation() { let transition = CATransition() transition.duration = 0.75 transition.type = kCATransitionFade transition.delegate = self self.thumbnailImage.image = UIImage(named: "image2.png") self.thumbnailImage.layer.add(transition, forKey: nil) } } extension Myclass: CAAnimationDelegate { func animationDidStop(_ anim: CAAnimation, finished flag: Bool) { print("アニメーション終了") }
PHAssetからファイル名や拡張子を取得する
PHAssetからファイル名を取得しようとしたらちょっと苦労したのでメモ
PHAssetのメンバにはそれっぽいものがなかった。
結論を言うと
- Private Apiで取得
- PHImageManager経由で取得
上記のどちらかのようだ。
Private Apiで取得
// 'asset'は PHAssetのインスタンス let filename = asset.value(forKey: "filename")
PHImageManager経由で取得
PHImageManagerの関数の戻り値から取得できる
画像とビデオでそれぞれ取得方法が違った
// 'asset'は PHAssetのインスタンス switch asset.mediaType { case .image: let option = PHImageRequestOptions() option.deliveryMode = .highQualityFormat PHImageManager.default().requestImage(for: asset, targetSize: CGSize(width: asset.pixelWidth, height: asset.pixelHeight), contentMode: .aspectFill, options: option) { (image, info) in if let url = info?["PHImageFileURLKey"] as? URL { print(url.lastPathComponent) print(url.pathExtension) } } case .video: let option = PHVideoRequestOptions() option.deliveryMode = .highQualityFormat PHImageManager.default().requestAVAsset(forVideo: asset, options: option, resultHandler: { (avAsset, audioMix, info) in if let tokenStr = info?["PHImageFileSandboxExtensionTokenKey"] as? String { let tokenKeys = tokenStr.components(separatedBy: ";") let urlStr = tokenKeys.filter { $0.contains("/private/var/mobile/Media") }.first if let urlStr = urlStr { if let url = URL(string: urlStr) { print(url.lastPathComponent) print(url.pathExtension) } } } }) default: break }
Raspberry Pi3にCentOS7をインストール
どうやらRaspberry piにCentOSを入れることができるようなので 手順を残しておく。
必要なもの
- PC (mac想定)
- Raspberry pi3
- MicroSD (16GB以上あれば大丈夫だと思う)
- SDカードスロット (pcについてればそれでもいい)
- LANケーブル
- HDMIケーブル
- ACアダプタ
あったほうが便利 (なくてもルーターからローカルIPを調べれば sshで操作可能 )
- モニター
- USBキーボード
CentOSをインストールする
まずはRaspberry Pi3用のCentOS7をダウンロードする
https://wiki.centos.org/Download
上記リンクからダウンロードできる
リンク先からRaspberry Pi3用を探してダウンロードする
2017年2月現在では以下のファイル名
CentOS-Userland-7-armv7hl-Minimal-1611-RaspberryPi3.img.xz
ダウンロード後、上記を解凍する アプリを使ってもいいしコマンドでも可
コマンドの場合
#homebrewでインストールできる $brew install xz
#以下で解凍 xz -d CentOS-Userland-7-armv7hl-Minimal-1611-RaspberryPi3.img.xz
#マウントされてるMicroSDを調べる $diskutil list /dev/disk0 #: TYPE NAME SIZE IDENTIFIER 0: GUID_partition_scheme *121.3 GB disk0 1: EFI EFI 209.7 MB disk0s1 2: Apple_CoreStorage 120.5 GB disk0s2 3: Apple_Boot Recovery HD 650.1 MB disk0s3 /dev/disk1 #: TYPE NAME SIZE IDENTIFIER 0: Apple_HFS Macintosh HD *120.1 GB disk1 Logical Volume on disk0s2 2117A7C6-F20D-4E5F-92D2-0B352281C440 Unlocked Encrypted /dev/disk2 #: TYPE NAME SIZE IDENTIFIER 0: FDisk_partition_scheme *15.8 GB disk2 1: Windows_FAT_32 boot 66.1 MB disk2s1 2: Linux 15.7 GB disk2s2
#一旦アンマウントする (※`disk2s1`を指定) $diskutil umount /dev/disk2s1
#書き込む 結構時間かかるので待つ(※`disk2s1`ではなく`disk2`を指定) $sudo dd if=CentOS-Userland-7-armv7hl-Minimal-1611-RaspberryPi3.img of=/dev/disk2 bs=8192; sync 393216+0 records in 393216+0 records out 3221225472 bytes transferred in 1423.262396 secs (2263269 bytes/sec)
Rasberry pi の起動とログイン
MicroSDカードをセット。LANなどを差し込んで最後にACアダプタを差す
しばらく待つと起動するのでログインする
キーボード、モニターがない場合はローカルipを調べてsshでログインしても良い
#初期値は以下
login: root
password: centos
sshでログイン
# centosでipを調べる $ip a
#mac側でsshでログインする $ssh root@192.168.xxx password
タイムゾーンの設定
# タイムゾーンを`Asia/Tokyo`に変更する $timedatectl set-timezone Asia/Tokyo # 確認 $timedatectl status Local time: 日 2017-02-26 22:56:44 JST Universal time: 日 2017-02-26 13:56:44 UTC RTC time: n/a Time zone: Asia/Tokyo (JST, +0900) NTP enabled: yes NTP synchronized: yes RTC in local TZ: no DST active: n/a
Rootパーティションのサイズ拡張
デフォルトではSDカードの容量を全て使用していないため拡張する必要があるらしい
これについては root/README
に書いてある
# root/ 配下のREADME If you want to automatically resize your / partition, just type the following (as root user): /usr/local/bin/rootfs-expand For wifi on the rpi3, just proceed with those steps : curl --location https://github.com/RPi-Distro/firmware-nonfree/raw/master/brcm80211/brcm/brcmfmac43430-sdio.bin > /usr/lib/firmware/brcm/brcmfmac43430-sdio.bin curl --location https://github.com/RPi-Distro/firmware-nonfree/raw/master/brcm80211/brcm/brcmfmac43430-sdio.txt > /usr/lib/firmware/brcm/brcmfmac43430-sdio.txt systemctl reboot
# READMEに書いてある通りに以下を実行 $/usr/local/bin/rootfs-expand Extending partition 3 to max size .... /usr/bin/growpart: 行 170: シリンダ数*4、16*: 構文エラー: オペランドが予期されます (エラーのあるトークンは "シリンダ数*4、16*") Resizing ext4 filesystem ... resize2fs 1.42.9 (28-Dec-2013) The filesystem is already 524288 blocks long. Nothing to do! Done.
どうやらシェルのLANGの設定の問題らしい。
$locale LANG=ja_JP.UTF-8
上記のようになっていたら
$export LANG="en_US.UTF-8"
で変更。もう一度
$/usr/local/bin/rootfs-expand
終わったら戻しておく
$export LANG="ja_JP.UTF-8"
再起動した後に確認する
$reboot #拡張されているか確認 $df -h ファイルシス サイズ 使用 残り 使用% マウント位置 /dev/root 14G 2.4G 11G 19% / devtmpfs 459M 0 459M 0% /dev tmpfs 463M 0 463M 0% /dev/shm tmpfs 463M 12M 451M 3% /run tmpfs 463M 0 463M 0% /sys/fs/cgroup /dev/mmcblk0p1 500M 49M 452M 10% /boot tmpfs 93M 0 93M 0% /run/user/0
パッケージの更新
最後にyumを利用してシステムにインストールされているパッケージのバージョンアップを行う
$yum update -y