20200322のSwiftに関する記事は11件です。

SwiftUI の Property Wrappers

Property Wrappers

SwiftUIのpropertyWrapperの前に、そもそもpropertyWrapperとは何かを説明させてください。
変数をラッピングして、アクセス(get/set)を制御するための仕組みです。
簡単な例を見てみましょう。

@propertyWrapper
struct HelloWorld {
    private var text: String
    init() {
        text = ""
    }
    var wrappedValue: String {
        get { return text }
        set {
            if newValue == "世界" {
                text = "こんにちは, \(newValue)!"
                return
            }
            text = "Hello, \(newValue)!"
        }
    }
}

クラスや構造体、enumに@peopertyWrapperをつけることで定義できます。
定義したら、それを以下のように変数に適用することができます。

@HelloWorld var name: String

nameに何らかの値をセットすると、"Hello, (name)!"という値に変換してセットされるようになります。日本語で"世界"とセットしたときだけ、"こんにちは, 世界!"となるようにしてみました。

wrappedValue

propertyWrapperはラッピングした値を返す変数であるwrappedValueを実装する必要があります。この値のget/setで、ラッピングした値を変更したりします。
SwiftUI PropertyWrappers1.png

projectedValue

追加でprojectedValueという変数を実装することもできます。ラッピングした値の状態を示したり、wrappedValueに関するなんらかの情報を返すことができます。外からこの値にアクセスするには$を頭につけなければいけません。例えば、

@propertyWrapper
struct HelloWorld {
    var projectedValue: Bool
    init() {
        projectedValue = false
    }
    var wrappedValue {
        // ... get ..
        set {
            if newValue == "世界" {
                text = "こんにちは, \(newValue)!"
                projectedValue = true
                return
            }
            text = "Hello, \(newValue)!"
            projectedValue = false
        }
    }
}

とすると、$nameで、Bool値が返ります。

class Hello {

    @HelloWorld(text: "Hello, World!") var str: String

    func sayHello() {
        print(str)        // Hello, World!
        print("\($str)")  // false
        str = "世界"
        print(str)        // こんにちは, 世界!
        print("\($str)")  // true
    }
}

「世界」という値をセットしたときだけ、projectedValuetrueになるようにしています。
このようにprojectedValueを使ってwrappedValueの追加情報(投影値?)を返すことができます。

SwiftUI の propertyWrapper

以降はSwiftUIで定義されたpropertyWrapperについてみていこうと思います。

State

SwiftUIのviewは構造体(値)のため、変更不可です。ですが、変数に@Stateをつけると、その変数に変更が入ったら自動でviewを再構築してくれます。なのでviewで変更する必要があるものは@Stateをつけます。

struct GreetingView: View {
    @State var message: String = ""

    var body: some View {
        VStack {
            Text(message)
        }
    }
}

StateprojecteValueとして、後述するBindingを返します。上記の例だと、 $message で、StringBindingでラップした値を返してくれます。
SwiftUI PropertyWrappers2.png

Binding

双方向データバインディングというやつです。Bindingの値を変更すると、その情報源(変数)に、値の変更を反映してくれます。逆に情報源を更新すれば、Bindingから取得できる値も更新されています。

StateprojectedValue($)は、自身の値と結びつくBindingを返してくれるので、自身の値を更新してほしいときに渡します。

struct GreetingView: View {
    @State var message: String = "ボタンは押さないでね★"

    var body: some View {
        VStack {
            Text(message)
            // Bindingする例
            GreetingButton(message: $message)
            // Bindingしない例
            StateGreetingButton(message: message)
        }
    }
}

struct GreetingButton: View {
    @Binding var message: String

    var body: some View {
        Button(action: {
            self.message = "ボタン...押しましたね..."
        }) {
            Text("絶対に押すな!")
        }
    }
}

struct StateGreetingButton: View {
    @State var messageState: String

    var body: some View {
        Button(action: {
            self.messageState = "Bindingではないです"
        }) {
            Text("押してもいいですよ")
        }
    }
}

GreetingButtonで、Bindingであるmessageを更新すると、情報源であるGreetingViewmessageに変更が反映されます。
SwiftUI PropertyWrappers3.png
しかし、StateGreetingButtonのボタンを押して、messageStateを変更しても、情報源であるGreetingView.messageには反映されません。

