- 投稿日:2020-07-27T21:57:12+09:00
【厳選】これだけは覚えておきたいXcodeショートカットまとめ
コード編集
ショートカットキー 結果 Cmd + I インデント整理 Cmd + / コメントアウト Cmd + Click(※) 定義へ移動 Opt + Click Quick Help(リファレンス) Cmd + Ctr + E ファイル内変数のRename Cmd + Ctr + ← ジャンプ前のコードに戻る Cmd + Ctr + → 進む(上記の逆) Opt + ← 左の単語にカーソル移動 Opt + → 右の単語にカーソル移動 Cmd + [ インデントを下げる Cmd + ] インデントを上げる Cmd + ← カーソルを行頭へ移動 Cmd + → カーソルを行末へ移動 Ctrl + D 右の1文字削除 ※Cmd + Click で Jump to Definition を押せば、定義元に移動できます。
これが面倒な方は、上部メニュー Xcode > Preferences > Navigation > Command-clock on Coder を Jump to Definition に変更すれば、Cmd + Click するだけで、定義元に移動できます。
検索
ショートカットキー 結果 Cmd + Shift + O プロジェクト内検索 Cmd + F ファイル内検索 ウィンドウ・エリア
ショートカットキー 結果 Cmd + 0 ナビゲートエリア表示 Cmd + Opt + 0 ユーティリティーエリア表示 Cmd + Shift + y デバッグエリア表示 Cmd + Opt + Ctr + Return アシスタントエディタ表示/非表示 実行・ビルド・デバッグ
ショートカットキー 結果 Cmd + R 実行 Cmd + B ビルド Cmd + Shift + K クリーンビルド Cmd + . 停止 Cmd + \ ブレイクポイント設定/解除 Cmd + Ctr + Y ブレイクポイントで止まった処理をコンテニュー F6 ステップオーバー F7 ステップイン シミュレータ
ショートカットキー 結果 Cmd + Shift + H ホーム Cmd + L ロック Cmd + ← 反時計回りに回転 Cmd + → 時計回りに回転 Cmd + Ctr + Z 振る Cmd + K キーボード表示/非表示 Cmd + Shift + K Macのキーボードから入力 Cmd + S スクリーンショット 参考記事
- 投稿日:2020-07-27T21:50:43+09:00
Swiftメソッド内nameを間違えた時の対処方
Swiftでitemなどをドラック アンド ドロップし,UIパーツとプログラムを関連付けした後nameなど間違った場合の対処方
例えば
コード上部にエラーが発生している。
エラー文は Use of unresolved identifier 'timerSettingPicker'
未解決の識別子 'timerSetting' の使用と言ってます。
現状私が直面してるエラーは、言い方変えればtimerSettingPickerなんて無いですよと言われています。
おかしいと思いPickerと関連付けしたコードを確認しました。
timerSettingPickerとしたいのに、timeSettingPickerとしてしまっていました。rをつけ忘れてしまった。
一度関連付けをしてしまったらコードを書き直すだけでは解決できません。
対処方は
①まず、コードを削除します。関連付けを削除@IBOutlet weak var timeSettingPicker: UIPickerView!
の行を全て削除②
写真のように、黄色の部分(control)にカーソルを合わせ、キーボードでcontrolを押しながらタップすると
図のような画面になります。
その中に、三角の形をした黄色いマーク部分が先ほど関連付けを削除した部分です。
関連付けが無効な場合は黄色の三角マークが出ます。③後は、×マークをクリックすれば、完全に関連付けを削除できます。
④再度UIパーツをドラックアンドドロップし、name部分を書き換えればエラーは解除されます。
##説明がわかりずらく申し訳ありません。
- 投稿日:2020-07-27T21:28:16+09:00
【Swift】スコープについて
スコープの種類
スコープは以下の2種類に分類することができる
・ ローカルスコープ
・ グローバルスコープローカルスコープ
if
やfor
などの制御構文や関数内で定義されるスコープ
制御構文や関数内などで定義された定数・変数はその外部から使用することができない制御構文の例
if true { // hoge関数内で定数a、変数bを宣言 let a = 100 var b = 200 } print(a) // エラー! print(b) // エラー!上記の様に、制御構文内で定義された(= ローカルスコープ)定数や変数を関数外で使用することはできない
if true { // hoge関数内で定数a、変数bを宣言 let a = 100 var b = 200 print(a) // -> 100 print(b) // -> 200 }上記の様に、関数内であれば使用することができる
関数の例
func hoge() { // hoge関数内で定数a、変数bを宣言 let a = 100 var b = 200 } print(a) // エラー! print(b) // エラー!上記の様に、関数内で定義された(= ローカルスコープ)定数や変数を関数外で使用することはできない
func hoge() { // hoge関数内で定数a、変数bを宣言 let a = 100 var b = 200 print(a) print(b) } hoge() // -> 100 // 200上記の様に、関数内であれば使用することができる
グローバルスコープ
制御構文や関数など、どの範囲にも含まれないスコープ
let a = 100 var b = 200 if true { print(a) // -> 100 print(b) // -> 200 } func hoge() { print(a) print(b) } print(a) // -> 100 print(b) // -> 200 hoge() // -> 100 // 200上記の様に、どこからでも使用することができる
どこからでも使用できるグローバルスコープは便利である反面、意図しない変更が生じるリスクがあるので使用する際は注意が必要
- 投稿日:2020-07-27T16:37:38+09:00
SwiftでUIViewにグラデーションを付ける方法
はじめに
SwiftでUIViewにグラデーションを付ける方法をまとめました。
対象バージョン
- Xcode ver.11.6
- Simulater ver.13.6
- iOS ver 13.5.1
デフォルト(上から下)
let gradientLayer = CAGradientLayer() // グラデーションレイヤーの領域をviewと同じに設定 gradientLayer.frame = self.frame // グラデーション開始色 let topColor = UIColor(red: 0.0, green: 0.0, blue: 0.73, alpha: 0.1).cgColor // グラデーション終了色 let bottopColor = UIColor(red: 0.0, green: 0.20, blue: 0.40, alpha: 1).cgColor let gradientColors: [CGColor] = [topColor, bottopColor] gradientLayer.colors = gradientColors // ビューにグラデーションレイヤーを追加 layer.insertSublayer(gradientLayer, at:0)startPointとendPointを変更することでグラデーションの向きを変更
左から右
let gradientLayer = CAGradientLayer() // グラデーションレイヤーの領域をviewと同じに設定 gradientLayer.frame = self.frame // グラデーション開始色 let topColor = UIColor(red: 0.0, green: 0.0, blue: 0.73, alpha: 0.1).cgColor // グラデーション終了色 let bottopColor = UIColor(red: 0.0, green: 0.20, blue: 0.40, alpha: 1).cgColor let gradientColors: [CGColor] = [topColor, bottopColor] gradientLayer.colors = gradientColors gradientLayer.startPoint = CGPoint.init(x: 0, y: 0) gradientLayer.endPoint = CGPoint.init(x: 1, y: 0) // ビューにグラデーションレイヤーを追加 layer.insertSublayer(gradientLayer, at:0)左上から右下
let gradientLayer = CAGradientLayer() // グラデーションレイヤーの領域をviewと同じに設定 gradientLayer.frame = self.frame // グラデーション開始色 let topColor = UIColor(red: 0.0, green: 0.0, blue: 0.73, alpha: 0.1).cgColor // グラデーション終了色 let bottopColor = UIColor(red: 0.0, green: 0.20, blue: 0.40, alpha: 1).cgColor let gradientColors: [CGColor] = [topColor, bottopColor] gradientLayer.colors = gradientColors gradientLayer.startPoint = CGPoint.init(x: 0, y: 0) gradientLayer.endPoint = CGPoint.init(x: 1, y: 1) // ビューにグラデーションレイヤーを追加 layer.insertSublayer(gradientLayer, at:0)まとめ
Viewのサイズとグラデーションのサイズが異なる場合は適時frameを調整すれば、
一部でけグラデーションを適用することも可能なようです。
グラデーションのcolorsプロパティも配列になっているので2色以外も設定して使用できるのかなと思います。
- 投稿日:2020-07-27T14:26:15+09:00
Raspberry Pi で Swift を使えるようにする【Swift 5】
本記事は Qrunch とのクロス投稿です。
Raspberry Pi で Swift を使えるようにする【Swift 5】 | Qrunch(クランチ)
Raspberry Pi に Swift をインストールし、「Hello, world!」を出力するまでをやってみます。
環境
Mac にインストールした Visual Studio Code で Raspberry Pi 3 Model B にSSH 接続。
Mac 側の環境
- MacBook Pro (Retina, 15-inch, Late 2013)
- macOS Catalina バージョン 10.15.6(19G73)
- Visual Studio Code バージョン: 1.47.2
- コミット: 17299e413d5590b14ab0340ea477cdd86ff13daf
- 日付: 2020-07-15T18:18:50.054Z
- Electron: 7.3.2
- Chrome: 78.0.3904.130
- Node.js: 12.8.1
- V8: 7.8.279.23-electron.0
- OS: Darwin x64 19.6.0
Raspberry Pi 側の環境
- Raspberry Pi 3 Model B
$ cat /etc/issue Raspbian GNU/Linux 9 \n \l $ cat /etc/debian_version 9.11 $ uname -a Linux raspberrypi 4.19.66-v7+ #1253 SMP Thu Aug 15 11:49:46 BST 2019 armv7l GNU/Linux $ cat /proc/version Linux version 4.19.66-v7+ (dom@buildbot) (gcc version 4.9.3 (crosstool-NG crosstool-ng-1.22.0-88-g8460611)) #1253 SMP Thu Aug 15 11:49:46 BST 2019 $ bash --version GNU bash, バージョン 4.4.12(1)-release (arm-unknown-linux-gnueabihf)Swift-Arm の入手
Swift-Arm を入手します。以下のスクリプトで OS の判別、curl のチェック、gpg のチェック等が行われ、Swift-Arm がインストールされます。
$ curl -s https://packagecloud.io/install/repositories/swift-arm/release/script.deb.sh | sudo bashSwift のインストール
$ sudo apt-get install swift5必要なパッケージも一緒にインストールされます。
インストールした Swift のバージョンを確認
$ swift --version Swift version 5.1.5 (swift-5.1.5-RELEASE) Target: armv6-unknown-linux-gnueabihf無事に Swift をインストールできました?
ディレクトリと初期ファイルの作成
今回は
SwiftPractice
というディレクトリを作成します。swift package
で初期ファイルたちを作成します。$ mkdir SwiftPractice $ cd SwiftPractice $ swift package init --type executable生成された
main.swift
にはprint("Hello, world!")
と書かれています。ビルドと実行
ビルドして実行します。
$ swift build [4/4] Linking SwiftPractice $ swift run Hello, world!ビルドに成功し、正しく「Hello, world!」が出力されました???
参考資料
- 投稿日:2020-07-27T13:10:17+09:00
SwiftUIでローディング画像を表示するメモ
はじめに
これは僕が使いたくなるかもしれないコードを書いたメモです。
ローディング画像表示View
import SwiftUI // ローディングを表示します。 struct LoadingView: View { @State private var isAnimating = false private let animation = Animation.linear(duration: 1).repeatForever(autoreverses: false) // 画像を表示する場合はこちらを使う。 // @State private var index = 0 // private let images:[UIImage] = { UIImage.loadImages(path: "Images/Loading") }() // private var timer = LoadingTimer(0.05) var body: some View { GeometryReader { geometry in ZStack { // 他のタップを許さないようにする。 Color(.black) .opacity(0.01) .frame(width: geometry.size.width, height: geometry.size.height) .edgesIgnoringSafeArea(.all) Circle() .trim(from: 0, to: 0.6) .stroke(AngularGradient(gradient: Gradient(colors: [.gray, .white]), center: .center), style: StrokeStyle( lineWidth: 8, lineCap: .round, dash: [0.1, 16], dashPhase: 8)) .frame(width: 48, height: 48) .rotationEffect(.degrees(self.isAnimating ? 360 : 0)) .onAppear() { withAnimation(Animation.linear(duration: 1).repeatForever(autoreverses: false)) { self.isAnimating = true } } .onDisappear() { self.isAnimating = false } // アニメーションを表示する。 // Image(uiImage: self.images[self.index]) // .resizable() // .frame(width: 100, height: 100, alignment: .center) // .onReceive( // self.timer.publisher, // perform: { _ in // self.index = self.index + 1 // if self.index >= self.images.count { self.index = 0 } // } // ) // .onAppear { self.timer.start() } // .onDisappear { self.timer.cancel() } } } } } struct LoadingView_Previews: PreviewProvider { static var previews: some View { LoadingView() } }import Foundation // ロード状態を表示します。 class Loading: ObservableObject { static private var instance:Loading? @Published var isShow:Bool = false init() { // インスタンスを保持しておく Loading.instance = self } static func show() { Loading.instance?.isShow = true } static func hide() { Loading.instance?.isShow = false } }使い方
struct ContentView: View { // ローディング表示用 @ObservedObject var loading = Loading() var body: some View { ZStack { // コンテンツ表示 // ローディング表示 if loading.isShow { LoadingView() } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView().environmentObject(User()) } }// これでローディングが表示される。 Loading.show()本当はこうしたかった。
まぁ、今回はここまでしなくても良かったので・・・。
var body: some View { ZStack { // コンテンツ表示 }.loading(isShow: $loading.isShow) }
- 投稿日:2020-07-27T11:59:20+09:00
【iOS】 ReactorKitでStoryboardを使う方法
経緯
ReactorKitを使っているプロジェクトでStoryboardでレイアウトした画面を表示させたら画面に何も表示されなかったので原因を調べてみた
対応方法
最初はbind内でloadView()を呼んでViewの生成を行っていたがStoryboardを使っているのにloadView()を呼びたくないとおもい公式ドキュメントを調べてみたらそれ用のプロトコルが用意されていた
func bind(reactor: Reactor) { loadView() }以下のようにStoryboardViewプロトコルを使用するとViewの生成が行われ画面が表示された
class MyViewController: UIViewController, StoryboardView { func bind(reactor: MyViewReactor) { // this is called after the view is loaded (viewDidLoad) } }
- 投稿日:2020-07-27T11:52:31+09:00
遷移先でdismissした後に画面更新したい場合
iOS13からModalで画面遷移をする際にフルスクリーンではなくシート型に変更になりました。この場合、UIとしては格好いい(スワイプで閉じられる)のですが、遷移元の画面更新をviewWillAppearでやっていた場合、iOS13では呼ばれなくなりました。
対応策
遷移先のViewControllerのなかで下記のメソッドを呼んでやる必要があります。iOS12で呼ぶと二重で実行されてしまうので、実行をiOS13以上にしてやる必要があります。
override func viewWillAppear(_ animated: Bool) { if #available(iOS 13.0, *) { presentingViewController?.beginAppearanceTransition(false, animated: animated) } super.viewWillAppear(animated) } override func viewWillDisappear(_ animated: Bool) { super.viewWillDisappear(animated) if #available(iOS 13.0, *) { presentingViewController?.beginAppearanceTransition(true, animated: animated) presentingViewController?.endAppearanceTransition() } } override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) if #available(iOS 13.0, *) { presentingViewController?.endAppearanceTransition() } }
- 投稿日:2020-07-27T11:41:06+09:00
Swift でショートムービ(動画)を再生する
はじめに
AVPlayer を使って動画を再生できるように実装していきます。
より詳細な情報は下記で載せました。動画を表示するためのクラス作成
まずは動画を再生するために、
AVPlayerLayer
をlayerClass
とする UIView のサブクラスを
作成していきます。class VideoPlayerView: UIView { private var playerLayer: AVPlayerLayer? { return layer as? AVPlayerLayer } // Override UIView property override static var layerClass: AnyClass { return AVPlayerLayer.self } }
VideoPlayerView
に Property を追加基本的には動画の制御に必要な API は
AVPlayer
が全て持ってます。
isPlaying
に関してはAVPlayer
に特にそれっぽい API が無かったのでプロパティを追加しま
した。class VideoPlayerView: UIView { private(set) var player: AVPlayer? { get { return playerLayer?.player } set { playerLayer?.player = newValue } } var isPlaying: Bool { guard let player = player else { return false } return player.rate != 0 && player.error == nil } private var playerLayer: AVPlayerLayer? { return layer as? AVPlayerLayer } // Override UIView property override static var layerClass: AnyClass { return AVPlayerLayer.self } func setPlayer(player: AVPlayer) { self.player = player } }再生してみる
// 再生 videoPlayerView.player?.play() // 一時停止 videoPlayerView.player?.pause()
- 投稿日:2020-07-27T10:18:43+09:00
Swiftリンク集
AutoLayout で UIButton の image が拡大しない
https://ofsilvers.hateblo.jp/entry/uibutton-image-expansionUICollectionViewでSelfSizingを行う
https://qiita.com/y__n/items/7fdecc425427ca628ba8
- 投稿日:2020-07-27T03:12:02+09:00
実はiOSのWebView内のHTTPSリクエストは傍受できる(URLProtocol)
Chromeの開発ツールにはnetworkという項目があり,ブラウザでサイトにアクセスしたときのHTTP/HTTPSのアクセスのログを見ることができます.APIの動作確認などできるので,Web開発者なら重宝している機能の一つだと思います.
とても便利な機能なので,iOSのWKWebViewでも使えたらいいなと思い開発しました.
下記の動画が作ったサンプルなのですが,アプリ内のWKWebViewでGithubにアクセスしたときのHTTPSリクエストすべてをTableViewに表示できるようになっています.
こちらが今回作成したサンプルのレポジトリです.
https://github.com/tommy19970714/WebKitURLProtocol
これはログを表示するだけですが,この技術を応用する例としては,WKWebView上で開いているyahooのホームページ内にある画像をすべて猫の画像にすり替えるChrome Extensionのようなこともできます.
他に事例がないか調べたのですが,通信デバックライブラリのnetfoxやWormholyは非推奨になったUIWebViewのパケットキャプチャはできるようです.WKWebViewに対してパケットキャプチャしている事例はどこにもなかったので今回書くことにしました.
本記事ではURLProtocolについて解説します.ただURLProtocolを普通に使うだけでは,すべてのHTTPSリクエストを見ることはできません.ちょっとした裏技を使ったらできるようになるので,それについて解説します.
よくよく考えたら,SNSやニュースアプリなどアプリ内でブラウザを開くことのできるアプリは多くありますが,ユーザがそのブラウザを使ってアクセスしたログ(SNSのログイン情報や決済情報も含めて)をユーザの許可なく保存できてしまいます.なので悪用はしないでください.
URLProtocolとは
iOSではインターネット通信を行う際に
URL Loading System
というものを使っています.
HTTP/HTTPSなど通信プロトコルを使ってURLで特定されるWebサイトや画像等のリソースに非同期でアクセスするための仕組みのことです.URL Loding Systemについて詳しく知りたい方は公式のドキュメントがあります.
https://developer.apple.com/documentation/foundation/url_loading_systemURLProtocolとは
URL Loading System
の通信に使われるインターフェイスで,ネットワーク通信を開始しリクエストを送ってレスポンスを受け取るプロトコルです.
基本的にURLProtocolはデバック時のAPI通信のモックに使用できます.サーバのAPIが出来上がっていないけど,クライアントのiOS側も先に作りたいという場合に,URLProtocolを使うと実際の通信をインターセプトして戻り値を自由に設定できます.今回はHTTPSすべてのリクエストをインターセプトできるように,カスタマイズしたURLProtocolを作っていきます.
カスタマイズしたURLProtocolを作る
URLProtocolはサブクラス化することで実装できます.URLProtocolのサブクラスにするには下記の5つのoverrideメソッドを組み込む必要があります.
組み込むにあたってそれぞれのメソッドの簡単な説明を示します.class CustomURLProtocol: URLProtocol { override class func canInit(with request: URLRequest) -> Bool // このURLProtocolが引数に渡されるrequestを扱う必要があるかを判断します.trueにするとこのURLProtocolでインターセプトできます. override open class func canInit(with task: URLSessionTask) -> Bool // このURLProtocolが引数に渡されるtaskを扱う必要があるかを判断します.trueにするとこのURLProtocolでインターセプトできます. override func startLoading() // リクエストのロードが開始したときに呼び出されます. override func stopLoading() // リクエストの読み込みが終了するときに呼び出されます. open override class func canonicalRequest(for request: URLRequest) -> URLRequest // リクエストで送られたURLRequestにヘッダーをカスタマイズできます.特に何もする必要がなければ引数のrequestをそのまま返します. }最初に見せたサンプルのようにアクセスした先のURLを知るには,
canInit
メソッドのURLRequest
かURLSessionTask
内を見れば良いです.サンプルではcanInit
が呼ばれたときにURLSessionTask
の中身をtableviewに表示しています.そしてカスタマイズしたURLProtocolは次のようにして,登録できます.
URLProtocol.registerClass(CustomURLProtocol.self)CustomURLProtocolを登録をしたら.WKWebViewでページが移動する度に,それぞれのoverrideメソッドが呼ばれるようになります.
ただ今の段階だと,ページ移動時したときのURLしか分からないので,これからすべてのHTTPSリクエストに反応できるように設定していきます.URLProtocolのschemeを設定する
URLProtocol関連で調べていたら,たまたま次のレポジトリを発見しました.
https://github.com/Yeatse/NSURLProtocol-WebKitSupport
そのレポジトリではObjective-cでURLProtocolのAppleのドキュメントに載っていない非公開APIについて記述してありました.そのAPIはURLProtocolのトリガーとしてのschemeを設定できるようです.つまり,schemeとして「https」を設定したら,httpsから始まるリクエストにアクセスする度にURLProtocolを呼び出すというトリガーを設定できるということです.それをswiftに書き換えたのが下記のコードです.
extension URLProtocol { class func contextControllerClass()->AnyClass { return NSClassFromString("WKBrowsingContextController")! } class func registerSchemeSelector()->Selector { return NSSelectorFromString("registerSchemeForCustomProtocol:") } class func unregisterSchemeSelector()->Selector { return NSSelectorFromString("unregisterSchemeForCustomProtocol:") } class func wk_register(scheme:String){ let cls:AnyClass = contextControllerClass() let sel = registerSchemeSelector() if cls.responds(to: sel) { _ = (cls as AnyObject).perform(sel, with: scheme) } } class func wk_unregister(scheme:String){ let cls:AnyClass = contextControllerClass() let sel = unregisterSchemeSelector() if cls.responds(to: sel) { _ = (cls as AnyObject).perform(sel, with: scheme) } } }上記のURLProtocol Extensionを使用すると,次のようにURLProtocolのトリガーのSchemeを設定できます.
URLProtocol.wk_register(scheme: "https") URLProtocol.wk_register(scheme: "http")上記のコードを実行することで,https/httpのすべてのリクエストが呼ばれた際に先ほど登録したカスタムURLProtocolが呼ばれるようになります.
まとめ
この記事では,次の二段階ですべてのHTTP/HTTPSリクエストをパケットキャプチャできるようにしました.
1. カスタマイズしたURLProtocolを作る
2. URLProtocolのschemeを設定する
今回はたまたま発見した非公開APIを使用したやり方になっているため,推奨できません.あくまで開発のデバックの一つとして使用してください.
審査に通るかどうかは別にして,パケットキャプチャして得たURLを元にWebView上で見ている動画をダウンロードするツールとかは,この技術を使用して作れるかもしれないですね.
もしこの記事を見たAppleのレビュワーさんがいたら,この非公開APIの審査を厳しくしたほうが良さそうです.追記
海外のセキュリティの専門家がこの脆弱性(非公開API)を利用して,脱獄せずに他のアプリのHTTP/HTTPSリクエストを傍受する方法を指摘している記事を見つけました.
どうやって他のアプリを傍受するかというと,今回のコードをライブラリとして書き出してしまって,端末内のアプリのディレクトリに直接入れるだけとのことです.なぜそんなことができてしまうかというと,アプリ内で一度URLProtocolを登録してしまうと,必ずURLProtocolが呼ばれてしまうというstaticな設計になっているためです.これは設計を変えたほうが良さそうです.書きながら思ったのですが,もしこれをmacOSで同じことができてしまうのなら,結構大きなセキュリティホールになるのではと思ってしまいました.今度,macOSでも他のアプリの通信内容を傍受できてしまうのかを実験してみたいと思います.medium - Let’s write Swift code to intercept SSL Pinning HTTPS Requests
Network Interception - Write Swift codes to inspect network requests (even with SSL Pinning active)参考文献
netfox: URLProtocolを実装する際に参考にしました
【Swift】URLProtocolという名のclassについて: URLProtocolについて説明する際に参考にしました.