- 投稿日:2020-03-05T22:40:23+09:00
Xcode10から11にあげたらBitriseでbuildできなくなった。
この記事の解決方法の対象
- iOS13対応を終えてBitriseのbuild環境をXcode10からXcode11にあげた
- Mac Catalystは対応しない
- xcodebuildコマンドで以下のエラーが出る
xcodebuild: error: Failed to build workspace "workspace_name" with scheme "scheme_name". Reason: The run destination My Mac is not valid for Archiving the scheme "scheme_name".原因
Xcode11からの追加機能のMac CatalystのBuild Settingsのフラグを未設定だったためBuild DeviceがMy Macに設定されてしまったことが原因です。
解決方法
Build Settingsで
Support Mac Catalyst = NO
を設定をします。
(未設定の場合、検索して開くだけで設定値が入ります)Build Settings > Mac Catalyst - Deployment > Setting > Support Mac Catalyst
あとがき
プロジェクトでは関係ない機能や要素の追加でもBuild Settingsの変更は大きな影響があることがあるので気をつけないといけないなと、久々に時間も使ってしまったこともあり同じトラブルにあった方の助けになれば!
- 投稿日:2020-03-05T22:10:12+09:00
iOS13.3.1の環境で実機テストするとLibrary not loaded が表示される件について
こんにちは。
先日、外部フレームワークを使ったアプリで実機テストしようとしたら、真っ黒な画面になってしまい、少々ハマってしまったので記事を書きます。
同じことが起きてる人がいたら参考にして欲しいです。環境
Xcode11.3.1
iOS(実機)13.3.1解決すべき問題
Firebaseなどの外部ライブラリをCocoaPodsで導入したアプリを実機にインストールすると、「Library not loaded」となって、画面が真っ黒くなるという問題。なお、シュミレーターでは普通に動く。
原因
iOS13.3.1から、Appleは無料のアカウントで外部フレームワークを使用することをブロックしたらしいです、、、
僕は試してないんですが、有料版にアップグレードすると動くらしいです。解決するためにやったこと
とりあえずエラーをコピペして検索してみた。そしたら、上の原因に書いたことが影響しているってことは分かったのですが、じゃあ1万円払って有料のデベロッパーアカウントを作成するのもなんか悔しい。
それで色々調べた結果、無料アカウントでも外部フレームワーク使える方法がありました。
それは、Podfileのuse_frameworks!をuse_modular_headers!に変更するという方法です。こんな感じに、、、
# Uncomment the next line to define a global platform for your project # platform :ios, '9.0' target 'AppName' do # Comment the next line if you don't want to use dynamic frameworks # use_frameworks! use_modular_headers! # Pods for AppName pod 'Firebase' pod 'Firebase/Analytics' endここでは、use_frameworks!をコメントアウトしています。
もし、せっかく作ったアプリが動かなくて困っている方がいたら参考にしていただければと思います。
参考にしたサイト
- 投稿日:2020-03-05T18:24:24+09:00
[swift]カスタムメニュー、ハンバーガーメニューで使いたい表示方法 備忘録
- 投稿日:2020-03-05T17:52:57+09:00
[Swift] コードで書くUIView、 ボタンを押すと画面遷移 備忘録
override func viewDidLoad() { super.viewDidLoad() Button() } func Button() -> UIView?{ let button = UIButton(frame: CGRect(x:self.view.frame.maxX - 50, y:0, width:50, height: 50)) button.backgroundColor = UIColor.black button.setTitle("追加", for: .normal) //追加ボタンがタップされた際に画面遷移をする(buttonTappedはタップされた際に呼び出される関数) button.addTarget(self, action: #selector(ViewController.buttonTapped(sender:)), for: .touchUpInside) view.addSubview(button) return view } @objc func buttonTapped(sender:UIButton){ let storyboard: UIStoryboard = self.storyboard! let second = storyboard.instantiateViewController(withIdentifier: "secondView") self.present(second, animated: true, completion: nil) }以上
- 投稿日:2020-03-05T10:36:05+09:00
【Swift】Navigation Controllerをコードで実装する
Storyboardでいうところの、以下のようなNavigation Controllerをコードで実装する方法をご紹介します
まず、UINavigationControllerを継承したクラスを作成します
NavigationController.swiftclass NavigationController: UINavigationController { override func viewDidLoad() { super.viewDidLoad() } }AppDelegateに以下のように記述します
AppDelegate.swiftclass AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { let nav = NavigationController() let vc = ViewController() nav.viewControllers = [vc] //NavigationControllerをrootViewに設定する window?.rootViewController = nav window?.makeKeyAndVisible() return true } }
- 投稿日:2020-03-05T10:30:58+09:00
SwiftUIのViewは自分のサイズを自分で決めます
もと(英語)→ https://netsplit.com/swiftui/views-choose-their-own-sizes/ 外国人なので日本語がおかしいところがあれば是非教えてください。SwiftUIの紹介記事などでだいたい最初に書かれるのは「ビューは自分で自分のサイズを決め、一回決められたサイズは上書きできません」とのことですが、こんな簡単そうなことでも以外と複雑な闇を隠しています。なぜならその簡単そうな宣言が我らの知っているレイアウトについての全ての常識を変えるのです。
SwiftUIはUIKitやAppKitの考え方とは違いますしメリットとデメリットもありますので時間をかけてちゃんと勉強する価値はあると思います。なのでこの記事ではたくさんのレイアウトの土台になるビューの2つ(ImageとText)を見ながら宣言の深い意味を考えてみましょう。
Images
まず画像を表示しましょう:
struct ContentView : View { var body: some View { Image("barbarian") } }ソース画像のサイズ(解像度)は
101px x 92px
なので表示される画像も同じサイズになって、画面の真ん中に表示されます。見やすいため記事のスクショは全部ボーダー付きにしました。
画像のボーダーは全部「赤色」
デバイスのボーダーは「グレー」
フレームのボーダーは「緑色」
テキストのボーダーは「黄色」
他の記事でSwiftUIのボーダーについて書きますがとりあえず今回はビューのバウンドを見やすくするために使用し、コードからは抜きます。
.frame
modifierを使うと画像をフレームの中に入れることができます。struct ContentView : View { var body: some View { Image("barbarian") .frame(width: 200, height: 200) } }UIKit, AppKitなどだとこれは意外な結果ですよね?
画像を拡大するのじゃなくて、画像は同じサイズそのままフレームの真ん中にドンと置いてあるだけです。
結局のところ、
.frame
は使用されたビューのプロパティーを変更せず指定されたサイズで新しく "frame" というビューを作成し使用されたビューがその新しいフレームのチャイルドとして追加されます。ポイント!!
.frame
は使用されたビューのプロパティーを変更せず指定されたサイズで新しく "frame" というビューを作成し使用されたビューがその新しいフレームのチャイルドとして追加されます。これがSwiftUIの基礎的なところなのでちゃんと理解をした方がいいんじゃないかなと思います。
.frame
みたいなmodifierは新しくビューを作成し元のビューが新しいビューにチャイルドとして追加されます。Imageのサイズが画像アセットだけを元に選ばれます。親ビューがそれを上書きできません。
シンプルなデモとして小さすぎるフレームに画像をぶち込んでみましょう。
struct ContentView : View { var body: some View { Image("barbarian") .frame(width: 50, height: 200) } }多分これだと画像が必ずリサイズされる!かと思うのは普通ですが、SwiftUIだと画像がフレームをオーバーフローするだけです。
重ねられるビューを作る時、これは使えますね。
ですが、.clipped
や.cornerRadius
みたいな、画像を切り取るmodifierを使うとフレームのバウンドを元に画像を切り取ることは可能です。が、長くなるのでこの記事では詳しくは書かないことにします。あとでまた画像に戻りますがここで他に確認するべきところがありますので一旦
Text
をみてみましょう。Text
さっきのレイアウトを画像じゃなくてキャラクターの名前の文字列にしてみましょう。
struct ContentView : View { var body: some View { Text("Nogitsune Takeshi") } }画像と同じように画面の真ん中に文章が表示されています。Textも文字がちゃんと入るサイズを自分で決めました。そして
.frame
も同じように使うことはできます。struct ContentView : View { var body: some View { Text("Nogitsune Takeshi") .frame(width: 200, height: 200) } }
.frame
がもう1つの新しいビューを作ることを知っているとTextが前と同じく真ん中に置いてあることに驚きはないと思います。Textはサイズ選びに設定は色々ありますよ。例えば
.font
でフォントを選べます。ヒーローの名前なので.title
にしましょう。struct ContentView : View { var body: some View { Text("Nogitsune Takeshi") .font(.title) } }フォントが大きくなったので前よりテキストが大きくなっています。
画像の対応と完全に同じにするため大きくなったTextを小さすぎるフレームにぶち込んでみます。
struct ContentView : View { var body: some View { Text("Nogitsune Takeshi") .font(.title) .frame(width: 200, height: 200) } }似たコードで画像のサイズを全く変更せずにフレームをオーバーフローしてしまったが、Textだと
.font
でサイズの変更できましたしこれの結果は違うのかな?!オーバーフローせず、ちゃんとフィットするサイズを選ぶことはできたらしい。この場合だとコンテンツを2行に分け、横幅の広さを抑えて縦幅を大きくしました。
これは「親ビューは決まったサイズを上書きできない」とのことを矛盾しない。ただまだ勉強していないもう1つの原則を表す→ ビューが自分のサイズを決める前に親から「提案」をもらいます。
ポイント!!ビューが自分のサイズを決める前に親から「提案」をもらいます。
ちなみに「親が子に渡す提案サイズ」と「親が決める自分(親)のサイズ」は別物です。大体、親は子ビューを元に自分のサイズを選びますので。
Flexible Frames
は複雑なので、他の記事でもう少し詳しく書きます。提案サイズについて
前の例で、サイズを決めてビューが設置された手順の理解がSwiftUIの理解の鍵になります。Textが自分のサイズを決めて、そのサイズを上書き不可能。だがTextは親から渡されたサイズをもとに自分のサイズを柔軟に選べます。
Frameを
200 x 200
のサイズを指定したのでTextを設置する準備が終えた後にTextに提案サイズとして自分のサイズを渡し、その後フレームが、チャイルドになっているTextに自分のサイズを決めろと頼みます。Frameがない例でデバイスのバウンドがTextに提案サイズを渡しました。
Frameがある例で提案された横幅(width)が足りなかったが縦幅(height)に十分のスペースがあったのでコンテンツを2行に分けたら収まることができます。
Textは親が渡した提案サイズを元に自分のコンテンツの最適な表示方法を決めてそのように表示してるのです!
普段は決められたサイズが提案サイズより小さいのがいいです、コンテンツが丁度入るぐらいの大きさ。んで、親から渡された提案サイズが大ぎるとしても自分がそのサイズに合わせて大きくなること基本的にないです。
それに、上の例のように提案サイズのwidthをそのまま選ぶじゃなくて、2行になった文字列が入るの、提案より小さいサイズになりました。Frameよりは小さいのでTextをFrameの真ん中に設置されることになりました。
ImageがFrameより大きい場合のようにTextがFrameより縦が大きい時も同じようなことが起きます。
struct ContentView : View { var body: some View { Text("Nogitsune Takeshi") .frame(width: 200, height: 10) } }ImageがFrameをオーバーフローするしTextもオーバーフローしちゃいます。
テキストの切り捨て
サイズを柔軟に選ぶのに数行に分けるのはTextのたった1つの選択ではありません。文字と文字の間のスペースを小さくすることもでき、コンテンツを切り捨てることもできます。こうやって切り捨て機能を確認できます →
struct ContentView : View { var body: some View { Text("Nogitsune Takeshi") .font(.title) .lineLimit(1) .frame(width: 200, height: 200) } }
.lineLimit
を使ったことによって前の無限行数ではなく1行に収まるように命令しましたので、提案サイズが足りないときはTextが違うやり方でコンテンツを抑えてサイズを選ばないといけない。1行で文字列の横幅をフィットすることができず、数行使うこともできないのでTextが文字列を切り捨てて自分の横幅を減らすようにしてます。もう一度、選ばれた横幅はコンテンツが丁度入るくらいのサイズで親ビュー(Frame)の真ん中にポンと置かれています。
縦幅が足りない時でも切り捨てが起きることがあります。
struct ContentView : View { var body: some View { Text("Nogitsune Takeshi") .font(.title) .frame(width: 200, height: 50) } }行数が限られてないとしても提案サイズの縦幅が1行しか入らないのでこの例でコンテンツが提案サイズに合わせてます。
リサイズ可能な画像
ビューが自分のサイズを選ぶときに柔軟に選べることはわかった上でもう一度Imageを見てみましょう。
普段Imageは画像ファイルの解像度のサイズになりますが、リサイズすることもできます。
struct ContentView : View { var body: some View { Image("barbarian") .resizable() .frame(width: 200, height: 150) } }リサイズ可能なImage(リサイザブル)は親ビューからもらった提案サイズそのまま選んでできるだけスペースを埋むようにします。
デフォルトでImageは画像を伸ばしてスペースを埋むけど
.resizable(resizingMode: .tile)
を使うと画像をリピートすることができます。struct ContentView : View { var body: some View { Image("barbarian") .resizable(resizingMode: .tile) .frame(width: 200, height: 150) } }ImageのサイズはまだFrameからもらった提案サイズのままなのですが、単に画像を複数回描画しているだけに注意。
アプリつくっているとき、画像を伸ばすのも複数描画のも違う単純に「変に伸ばさずこのサイズで一番大きいサイズで画像を表示したい」だけの時が多いと思いますが、その時は
.aspectRatio
という便利なmodifierもあります。.aspectRatio
を.resizable
と一緒に使うことでアスペクト比変わらずリサイズをすることが可能になります。Modifierの順番
複数なmodifierを使うときは順番は重要です。各modifierがそのmodifierが使われたビューに適応されるのでSwiftUIのmodifierは逆の順番に書かれるのです。
ポイント!!SwiftUIのmodifierは逆の順番に書かれるのです。
ソース画像のアスペクト比で正しくframeのサイズに合わせたImageを作るのに以下の順番でmodifierを書く必要があります。
struct ContentView : View { var body: some View { Image("barbarian") .resizable() .aspectRatio(contentMode: .fit) .frame(width: 200, height: 150) } }このコードでは
.resizable
はImageに追加されました。ってことはImageは.resizable
のチャイルドになります。.frame
と同じように。そのあとは第2のmodifier、
.aspectRatio
を追加することによってaspectRatioは「リサイザブル画像」に適応されて、「リサイザブル画像にアスペクト比を適応する」という流れなので、modifierチェーンの最後に追加します。そして最後に「アスペクト比を使うリサイザブル画像」をframeに打ち込みたいので最後に
.frame
を追加。大事なポイントはチェーンの最後にframeは来てますがビューの構成ではframeは一番最初のビューになります。そしてそれで正しく表示できます→
ソース画像と親ビューの提案サイズを参考にして、
Image
が親が渡したheightを使おうとしましたが、元画像のheightが足りないので元画像のサイズを大きくしてheightを選び、アスペクト比が変わらないためのwidthを計算して選んで、サイズを決定しました。親の横幅が大きすぎて子ビューが全部使わないので真ん中に置くことになりました。
こういったルールを理解した上で複数ビューをstackで合体することやflexible frameの奇妙なケースなどを確認できるでしょう!
Imagery used in previews by Kaiseto, original images and derived here licensed under Creative Commons 3.0 BY-NC-SA.
- 投稿日:2020-03-05T01:38:51+09:00
【Swift】Firebaseのuser.photoURLをカメラロールの画像をアップして設定する
カメラロール(ローカルファイル)から写真をピックし、ローカルのURLを指定してStorageにアップロード。その際のDownloadURLをuser.photoURLに指定してやる。
import UIKit import Firebase import FirebaseDatabase import FirebaseStorage class EditProfileViewController: UIViewController, UIImagePickerControllerDelegate, UINavigationControllerDelegate { var user: User! var ref: DatabaseReference! // private var databaseHandle: DatabaseHandle! // var storage: Storage! var storageRef: StorageReference! var localImageURL: NSURL? @IBAction func uploadImageButtonDidTap(_ sender: Any) { let ipc = UIImagePickerController() ipc.delegate = self self.present(ipc, animated:true, completion:nil) } func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) { picker.dismiss(animated: true, completion: nil); self.profileImageView.image = info[UIImagePickerController.InfoKey.originalImage] as? UIImage self.localImageURL = info[UIImagePickerController.InfoKey.imageURL] as? NSURL } @IBAction func saveDidTap(_ sender: Any) { let changeRequest = user.createProfileChangeRequest() guard let imageURL = localImageURL else { return } let localFile = imageURL as URL // ここは公式ドキュメントに揃えただけなので別に変数化しなくていい let imageRef = storageRef.child("user/\(user.uid)/images/profile.jpg") _ = imageRef.putFile(from: localFile, metadata: nil) { metadata, error in guard let metadata = metadata else { // Uh-oh, an error occurred! return } // Metadata contains file metadata such as size, content-type. let size = metadata.size // You can also access to download URL after upload. imageRef.downloadURL { (url, error) in guard let downloadURL = url else { // Uh-oh, an error occurred! return } changeRequest.photoURL = downloadURL changeRequest.commitChanges() { (error) in self.dismiss(animated: true, completion: nil) } } } } }https://firebase.google.com/docs/storage/ios/create-reference?hl=ja
https://firebase.google.com/docs/auth/ios/manage-users?hl=ja#update_a_users_profile
https://stackoverflow.com/questions/40177250/firebase-how-to-get-image-url-from-firebase-storage