もう一つの例をあげると、Toggleの引数isOnBindingを渡しますよね。これは、Toggle自身がisOnに渡したBindingの情報源を変更するためです。

@State var onOff: Bool = true

var body: some View {
    Toggle(isOn: $onOff) {
        Text("情報源(var onOff)の値を変えますよ: \(onOff.description)")
    }
}

ObservedObject

ObservedObjectObservableObjectを実装したクラスをwrappedValueとして持ちます。

struct PlayerViewView: View {

    @ObservedObject var user: PlayerViewModel = PlayerViewModel()

    var body: some View {
        VStack {

            Text("あなたは \(user.age) 歳です")

            Button(action: {
                self.user.haveBirthday()
            }) {
                Text("何歳ですか?")
            }
        }
    }
}

final class PlayerViewModel: ObservableObject {
    private(set) var age: Int = 0 {
        willSet {
            objectWillChange.send()
        }
    }

    func haveBirthday() {
        age += 1
    }
}

上記の例だと、ボタンを押すたびに、PlayerViewPlayerViewModelの変更が通知され、viewが更新されます。
データフローは@Stateと変わらないのですが、@ObservedObjectの場合は、wrappedValueObservableObjectのオブジェクトでないといけない、という点が異なります。

ObservableObject

ObservableObjectCombineフレームワークに含まれるプロトコルです。オブジェクトの変更を通知できることを表します。objectWillChangeというPublisher(変更イベントの発行元)を持っており、これを購読していれば、ObservableObjectの変更を検知できます。
ObservableObjectが自身に変更が入った、ということを通知するには、以下のようにobjectWillChange.send()を実行します。

class SomeObservableObject: ObservableObject {
    var hello: String {
        willSet {
            // ObservableObjectに適合するクラスは objectWillChangeを持っている
            objectWillChange.send()
        }
    }    
}

以下のように購読すれば、変更が入ったことを検知できます。

class Hoge {
    var cancellable: AnyCancellable?
    init() {
        cancellable = someObservalbeObject.objectWillChange.sink { _ in
            // objectWillChange.send() が呼ばれた!
        }
    }
}

@ObservedObjectのpropertyWrapperを使うと、SwiftUIがObservableObjectを購読し、変更が入るたびにviewを更新してくれます。
SwiftUI PropertyWrappers4.png

Published

SwiftUIではなく、Combineで定義されたpropertyWrapperですが、ObservableObjectでよく使われるので説明します。
変数に@Publishedを付与すると、その変数のprojectedValueは自身の変更を通知する Publisher を返してくれます。

class Dog {
    @Published var name: String = "Pero"
    private var cancellable: AnyCancellable?

    init() {
        self.cancellable = $name.sink { newName in
            print("あなたの名前: \(newName)")
        }
    }
}

let dog = Dog()   // あなたの名前: Pero
dog.name = "John" // あなたの名前: John
dog.name = "Taro" // あなたの名前: Taro

sink で購読し、値の変更を監視しています。変更が入るたびにログ出力しています。

ObservableObjectというプロトコルに適合したクラスで、@Publishedの変数を持っている場合、それに対して変更すると、ObservableObjectの変更を自動で通知してくれます。

class Dog: ObservableObject {
    @Published var name: String = "Pero"
    private var cancellable: AnyCancellable?

    init() {
        self.cancellable = objectWillChange.sink {
            print("名前、変わりましたね...")
        }
    }
}

let dog = Dog()
dog.name = "John" // 名前、変わりましたね...

なので、@Publishedを使えば、自前でwillSetにてobjectWillChange.send()なんて書かずによいので楽です。

EnvironmentObject

ObservableObjectを子ビューでも使いまわしたい場合は、@ObservedObjectではなく、@EnvironmentObjectを使用します。

struct ContentView: View {

    @EnvironmentObject var setting: PlayerSettings

    var body: some View {
        VStack {
            Text("あなたの通知設定: \(setting.isNotificationEnable.description)")
            SubView()
        }
    }
}

struct SubView: View {

    @EnvironmentObject var setting: PlayerSettings

    var body: some View {
        VStack {
            Button(action: {
                self.setting.isNotificationEnable.toggle()
            }) {
                Text("通知設定を変更")
            }
        }
    }
}

/// View間で共有するオブジェクト
final class PlayerSettings: ObservableObject {

    @Published var isNotificationEnable: Bool = false
}

上記の例だと、SubViewsettingは親View(ContentView)のsettingが自動でインジェクトされます。なので、子View側で、変更したら、親Viewにも反映されます。

ただし、最初に@EnvironmentObjectを使用しているViewの生成時に、オブジェクトを生成して渡す必要があります。渡さないとクラッシュします。

let contentView = ContentView().environmentObject(PlayerSettings())

もう一つ注意する点は、sheetなどで表示した親子関係でない別のViewには自動でインジェクトされないということです。共有したい場合は、明示的に渡す必要があります。

struct ContentView: View {

    @EnvironmentObject var setting: PlayerSettings

    @State var showModal: Bool = false

    var body: some View {
        VStack {

            Text("あなたの通知設定: \(setting.isNotificationEnable.description)")

            Button(action: {
                self.showModal = true
            }) {
                Text("べつのがめん")
            }.sheet(isPresented: $showModal) {
                // 親子関係でないViewでも共有したい場合は、明示的に渡す必要がある
                SubView().environmentObject(self.setting)
            }
        }
    }
}

Environment

SwiftUIで定義されたViewの設定値を取得することができます。

struct SubView: View {
    @Environment(\.isEnabled) var enable: Bool

    var body: some View {
        VStack {
            Text("活性状態? \(enable.description)")
        }
    }
}

例えば上記画面の表示時に、以下のようにdisabled(true)とすれば、@Environment(\.isEnabled)falseになります。

SubView().disabled(true)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Swift】クロージャの中に書く[weak self] はじめからていねいに

はじめに

少し前に業務の中でクロージャを丁寧に実装する必要があり、その際に調べたものを文字残して、しっかりとまとめておこうと思いました。この記述が必要である理由を説明するには色々な知識が必要になりますが、この記事の結論を1行でまとめると

[weak self]と記述することでクロージャがselfを弱参照し、強参照による循環を防ぐ

になります。以下で順を追ってこのテーマについてまとめます。

強参照の循環

強参照とは

強参照 (strong reference)とはあるオブジェクトが他のオブジェクトを参照する際のデフォルトの参照方法です。Swiftでは、ARC (Auto Reference Counting) と呼ばれる仕組みで、オブジェクトが他のオブジェクトから参照されている数 (参照カウント)を記憶して、メモリ領域内のオブジェクトの管理を行います。オブジェクトの参照カウントが1以上の場合はそのオブジェクトは破棄されず、参照カウントが0になったとき、ガベージコレクションの要領でそのオブジェクトは破棄されます。

Swiftにおいて、あるオブジェクトが他のオブジェクトを参照した場合、参照した側は参照された側を強参照で参照したものとして処理されます。そして、ARCでは強参照で参照されたとき、そのオブジェクトの参照カウントは1として計上されます。

class Hoge {}
var h: Hoge? = Hoge() //(1)
h = nil //(2)

【Swift】クロージャの中に書く[weak self] はじめからていねいに.002

強参照の循環

他のプログラミング言語でも起こりうるように、Swiftでも参照型のオブジェクト同士では強参照による循環 (strong reference cycle)が起こり得ます。

class Hoge {
  var fuga: Fuga?
}

class Fuga {
    var hoge: Hoge?
}

var h: Hoge? = Hoge()
var f: Fuga? = Fuga()

//(1)
h.fuga = f
f.hoge = h

//(2)
h = nil
f = nil

このような循環参照が発生した場合、Hoge()Fuga()のは参照カウントが1になったまま、各インスタンスへ変数からアクセスができなくない状態になったため、それぞれのインスタンスが解放されない状態となってしまっているのがわかります。

【Swift】クロージャの中に書く[weak self] はじめからていねいに.003

クロージャで起こりうる循環参照

上記のような循環参照はクロージャとあるクラスのインスタンスの間でも起こり得ます。この記事のタイトルにもなっている[weak self]はクロージャの中に記述するキャプチャリストの記法の1つです。以下の例を見てください。

class Hoge {
    private var closure: (() -> Void)?
    private var count = 0

    init() {
        closure = createClosure()
    }

    func createClosure() -> (() -> Void) {
        return { [self] in self.count += 1 }
    }
}

var h: Hoge? = Hoge() //(1)
h = nil //(2)

この例を実行した場合、hogeが生成された時点でイニシャライザ内部でcreateClosure()が呼び出され、クロージャ{ [self] in self.count += 1 }のインスタンスが生成され、プロパティclosureに格納され1self→クロージャへの参照が発生します。そして、このクロージャは内部でselfを参照しているため、クロージャ→selfへの強参照が発生します。すると、hと内部で生成されるクロージャのインスタンスは互いに強参照で参照しあっているため、参照の循環が発生していることがわかります。

【Swift】クロージャの中に書く[weak self] はじめからていねいに.004

弱参照による解決

上記の問題を解決するために、参照型のインスタンスを参照する際にSwiftでは強参照ではなく、弱参照(weak reference)という方法でインスタンスを参照する方法があります。弱参照による参照を受けた場合、ARCの参照カウントには含まれず、他のオブジェクトから参照されながらであってもメモリ領域を解放することができます。

これをクロージャのキャプチャリストに適用すると、記事のタイトルにある[weak self]の記法になります。これにより、先に説明したクロージャとインスタンスの強循環参照を無くし、インスタンスを解放することができるようになります。したがって、冒頭でも提示したように[weak self]とすることによって、[weak self]と記述することでクロージャがselfを弱参照し、強参照による循環を防ぐということになっています。

class Hoge {
    private var closure: (() -> Void)?
    private var count = 0

    init() {
        closure = createClosure()
    }

    func createClosure() -> (() -> Void) {
        return { [weak self] in self.count += 1 }
    }
}

var h: Hoge? = Hoge() //(1)
h = nil //(2)

【Swift】クロージャの中に書く[weak self] はじめからていねいに.005

参考


  1. 前投稿でも言及したようにSwiftのクロージャは参照型のオブジェクトなので、厳密には参照が渡されます。 

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「画面遷移で画面が浮く」を解決

開発環境

Xcode: Version 11.3.1
記事記入時: 2020/03/22

解決したい問題

・以前までは,画面遷移がうまくできていたのに!
・動画等,教材通りにならない!

スクリーンショット 2020-03-22 19.31.48.png

↑のように画面遷移を実装した際に,
遷移後の画面が浮いたみたいになってる......

ViewController.swift
override func viewWillAppear(_ animated: Bool) {
        ~
        ~
    }

が正常に作動しない.

解決方法

画面遷移では
・「control」+ドラッグ
・Present Modally
で実装する場合について書いていこうと思います!

この際に,Transitionを指定してやることで解決できました.

まずは,storyboard上のsegueを選択します.
そして,右の野球ベースみたいなところを選択すると,
PresentationSame As Destinationになってるかと思います.
このデフォルト設定を Full Screen にしてやることで無事解決しました!

スクリーンショット 2020-03-22 19.32.24.png

すると!

スクリーンショット 2020-03-22 19.32.31.png


そして,,,

ViewController.swift
override func viewWillAppear(_ animated: Bool) {
        ~
        ~
    }

が作動しない問題も,Presentationがデフォルトだと画面が遷移してない状態なので,作動していなかったのです!
PresentationをFull Screenにすることでこの問題も無事解決しました!
スクリーンショット 2020-03-22 19.32.47.png

これで無事画面遷移を実装できましたね!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「画面遷移で画面が浮く」を解決(swift_xcode)

開発環境

Xcode: Version 11.3.1
記事記入時: 2020/03/22

解決したい問題

・以前のバージョンまでは,画面遷移がうまくできていたのに!
・動画・記事等,教材通りにならない!

スクリーンショット 2020-03-22 19.31.48.png

↑のように画面遷移を実装した際に,
遷移後の画面が浮いたみたいになってる......

ViewController.swift
override func viewWillAppear(_ animated: Bool) {
        //code記述
    }

が正常に作動しない.

解決方法

画面遷移では
・「control」+ドラッグ
・Present Modally
で実装する場合について書いていこうと思います!

この際に,Transitionを指定してやることで解決できました.

まずは,storyboard上のsegueを選択します.
そして,右の野球ベースみたいなところを選択すると,
PresentationSame As Destinationになってるかと思います.
このデフォルト設定を Full Screen にしてやることで無事解決しました!

https___qiita-image-store.s3.ap-northeast-1.amazonaws.com_0_550611_4b48be95-79b1-cd7f-cb32-468217fe097f.png

すると!

スクリーンショット 2020-03-22 19.32.31.png

見事,画面遷移後もスクリーンがきれいになりました!


そして,,,

ViewController.swift
override func viewWillAppear(_ animated: Bool) {
        //機能
    }

が作動しない問題も,Presentationがデフォルトだと画面が遷移してない状態なので,作動していなかったのです!
PresentationをFull Screenにすることでこの問題も無事解決しました!
スクリーンショット 2020-03-22 19.32.47.png

これで無事画面遷移を実装できましたね!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Swiftで簡単なコードを書いてみた(初心者向け)

はじめに

アプリ開発に最近興味を持ち始めSwiftについて勉強したことのアウトプットとして書きました
初心者向けの簡単な文法や記述方法について触れています

Swiftって?

誰もが圧倒的に優れたアプリケーションを作れる、パワフルなオープンソースの言語です(Appleサイトより)

主に下記アプリの基幹言語として使用されています
・iPhoneアプリ
・OSXアプリ
・Apple Watchアプリ
・tvOSアプリ

環境構築

WindowsやLinuxでもSwiftは動かすことは出来ますが、やはりMacを使用するのが適しています
また、実際に開発を行うのは「XCode」というソフトを使用します

詳しくは下記サイトで環境構築をしてみてください
XcodeとSwiftを使ってアプリ開発を体験してみよう

実装

681E9860-93E4-4D46-B44A-1322FFA9FF9F.jpeg

Xcodeをインストール後、以下の画面が表示されるので、今回はplaygroudを使用していきます

playgroudは名の通り、遊び場のように作ってはすぐに実装の確認をすることが出来ます

Single Viewを選択し適当な名前を付けます

[実行画面]
02A67201-011F-466A-9B8C-6B00AA1E9CD2.jpeg

初期の起動時に、自動的にHello Worldを出力するソースがあるので、とりあえず実行してみました

実装の確認を同一の画面で確認出来ることが分かると思います

簡単な記述方法

それでは簡単なコードをSwiftで記述していきます

1.文字の出力

print("Hello Swift")

//実行結果
//Hello Swift

と記述することでテキスト出力します(改行あり)
Java等に比べると、シンプルに記述可能です

2.if文

var num = 1

if num < 10 {
    print("10より小さい値です")
}else{
    print("10より大きい値です")
}

//実行結果
//10より小さい値です

varで変数を定義し、if文で判定を行っています
ちなみに、変数numにカーソルを当てQuick Helpというツールを使うと自動的に変数の型を明示してくれます。これも便利ですね
BFC8C3F9-DD17-4A0D-8724-AAAC0C5FA983_4_5005_c.jpeg

3.for文

for n in 1...5 {
    print(n)
}

//実行結果
//1
//2
//3
//4
//5

1から5までの繰り返しを記述します
こちらも独特な書き方ですが、分かりやすいです

4.while文

var cnt = 0
var sum = 0

while cnt < 5{
    cnt += 1
    sum += cnt
}
print("cnt:\(cnt)")
print("sum:\(sum)")

//実行結果
//cnt:5
//sum:15

終わりに

ここまで読んで頂きありがとうございました
今回は簡単なSwiftの記述方法に触れましたが、他の言語と比べ書き方が相違する所はありますが、簡略して書けるのではと思います
これからもSwiftについて勉強していこうと思います

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

How to show view controller in full screen

Q:
when I open a view controller in following way, it don't be shown in full screen

let viewController = UIViewController()
present(viewController, animated: true, completion: nil)

A:

just add the following code.

let viewController = UIViewController()

viewController.modalPresentationStyle = .fullScreen

present(viewController, animated: true, completion: nil)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift] Class-only Protocolは": class"じゃなくて": AnyObject"で宣言することに慣れましょう

概要

本記事の前提環境:Swift 5.1

ちょっと今さら感があるネタですが。。。

Class-only Protocolは、
↓こうじゃなくて

protocol MyDelegate: class {
}

↓こう宣言しましょう、という話題です。

protocol MyDelegate: AnyObject {
}

私なりに知ってはいたのですがメンバーに理由をうまく説明できなかったので、今さらながら整理してみました。

前置き

Xcodeでこのような実装をするとエラーになるので、こういう実装はできないのだな、ということにすぐに気づくと思います。

protocol MyDelegate {
}

class MyClass {
  weak var delegate: MyDelegate?
}

weakは循環参照を避けるために「弱参照にします」というキーワードであって、参照型の変数じゃないと意味がないため、myDelegateを参照型だけに適用できるような宣言をしないとダメですよ、という訳です。

本題

Swift 3までは、このような↓書き方をしていました。

protocol MyDelegate: class {
}

Swift 4で、SE-0156という提案に基づいて、AnyObjectが導入されました。
以降は、こちら↓の書き方が推奨となっています。

protocol MyDelegate: AnyObject {
}

参考:Swift Documentation – Class-only Protocols

SE-0156の背景と意図は私には完璧に読み取り難いですが、AnyObjectとは「参照型全般」という意味を明確にしたモノ、という理解です。

参考:SwiftのAnyObjectとAnyについて

Swift 4以降、classは後方互換のためにAnyObjectのtypealias(別名)として残っている状態です。

結論

Swift 5.1現在では、: classで宣言してもエラーになりませんし警告も出ません。
また、ビルドや実行時に遅くなるということもないようです。

ただし、SE-0156には以下のような記述もあり、将来はdeprecatedとして警告が発生する可能性があります。

Later, class could be removed in a subsequent version of Swift.

このため、コードに: classを見かけたら、: AnyObjectにリファクタリングしておいた方が良さそうです。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[iOS] [Xcode] WKWebViewで位置情報を取得するコンテンツをloadする

前提環境

  • Xcode 11.3
  • Swift 5.1

info.plistの設定

ユーザーから位置情報取得の許諾を得るための設定
スクリーンショット 2020-03-21 11.19.33.png

許諾アラートを日本語にする設定
スクリーンショット 2020-03-21 10.57.42.png
スクリーンショット 2020-03-21 10.58.11.png

謎の挙動

許諾アラートで「OK」をtapして、WKWebViewをいったん閉じて、再度WKWebViewを開いてもまた許諾アラートが表示されます。
2回目の「OK」で記憶されて、3回目は表示されなくなるようです。
この挙動の原因と回避方法は謎です。。。どなたかご存知でしたら教えてください。

注意点

Xcode 11.3で新規作成したプロジェクトでは、コンテンツが位置情報を取得しようとした際にコンソールに以下のログが出力されてクラッシュします。

*** Terminating app due to uncaught exception 'NSObjectNotAvailableException',
reason: 'UIAlertView is deprecated and unavailable for UIScene based applications,
please use UIAlertController!'

許諾アラートが表示されるタイミングで、Xcode 11で新規にプロジェクトを作成した時のデフォルトである「scene baseアプリケーション」の場合にクラッシュしてしまうようです。

許諾アラートはアプリ側で実装している訳ではないので、どうやらSDKのバグっぽい雰囲気です。
Xcode 11.3現在では、window baseアプリケーションにするしかなさそうです。

1.SceneDelegate.swiftをファイルごと削除

2.AppDelegate.swiftを修正

import UIKit

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    var window: UIWindow? // この行を追加

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.
        return true
    }

// ここから下を削除
//    // MARK: UISceneSession Lifecycle
//
//    func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
//        // Called when a new scene session is being created.
//        // Use this method to select a configuration to create the new scene with.
//        return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
//    }
//
//    func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
//        // Called when the user discards a scene session.
//        // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
//        // Use this method to release any resources that were specific to the discarded scenes, as they will not return.
//    }

}

3.info.plistから"Application Scene Manifestを削除
スクリーンショット 2020-03-21 10.43.12.png

この件については、Xcodeがバージョンアップされたら再確認しようと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Delagateを用いたキーボードの閉じ方

TextFieldを開いた時に展開されるキーボードを、余白のタッチやリターンキー(キーボードの左下にある)を押して閉じる方法。

全体像

qiita.rb
import UIKit

class ViewController: UIViewController,UITextFieldDelegate {
    @IBOutlet weak var logoImageView: UIImageView!
    @IBOutlet weak var userNameTextField: UITextField!
    @IBOutlet weak var passWordTextField: UITextField!
    @IBOutlet weak var userNameLabel: UILabel!
    @IBOutlet weak var passWordLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        //以下二つのテキストフィールドに、returnでキーボードを閉じることができるメソッドが入ったクラスを設定する = Delegate
        //よって、これらに対応したキーボードのみ、returnで閉じることができる
        userNameTextField.delegate = self
        passWordTextField.delegate = self

    }

    @IBAction func login(_ sender: Any) {

        logoImageView.image = UIImage(named: "loginOK")

        userNameLabel.text = userNameTextField.text
        passWordLabel.text = passWordTextField.text
    }

    //タッチでキーボードを閉じる
    //タッチした時に呼ばれるメソッド
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        view.endEditing(true) //編集を終了してもよろしいですか?で消える
    }

    //リターンキーを押した時にキーボードを閉じる
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        //キーボードが閉じる
        textField.resignFirstResponder()
        return true //Boolだからtruefalseを返さないといけない

    }

}

まずはDelegateクラスを定義する

分割して説明すると、UITextFieldDelegateクラスを定義してその中のメソッドの使用を可能にして、

qiita.rb
import UIKit

class ViewController: UIViewController,UITextFieldDelegate {

そのDelegateを、反映させたいTextFieldに設定する。
(このTextField上のキーボードでは、のちに設定するDelegateクラスのメソッドが反映される)

qiita.rb
 override func viewDidLoad() {
        super.viewDidLoad()

        userNameTextField.delegate = self
        passWordTextField.delegate = self

余白のタッチでキーボードを閉じる

touchesBeganメソッドは、余白をタッチした時に呼ばれるメソッド。その関数の中に、view.endEditing(true) つまりエディター(キーボード)をエンド(終える)すると書いて終わり。

qiita.rb
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        view.endEditing(true) 
    }

リターンキーのタップでキーボードを閉じる

textFieldShouldReturnメソッドは、リターンキーをタップした時に呼ばれるメソッド。

qiita.rb
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()

        return true

    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Delegateを用いたキーボードの閉じ方

TextFieldを開いた時に展開されるキーボードを、余白のタッチやリターンキー(キーボードの左下にある)を押して閉じる方法。

全体像

qiita.rb
import UIKit

class ViewController: UIViewController,UITextFieldDelegate {
    @IBOutlet weak var logoImageView: UIImageView!
    @IBOutlet weak var userNameTextField: UITextField!
    @IBOutlet weak var passWordTextField: UITextField!
    @IBOutlet weak var userNameLabel: UILabel!
    @IBOutlet weak var passWordLabel: UILabel!

    override func viewDidLoad() {
        super.viewDidLoad()

        //以下二つのテキストフィールドに、returnでキーボードを閉じることができるメソッドが入ったクラスを設定する = Delegate
        //よって、これらに対応したキーボードのみ、returnで閉じることができる
        userNameTextField.delegate = self
        passWordTextField.delegate = self

    }

    @IBAction func login(_ sender: Any) {

        logoImageView.image = UIImage(named: "loginOK")

        userNameLabel.text = userNameTextField.text
        passWordLabel.text = passWordTextField.text
    }

    //タッチでキーボードを閉じる
    //タッチした時に呼ばれるメソッド
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        view.endEditing(true) //編集を終了してもよろしいですか?で消える
    }

    //リターンキーを押した時にキーボードを閉じる
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        //キーボードが閉じる
        textField.resignFirstResponder()
        return true //Boolだからtruefalseを返さないといけない

    }

}

まずはDelegateクラスを定義する

分割して説明すると、UITextFieldDelegateクラスを定義してその中のメソッドの使用を可能にして、

qiita.rb
import UIKit

class ViewController: UIViewController,UITextFieldDelegate {

そのDelegateを、反映させたいTextFieldに設定する。
(このTextField上のキーボードでは、のちに設定するDelegateクラスのメソッドが反映される)

qiita.rb
 override func viewDidLoad() {
        super.viewDidLoad()

        userNameTextField.delegate = self
        passWordTextField.delegate = self

余白のタッチでキーボードを閉じる

touchesBeganメソッドは、余白をタッチした時に呼ばれるメソッド。その関数の中に、view.endEditing(true) つまりエディター(キーボード)をエンド(終える)すると書いて終わり。

qiita.rb
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        view.endEditing(true) 
    }

リターンキーのタップでキーボードを閉じる

textFieldShouldReturnメソッドは、リターンキーをタップした時に呼ばれるメソッド。

qiita.rb
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        textField.resignFirstResponder()

        return true

    }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【SwiftUI】NavigationViewの遷移先の画面でtitleの非表示

非表示というか、こんな感じの状態

SecondVIew_swift_—_Edited.png

以下を遷移先のViewにつけるだけ

.navigationBarTitle(Text("title"), displayMode: .inline)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む