20201112のiOSに関する記事は7件です。

TableViewのヘッダーではなくNavigationItemのTitleだった件

iOS標準のメモアプリやメッセージアプリなど
TableViewのHeaderViewっぽいのがスクロールするとNavigationItemのTitleに表示される動きについて、TableViewのHeaderViewを触るものと思い込んでしまったせいでハマったので覚書き。
NavigationTitle.gif

実装手順

  • NavigationBarのPrefers Large Titlesにチェックを入れる
  • NavigationItemのTitleにタイトルを入力
  • NavigationItemのLargeTitleをAutomaticに。

以上!!
一瞬でした。

参考記事
https://qiita.com/mcz9mm/items/cd005814550087c7c707

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

[iOS]ランダムな座標にUIImageを生成する

普段Storyboardを使ってUIを構築している私ですが、ランダムな座標にUIImageを生成しようと思って調べたら色々勉強になったのでまとめます。

バージョン

Swift 5.3
Xcode 12.1

この記事で述べること

  • storyboardを使わずにUIを画面に描画する方法

画面の真ん中に画像を配置する

とりあえず、コードから決まった位置に画像を配置します。

import UIKit

class ViewController: UIViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        // UIImageの初期化
        let image: UIImage = UIImage(named: "ninja")!

        // UIImageViewの初期化
        let imageView = UIImageView(image: image)

        // 画面の縦幅・横幅を取得
        let viewWidth: CGFloat = view.frame.size.width
        let viewHeight: CGFloat = view.frame.size.height

        // 画像に設定したい縦・横幅を変数に格納
        let imageWidth: CGFloat = 100
        let imageHeight: CGFloat = 100

        // 画像の座標・大きさを生成
        let rect: CGRect = CGRect(x: 0, y: 0, width: imageWidth, height: imageHeight)

        // 指定した座標・大きさを設定
        imageView.frame = rect;

        // 画像を画面の中央を指定
        imageView.center = CGPoint(x: viewWidth / 2, y: viewHeight / 2)

        // viewにUIImageViewを追加
        self.view.addSubview(imageView) 

    }

}

コードだけで画像が真ん中に配置されました。かわいいね。

ランダムな座標に画像を生成する

CGPointの座標はCGFloatを引数に取るので、

CGPoint(x: CGFloat.random(in: 0...viewWidth), y: CGFloat.random(in: 0...viewHeight))

でランダムな座標を生成することが出来る。

なので、上の画面の真ん中に画像を生成するコードの

imageView.center = CGPoint(x: viewWidth / 2, y: viewHeight / 2)

の部分を

imageView.center = CGPoint(x: CGFloat.random(in: 0...viewWidth), y: CGFloat.random(in: 0...viewHeight))

にすることでランダムな座標で画像が生成される。

まず、今はViewDidLoadの中に画像生成のコードを書いているので、関数にまとめます。

override func viewDidLoad() {
        super.viewDidLoad()

    }

    @IBAction func generateUIIMageVIew() -> Void {
        // UIImageの初期化
        let image: UIImage = UIImage(named: "ninja")!

        // UIImageViewの初期化
        let imageView = UIImageView(image: image)

        // 画面の縦幅・横幅を取得
        let viewWidth: CGFloat = view.frame.size.width
        let viewHeight: CGFloat = view.frame.size.height

        // 画像に設定したい縦・横幅を変数に格納
        let imageWidth: CGFloat = 100
        let imageHeight: CGFloat = 100

        // 画像の座標・大きさを生成
        let rect: CGRect = CGRect(x: 0, y: 0, width: imageWidth, height: imageHeight)

        // 指定した座標・大きさを設定
        imageView.frame = rect;

        // 画像を画面の中央を指定
        imageView.center = CGPoint(x: CGFloat.random(in: 0...viewWidth), y: CGFloat.random(in: 0...viewHeight))

        // viewにUIImageViewを追加
        self.view.addSubview(imageView)
    }

ボタンを付けます


そしてボタンと関連付けます。

Untitled.png

そうするとこんな感じでボタンを押すたびに画像がランダムな位置で生成されました。すごいね

一定の時間で画像が生成されるようにする

Timerを使って1秒ごとに画像が生成されるようにします。

  1. ボタンを削除して@IBActionの部分を@objcにする。
  2. タイマーの初期化

で実装できます。

    var generateImageTimer = Timer()
    override func viewDidLoad() {
        super.viewDidLoad()
        generateImageTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(generateUIIMageView), userInfo: nil, repeats: true)
    }

    @objc func generateUIIMageView() -> Void {
        // UIImageの初期化
        let image: UIImage = UIImage(named: "ninja")!

        // UIImageViewの初期化
        let imageView = UIImageView(image: image)

        // 画面の縦幅・横幅を取得
        let viewWidth: CGFloat = view.frame.size.width
        let viewHeight: CGFloat = view.frame.size.height

        // 画像に設定したい縦・横幅を変数に格納
        let imageWidth: CGFloat = 100
        let imageHeight: CGFloat = 100

        // 画像の座標・大きさを生成
        let rect: CGRect = CGRect(x: 0, y: 0, width: imageWidth, height: imageHeight)

        // 指定した座標・大きさを設定
        imageView.frame = rect;

        // 画像を画面の中央を指定
        imageView.center = CGPoint(x: CGFloat.random(in: 0...viewWidth), y: CGFloat.random(in: 0...viewHeight))

        // viewにUIImageViewを追加
        self.view.addSubview(imageView)
    }

自動で勝手に画像が生成されるようになりました。すばらしい!

参考文献

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

Xcode で Canvas を上手に利用するための Tips

記事内容

Xcode 12 では Canvas の機能を使って、コーディングしながらリアルタイムにデバイスの画面がどのように表示されるのかを確認できます。

この記事では、その便利な Canvas をさらにより良く使いこなすための Tips(ヒント)を掲載します。良い Tips があれば随時追加していく予定です。

もくじ

  • @EnvironmentObjectのプロパティを持つViewを表示するには
  • @Bindingのプロパティを持つViewを表示するには
  • コンポーネント用のViewだけを表示するには

@EnvironmentObjectのプロパティを持つViewを表示するには

ObservableObject クラス内の @Published 付きプロパティの値を 他のView から常に参照するために、そのクラスのインスタンスを @EnvironmentObject プロパティラッパーをつけて View 内に作成している場合、そのViewのプレビューには、以下のようにViewのインスタンスに、.environmentObject(ClassName())モディファイアをつける必要があります。これをつけないと Resume ボタンをクリックしても Canvas に表示されず、エラーになります。

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environmentObject(Manager())
    }
}

@Bindingのプロパティを持つViewを表示するには

@Bindingプロパティラッパーが付いているプロパティを持つ構造体の場合、そのプロパティはデータ型だけ指定され、値は代入されていません。例えば以下のように。

@Binding var name: String

このようなプロパティを持つ構造体のプレビューをCanvasに表示したい時、イニシャライズ時に適当な引数を入れてもエラーになります。このような場合は以下のように、引数として.constant()を指定するとうまく表示されます。これはView内のあらゆるバインディングで、何か値を仮に入れたい場合に使えます。プレビューのコードは以下のようになります。

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView(name: .constant("Masanao Sako"))
    }
}

Paul Hudson さんの Hacking with Swift もご参照ください。
https://www.hackingwithswift.com/quick-start/swiftui/how-to-create-constant-bindings

コンポーネント用のViewだけを表示するには

メインのViewに配置するコンポーネント用のView(画面のパーツ)を作成している場合、コンポーネント用のView単体をデバイススクリーン大のCanvasに表示するより、そのコンポーネント用Viewのみをジャストサイズで表示したい場合は、以下のように .previewLayout(.sizeThatFits) モディファイアをつけるとViewのジャストサイズになります。

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
            .environmentObject(Manager())
            .previewLayout(.sizeThatFits)
    }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[Swift5]ViewControllerからModelに通信を行って値を渡す方法

ViewControllerの役割

VIewControllerは、名前の通り表示されるViewを管理・操作(表示・非表示・配置・アニメーションなど)をする役割を持つクラスです。

あとは、受け取ったデータに合わせてTextやViewを表示・管理する役目を持ちます。

Modelの役割

システムの中でビジネスロジックを担当しており、実際にデータの処理を行うのがModelの役割です。
例えばアピの処理をおこなうのはModelです。

MVCモデルについて

アプリ開発におけるアーキテクチャの一つです。

MVCモデルの他にMVP、MVVM、などがあります。MVCモデルに関しての詳細は下記urlで取り上げられております。
https://qiita.com/s_emoto/items/975cc38a3e0de462966a

Modelの準備

まず、Model側でclassを作成しプロパティとinit(イニシャライザ(初期値))を用意します。

SampleModel.swift
class SampleModel {

    //Controllerから渡ってきた値を入れるプロパティ
    var sampleValueA: String?
    var sampleValueB: String?
    var sampleValueC: String?

    //Controllerから値を受け取る(イニシャライザ(初期値))
    init(firstSampleValue: String, secondSampleValue: String, thirdSampleValue: String) {

        sampleValueA = firstSampleValue
        sampleValueB = secondSampleValue
        sampleValueC = thirdSampleValue
    }

Controller側の記述

先にコードを記述します。

ViewController.swift
class SampleViewController: UIViewController {

    //SampleModelへ渡す値
    firstSampleValue  = "firstSampleValue"
    secondSampleValue = "secondSampleValue"
    thirdSampleValue  = "thirdSampleValue"

    override func viewDidLoad() {
        super.viewDidLoad()

        startSampleModel()
    }

    //SampleModelと通信をおこなうメソッド
    func startSampleModel() {

      let sampleModel = SampleModel(firstSampleValue: firstSampleValue, secondSampleValue: secondSampleValue, thirdSampleValue: thirdSampleValue)
    }
}

Modelで作成したinitをController側で呼び出して、Controllerで作成したプロパティをModelのinitに入れてあげます。

そうすると、Modelのinitの中で処理が行われ、今回のケースの場合、結果的にControllerで作成した文字列"firstSampleValue"sampleValueAに、文字列"secondSampleValue"が文字列sampleValueBに、文字列 "thirdSampleValue"sampleValueCに入ります。

これでControllerからModelへ値を渡すことができます。

最後に

次回の投稿はModelからControllerへ値を返す方法について投稿します。
今回の記事のの続編とです。

是非参考にしてください!

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

【初学者/自分用】未経験者が学ぶべきSwift基礎 レベル1:実務は厳しい

はじめに

https://qiita.com/Nekosennshi/items/2bb63a0cc92c9afa9fb9
こちらの記事を元に作成しています。

それでは早速始めていきます。

(それぞれの項目にあるURLは参考にした記事です。)

レベル1:実務は厳しい

演算(+, -, *, /, %)

特殊な効果を持つ記号とか文字のことを『演算子』と呼びます。
プログラミングの世界では「1 + 1の演算式は2を返す」という言い方をします。

演算の対象となる値や数値や変数の事を『オペランド』といいます。
例えば「1 + 2」の場合は数値『1』と数値『2』が『オペランド』になります。

他言語ではお作法のような感じですが、Swiftでは必ず『演算子』の両側に半角スペースを置く必要があります。
Swift側で上手く『演算子』として認識してくれない可能性があります。思わぬバグの原因になりがちなので要注意です。

Swiftの『+』記号は加算以外に文字列連結を行うことができます。使い方は簡単で文字列と文字列の間に『+』を置くだけでOKです。

print(1 + 1)
print("あなた" + "が好きです。")

2
あなたが好きです。

Swiftでの四則演算、加算は『+』、減算は『-』、乗算は『*』、除算は『/』、そして剰余(割り算した時の余り)は『%』を使用します。

print(1 + 2) #『1 + 2』の演算結果を出力します。
print(3 - 2) #『3 - 2』の演算結果を出力します。
print(3 * 2) #『3 × 2』の演算結果を出力します。
print(6 / 2) #『6 ÷ 2』の演算結果を出力します。
print(6 % 5) #『6 ÷ 5』の余りを出力します。

Swiftでも『+=』や『-=』といったように『加算』や『減算』とかをしつつ、同時に『代入』を行う演算子が用意されています。

var n = 1
n += 1 #変数『n』に数値『1』を加算しつつ自身に代入します。
print(n) #数値『2』が出力されます。

var n1 = 1
n1 -= 1 #変数『n』に数値『1』を減算しつつ自身に代入します。
print(n1) #数値『0』が出力されます。

var n2 = 1
n2 *= 3 #変数『n』に数値『3』を乗算しつつ自身に代入します。
print(n2) #数値『3』が出力されます。

var n3 = 10
n3 /= 2 #変数『n』に数値『2』で除算しつつ自身に代入します。
print(n3) #数値『5』が出力されます。

var n4 = 7
n4 %= 5 #変数『n』に数値『5』で剰余演算しつつ自身に代入します。
print(n4) #数値『2』が出力されます。

インスタンスとは

https://wp-p.info/tpl_rep.php?cat=swift-biginner&fl=r30
クラスは設計図みたいな存在なので、クラスを定義した時点では実体がないです。

そのため、中に書いてある処理を実行するためには、その設計図を元にした実体を生成しないといけません。これが『インスタンス』と呼ばれるものになります。『インスタンス』を生成するにはこんな感じで記述します。

class Test {
    let n = 1
    var _n = 2

    func f(){
        print(n)
        print(_n)
    }
}

Test() #クラス『Test』を元にした実体を作ります。これが『インスタンス』です。

『インスタンス.識別子』とすることで、そのデータにアクセスすることができます。

print(Test().n) #クラス『Test』を元に生成した『インスタンス』の中にある定数『n』の中身の『1』を出力します。

クラス『Test』の中にある関数『f』を実行させるとなるとなるとこうなります。

Test().f() #クラス『Test』を元に生成した『インスタンス』の中にある関数『f』を実行します。

プロパティとは

https://qiita.com/akeome/items/2197a635ac616ab2f8e2
※プロパティは非常に細かいため、詳細は参考記事をご覧ください。

プロパティとは型(クラス、構造体、列挙型)を構成する要素の一つで、型もしくは型のインスタンスに紐付いた値を指します。
ちなみに型を構成する他の要素としてはメソッド、イニシャライザ、サブスクリプト、ネスト型があります。

struct Person {
    var name = "Conan" #プロパティ

    func greet() { #メソッド
        print("I'm \(self.name)")
    }
}

メソッドとは

https://qiita.com/kiyotaman/items/c5d5e9e0084cf14ad0f6
メソッドは、関数と同じように戻り値を返すこともできますが、基本的にはインスタンスのプロパティを操作する方法として使う。

細かく言うと、、、
メソッドは特定の型をもつ関数のこと。
クラスや構造体や列挙型にインスタンスメソッドを定義できる。
メソッドには型を定義できる。
自分自身を型として関連付ける事もできる。
タイプメソッドはObjCのクラスメソッドに似ている。
構造体と列挙型に型を指定する事ができる。

比較演算子(==, !=)

https://i-app-tec.com/ios/swift-operator.html
数値の大きさを比較する演算子です。結果はBool値(true, false)です

Bool値とは、
真を表すtrueか偽を表すfalseのいずれかの値をとる型です。
真か偽を表す値を真理値といいます。

>   より上
<   より下
==  イコール
>=  より以上
<=  より以下
!=  ノットイコール
var a = 4
var b = 7
var c: Bool

c = (a > b)
c = (a < b)

c = (a >= b)
c = (a <= b)

c = (a == b)
c = (a != b)

補足:論理演算子

https://i-app-tec.com/ios/swift-operator.html
比較してBool値を返します。

&&  AND
||  OR
!   NOT
var d = true
var e = false
var f: Bool

f = (d && e)
f = (d || e)

f = (!d)
f = (!e)

変数 var

https://wp-p.info/tpl_rep.php?cat=swift-biginner&fl=r10
『変数』=「データを一時的に保存できる加工や複製が可能な名前がついた領域」

参考書などでは「箱」と例えられる事が多いですね。
箱で例えると「データを一時的に保存できる加工や複製が可能な名前がついた箱」って感じです。名前をつけられて加工したり複製することができる、というのがポイントです。

言葉ではわかりづらい方は、数学の方程式で表します。
x + 1 = y
この概念と非常に近く、プログラム言語の『変数』には、数値とか文字列とか真偽値とか様々なものを入れられます。

下記は、『s』という『変数』が『String型』で作られました。
『var』は『変数』を初めて作るときに"必ず"記述しないといけません。
コンピューターに「変数作るよー!」って教えてあげてるようなイメージですね。

var s: String
s = "Hello world" #文字列『Hello world』を代入してあげます。

print(s) #『Hello world』が出力される。
print("s") #変数『s』ではなく文字列『s』になるので『s』が出力されます。

『変数』の中に数値を入れた場合はそのまま計算できる。

var n: Int
var _n: Int

n = 1
_n = 2

print(n + _n) #数値『3』が出力されます。

『変数』は上書きすることができます。
注意点として、上書きするときも同じデータ型の値をいれてあげないとエラーになります。

var s: String

s = "Hello world"
s = "Hello Swift" #変数『s』を上書きします。この代入処理が最後に行われます。

print(s) #『Hello Swift』が出力されます。
---------------------------------------
var n: Int

n = 0
n = 1 #変数『n』を上書きします。この代入処理が最後に行われます。
n = "Hello world" #エラーです。変数『n』はInt型の値しか入りません。

これまで『変数』を生成して、その後に値を代入をするという流れでしたが、『変数』を生成すると同時に代入することもできます。
『変数』の生成と同時に何かの値を代入することを『初期化』と呼びます。
そして代入された値は『初期値』と呼ばれます。

var s: String = "Hello world" #『変数』の生成と同時に文字列『Hello world』を代入します。
#↑1文が初期化。『Hello world』が初期値。

print(s) #文字列『Hello world』が出力されます。

今まで『変数名: データ型』で型の指定をしていました。

⚠️重要:"『初期化』を行った場合は、データ型の指定をしなくても変数が生成できます。"

『初期化』を行った場合は下記のように型の指定をしなくても『変数』が生成でき、『初期値』に対する適切なデータ型を自動で設定してくれます。

文字列『Hello world』が『初期値』なのでその値に該当する適切なデータ型である『String型』が指定されているものとして生成されます。

var s = "Hello world" #ここに注目して下さい。String型が自動指定されている。

print(s) #文字列『Hello world』が出力されます。

定数 let

https://wp-p.info/tpl_rep.php?cat=swift-biginner&fl=r10
変数 var と違い、一度代入した値を上書きすることができない。「変更ができない変数」というイメージですね。
文法は『変数』の時と同じような感じになります。

#『初期化』した『定数』を上書きする。
let n = 1
let _n: Int = 2
n = 2 #エラーです。

#『初期化』しないで『変数』を生成してその後に代入する。
let s: String
s = 1 #OKです。
s = 2 #エラーです。

エスケープ処理「()」

通常の文字の集まりのことを『文字列』といいます。

print("Hello world") # ""←ダブルクォーテーションが必要。

大体の文字は『文字列』として扱えますが、例外があります。
『"』を文字列として扱いたい、となった場合は『"』が3つ連続してる感じです。
他のプログラム言語でも言えることですが、『"』を『"』で囲うことはできません。

これは『文字列』をくくるために使ってる『"』なのか、ただの文字としての『"』なのか、コンピューター側で上手く判断できないからこんな動きになります。

print(""") #エラーです。

「じゃあ『"』を普通の文字みたいな扱いにしたいときはどうするのー?」ってなりますよね。
そんな悩めるあなたは『\』(バックスラッシュ)を使用してみましょう。
(※『\』=『option + ¥』)

print("\"")

" #実行結果

『\』を何の機能も持たない『\』にしたい、といった場合は『\』と記述しちゃえばOK。

print("\\")

\ #実行結果

『"』などの特殊な記号の手前に『\』を置いて何の機能も持たないただの文字として扱わせることを「エスケープする」と言います。

『\』には『"』のような特殊な機能を持つ記号の機能を無くす機能があります。

特定の文字と組み合わせることで他の表現もできたりします。
『\n』と記述することで改行を表現することができます。

print("あいう\nえお")

あいう #実行結果
えお

『\t』でタブ文字を表現することができます。

print("あいう\tえお")

あいう   えお #実行結果

『\"』とか『\』とか『\n』とか『\t』とかのことを『エスケープシーケンス』(エスケープ文字)って呼ばれます。

if文

https://wp-p.info/tpl_rep.php?cat=swift-biginner&fl=r24
『if文』に必要な、真偽値とは↓
https://wp-p.info/tpl_rep.php?cat=swift-biginner&fl=r8
『if文』は「もし〜だったら〜を行う」といった分岐処理のこと。
『条件式』が『true』ならば『{}』の中身が実行され、『false』ならば実行されない、といった処理を構築できるのが『if文』です。

if 条件式 {
    #ここに処理...
}

『else文』は最初の『if文』の『条件式』が『false』となった場合に問答無用で『else文』の『{}』の中身が実行される、といった処理になります。
下記は、最初の『if文』の『条件式』が『false』なので『print("実行されました。その2")』が実行されます。

if false {
    print("実行されました。その1")
}
else {
    print("実行されました。その2")
}

『else文』ではその前の『if文』が『false』ならば問答無用で実行されますが、『else if文』だとそのあとに更に処理を分岐させることができるといった違いです。

『else if文』と『else文』を複数組み合わせることができます。

まず『if文』で条件分岐が行われ、その後に『else if文』でさらに条件分岐、その後全てが『false』ならば『else文』の処理が実行される、といった流れになります。

最初は必ず『if文』、最後は必ず『else文』です。

if false {
    print("実行されました。その1")
}
else if false {
    print("実行されました。その2")
}
else if false {
    print("実行されました。その3")
}
else {
    print("実行されました。その4")
}

今まで『条件式』のところに直接『true』や『false』を記述しましたが、あまり意味はないので演算式を用います。
『1 < 2』と記述した場合、これは『true』なので『print("実行されました。")』が実行される、といった感じになります。

if 1 < 2 {
    print("実行されました。")
}

⚠️重要:他言語と異なり、Swiftは『条件式』の演算結果が真偽値でない場合はエラーになります。

if 1 { #数値『1』は真偽値ではないのでエラーです。
}

switch文

https://wp-p.info/tpl_rep.php?cat=swift-biginner&fl=r26
『switch文』では同時に多数の分岐処理をさせていくことができます。
『case』を使った処理は『case文』と呼ばれ、『case文』は複数設置することができます。

let n = 1 #定数『n』に『1』を代入

switch n { #定数『n』が『条件式』。ここに評価させたい定数や変数や演算式などを入れる
    case 1: #『条件式』に書いてある定数『n』の中身が『1』だった場合に『:』以降の処理を実行。
        print("1です。")

    case 2: #『条件式』に書いてある定数『n』の中身が『2』だった場合に『:』以降の処理を実行。
        print("2です。")

    default:
        print("defaultです。")
}

最後の『default』は、その前の『case』での評価がすべて成立しなかった場合に実行されます。
『default』を使った処理は『default文』と呼ばれます。

let n = 3

switch n {
    case 1:
        print("1です。")

    case 2:
        print("2です。")

    default: #ここが実行されます。
        print("defaultです。")
}

『条件式』の演算が最初に行われるため、『1 + 1』の演算結果の『2』が比較対象となります。
その後に各『case文』と一致するかどうかの判定が上から順番に行われます。上から順番に行われる、というわけなので以下のように『case 2』を複数用意しても実行されるのは最初の『case 2』となります。

switch 1 + 1 {
    case 2: #実行されるのはここのみです。
        print("2です。")

    case 2:
        print("2です。その2")

    case 2:
        print("2です。その3")

    default:
        print("defaultです。")
}

基本的に『default文』を記述する必要はありますが、
「『条件式』の全ての結果が『case文』に記述されている場合のみ『default文』の省略ができる。」

しかし、「全ての『条件式』の結果を網羅する」というのが不可能だったりする場合が多いため、『default文』は必ず記述しておく、というイメージを持っておいた方が無難な気がします。

『default文』は必ず『switch文』の最後に記述する必要があります。

switch 1 { #これはOKです。
    case 1:
        print("1です。")
}

『case文』や『default文』の中身を空にすることはできず、『break文』というのを使います。
『break』は「『switch文』とかループ処理とかを抜けて!」という命令になるので、『break』と記述すれば処理を何も行わず『switch文』を抜けることが可能になります。

let n = 1

switch n {
    case 1:
        break #『break』と記述すると『switch文』を抜けることができます。「何もしたくない」という意味。

    case 2:
        print("2です。")

    default:
        print("defaultです。")
}

他言語と違い、Swiftの場合は「続く処理が全て実行される」という挙動にならないため、各『case文』ごとの『break』は記述する必要がありません。

逆に「続く処理を実行したい」場合、『fallthrough』と記述します。
『fallthrough』と記述した場合は、「次の『case文』または『default文』の処理のみが問答無用で実行される」という挙動になるので要注意です。

let n = 1

switch n {
    case 1:
        print("1です。")
        fallthrough

    case 2:
        print("2です。")
        fallthrough

    case 3:
        print("3です。")
        fallthrough

    default:
        print("defaultです。")
}

1です。
2です。
3です。
defaultです。

この定数『n』はInt型となっているため、文字列とかを入れることはできません。
『case "1"』のように、『case文』でデータ型が違う値と比較させようとするとその時点でエラーになります。

let n : Int = 1

switch n {
    case "1": #ここでエラーが出ます。
        print("1です。")

    default:
        print("defaultです。")
}

for文

https://techacademy.jp/magazine/14546
https://qiita.com/funacchi/items/4da8016b2d1e13cec538
for 文では条件を記述する代わりに、繰り返しの元となる範囲や配列を in の後に記述します。

範囲は 0…10 や 0..<10 のように 「…」「..<」を使った記法を利用できます。

『開始値…終了値』:「開始値」で始まり「終了値」まで続く範囲を指定します。「終了値」も範囲に含まれる。
『開始値..<終了値』:「開始値」で始まり「終了値」のひとつ前まで続く範囲を指定します。「終了値」は範囲に含まれない。
『範囲』や『配列』から元になる値が生成されて、それが『for』の後ろに記述した『定数』に代入されます。

for 変数 in 開始値 ..< 終了値 { #..<のため、終了値は含まない。
  #繰り返し実行されるコード
}

構造体:struct

https://qiita.com/Howasuto/items/ef02b0682f2222b3c391
https://qiita.com/Howasuto/items/57acf33b40dbf4604397
※構造体(struct)は非常に細かいため、詳細は参考記事をご覧ください。

値型の一種で、ストアドプロパティの組み合わせによって1つの値を表すことができるもの。
簡単に言うと、これは継承不可のクラスのようなものであり以下のような特徴を持っています。

・複数の値を一個の構造体で管理できる(ストアドプロパティの組み合わせによって一つの値を表す)
・辞書とは違い、同じ構造のオブジェクトを複数生成可能
・クラスと違い参照不可
・クラスは参照型に対し、構造体は値型
・イニシャライザも関数も使用可能

このような構造体の用途は多くあり、例えば画面上の幅と高さは2つのプロパティをもつ構造体で表すことができ、統一して管理したい複数のプロパティを使用する際に便利です。

struct 構造体名 {
  構造体の定義
}

関数 func

https://wp-p.info/tpl_rep.php?cat=swift-biginner&fl=r18
関数は「処理(演算)に名前をつけていつでも操作したり呼び出せるようにしたもの」というイメージになります。

下記は『print(1 + 1)』という処理に『test』という名前を付けていつでも呼び出せるようにした形です。

文頭の『func』は「関数を定義するよ!」ってコンピューターに教えてあげる宣言のような感じになり、『関数』を定義する際には"必ず"記述する必要があります。
変数とか定数を定義するときに使った『var』とか『let』とかと同じような感じですね。

『func』の後に『関数名』を記述します。今回は『test』が該当しますね。

func test() {
    print(1 + 1)
}

test() #数値『2』が出力されます。

『関数名()』とすることで定義した関数を呼び出して実行させることができます。
『()』を付けるのを忘れないようにしてください、これが『関数』を実行させる際のトリガーのようなものになります。

※私は『()』をよく忘れていました。?

型キャスト

https://fukatsu.tech/swift-cast

キャストとは『変数』や『定数』の型を、より具体的な型や汎用的な型として扱うことです。

『Any型』であった変数や定数を→『Int型』
『Int型』だった変数や定数→『Any型』
として扱うような操作です。

キャストには『アップキャスト』と『ダウンキャスト』の2種類があります。

アップキャスト

より汎用的な型として扱うことを指します。

例えば、たかし君は東京都民です。
東京都民であるならば、日本人でもあるので、日本人としての振る舞いもします。
このような東京都民から日本人というように、より広いくくりとして扱う場合に、アップキャストを使います。

『アップキャストしたい値 as アップキャストする型』という形式で書く。

let string: String = "sample"
let any: Any = string as Any #String型からAny型へアップキャスト

ダウンキャスト

より具体的な型として扱うことを指します。

先程のたかし君の例をもう一度考えてみます。
「東京都民であるたかし君は、日本人である」というのが先程の例でしたが、その逆を考えてみます。
「日本人であるたかし君は、東京都民である」
これは、たかし君は東京都民である可能性もありますが、もしかしたら大阪府民である可能性もあります。

⚠️重要:『アップキャストは必ず成り立っていた』のに対して、『ダウンキャストは必ずしも成り立つわけではない』
⚠️重要:失敗する可能性を含んでいます

そのため、文法としても「失敗を含む前提のもの」を前提に置きましょう。

ダウンキャストの書き方は『as?』か『as!』を使う2種類の方法があります。

as?

3行目でInt型へダウンキャストをしようとしますが、"sample"はInt型にはなりえないので失敗します。
その場合に値がnilとなるのがas?の特徴です。

それに付随して、2行目を見てみると、こちらはString型へのダウンキャストが成功していますが、値はString型のオプショナル型となっています。
これは失敗する可能性があるので結果がオプショナル型になります。
オプショナル型→https://fukatsu.tech/optional-swift

let any: Any = "sample" as Any
let string = any as? String #オプショナル("sample")
let int = any as? Int #nil

as!

書き方自体はas?と変わってはいませんが、結果が異なります。

2行目がas?の場合には『オプショナル型』だったのが『String型』になっています。
加えて、3行目で実行時エラーとなっています。

オプショナル型が分かると検討がついたかもしれませんが、as!を使うと、
結果が強制的にアンラップされる
→そして結果がオプショナル型にならない
→失敗した場合に実行時エラー
→アプリがクラッシュ

このように、as!を使ったダウンキャストを強制キャストといいます。

let any: Any = "sample" as Any
let string = any as! String #"sample"
let int = any as! Int #実行時エラー

どちらを使うべきか?
as?→安全である代わりに、失敗したときの処理を書く必要がある。
as!→失敗したときの処理を書かなくていい代わりに、実行時エラーの危険性がある。

基本的には安全であるas?を使うのがいいと思われます。
しかし、as!を使うほうがむしろ好ましい場面もいくつかあります。

例えばTableViewでTableViewCellを呼び出す際の処理です。
「処理が失敗しない前提」
「万が一失敗したとしても開発環境の時点でクラッシュしたほうが気づきやすい」
という利点を考慮してas!と書くようにする。

他にも、UI周りのパーツのインスタンス化する処理ではas!を使うようにしたり。
このように、両方の特徴をしっかり理解した上で、チーム内などで基準を設けたりして適切な方を選ぶことが重要だと思います。

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell = tableView.dequeueReusableCell(withIdentifier: "Cell") as! TableViewCell
    return cell
}

レベルX:一番重要かも

間違いない。

・ぐぐり力
・ある程度のエラーを自己解決できる
・難題に見切りをつけ、「何がどうわからず、どう調べたが、どうわからなかったので
 こういうことを知りたい」と言った形で質問ができる
・積極的に自習ができる
・プログラミングが好き

終わりに

お疲れ様でした!いかがだったでしょうか?

私は覚えること多いな〜と思いながら、この記事を書いていました笑
ですが、記事を書いているとものすごく理解して覚えることができました。

仕事で技術職のエンジニアを目指すなら、技術力なんて最低限は必須ですよね。
皆さんもインプットだけではなく、アウトプットをしながら学習することをおすすめします。

筆者も初学者ですので、未経験からエンジニアになるための人助けに少しでもなればいいと思い書きました。
少しでも参考になれば幸いです。☺️

下の『ストック』や『LGTM』をお忘れずに???それでは

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

【初学者/自分用】未経験者が学ぶべきSwift基礎

はじめに

未経験の方は、エンジニアを目指すには何を学習すればいいのかわからない。
そのため、ロードマップが必要だと考えました。

https://qiita.com/Sossiii/items/e2c846d12f2f5db7c426
こちらの記事を参考にさせていただき、基礎から着実に学んでいこうと思います。

基礎の学習は、「レベル5:独学はもう効率悪いから今すぐ実務に入ろう」に到達した時点で実務を推奨されているので、この記事ではレベル5までの内容を記述していくことにします。
(※もちろん技術力が高い方が、未経験者の就職・転職はしやすいと思います。あくまで参考記事を目安します。)

最後にも述べますが、基礎を学び続けるよりもポートフォリオを作った方がインプット、アウトプット、就活・転職を効率よくできると思うので、一通り学んだらすぐにでもポートフォリオ作成に移ってしまいましょう!

※量が多かったので、見やすさを重視するために分散させました。?‍♂️
レベルごとにURLを飛んでいただくと、閲覧可能です。

それでは早速見ていきます

レベル1:実務は厳しい

https://qiita.com/Nekosennshi/items/9dcb4a0dcb7323577153

・演算(+, -, *, /, %)
・インスタンスとは
・プロパティとは
・メソッドとは
・比較演算子(==, !=)
・変数 var
・定数 let
・エスケープ処理「()」
・if文
・switch文
・for文
・構造体:struct
・関数 func
・型キャスト

レベル2:数打てばどこか入れるかも

※作成段階です。?‍♂️

・型推論
・オプショナルがわかる
・if let
・オプショナルチェーン
・画像が使える
・storyboard/コーディングによる描画
 View、TableView、CollectionView、Switch、SegmentedControl
 TableViewとCollectionViewでのカスタムセルによる実装、
 その他もろもろのパーツ
・画面遷移(segue, navigationController,等)
・参照渡し, 値渡し
・アラート UIAlertController,UIAlertAction
・SVProgressHUDを適切なタイミングで使える
・NavigationControllerが使える

レベル3:数打てばどこか入れるかも

※作成段階です。?‍♂️

・UIView.animateでアニメーションが実装できる
 -> ライフサイクルを意識できると良い
   これができるとUIに磨きがかかるので選考でウケがいい
・セルの再利用がわかり、適切に動作させることができる
 -> 再利用を理解せず(特に初期化)、副作用が起きがち
・selfをつける時、要らない時がわかる

レベル4:入れる確率上昇中

※作成段階です。?‍♂️

・非同期処理(WebAPIを利用)->DispatchQueueやクロージャを使う
 (クロージャはここで使えれば良さそう)
・ライブラリ(Cocoapodsで外部ファイルをインストールして使う)
 Charts、FSCalendar、SwiftyJSON、とかで良さそう
・Delegateが実用できる
・NotificationCenterが使える
・Githubが使える
・SourceTreeが使える

レベル5:独学はもう効率悪いから今すぐ実務に入ろう

※作成段階です。?‍♂️

・Firestore、RealmSwiftを使える
 サーバー上に保存した情報をローカルDBに入れることで、
 何回もFirestoreからデータを引っ張らなくても良い(通信が減る)
 RealmSwiftはメモリ上に保存するのでタスクキルでデータは消え、肥大しない
・チャットが実装できる
 ライブラリ-> MessageKit
・ある程度のUIが設計できる
Pinterestでググれ

終わりに

お疲れ様でした!いかがだったでしょうか?

私は覚えること多いな〜と思いながら、この記事を書いていました笑
ですが、記事を書いていると、すごく理解して覚えることができました。

仕事で技術職のエンジニアを目指すなら、技術力なんて最低限は必須ですよね。
皆さんもインプットだけではなく、アウトプットをしながら学習することをおすすめします。

筆者も初学者ですので、未経験からエンジニアになるための人助けに少しでもなればいいと思い書きました。
少しでも参考になれば幸いです。☺️

下の『ストック』や『LGTM』をお忘れずに???それでは

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

switch文 範囲指定

概要

switch文の条件の範囲の指定方法について記述してみました。
自分自身switch文の条件には特定の値しか設定できないと思っていたので、自分で振り返る意味でも残しておきます。

記述

switch文は制御式の値に応じて実行する命令を切り替えるもの。

ViewController.swift
switch 制御式{
case 条件1:
    //条件1に当てはまる場合の処理
case 条件2:
    //条件2に当てはまる場合の処理
default:
    //どの条件にも当てはまらなかったっ場合の処理
}

条件に範囲がなく特定のものは問題なく記述できますが、以下のようなif文をswitch文に置き換える場合はどのようにすればいいでしょうか?

ViewController.swift
let number: Int!
if number > 0 {
    // numberが正のときの処理
} else if number < 0 {
    //numberが負のときの処理
} else {
    //numberが0のときの処理
}

このような時は、Int.minInt.maxを用います。
Int.minは整数型の取りうる最小値を表し、Int.maxは整数型の取りうる最大値を表しています。
整数の最大値、最小値と考えると+∞、−∞を思い浮かべますがデータ上は異なります。
整数の最大値は9223372036854775807、最小値は-9223372036854775807です。
桁が莫大なので実質+∞、−∞と考えていいと思います。
ということで、これを使ってswitch文を作ります。
[追記]ランダムの範囲が整数型全てであった時、1..<Int.maxではInt.maxが正の整数の範囲外になってしまうので1...Int.maxと修正しました

ViewController.swift
let number = Int.random(in: -100...100)
switch number{
case 1...Int.max:
    //numberが正のときの処理
    //[追記]1..<Int.maxの場合Int.maxが範囲外
case Int.min..<0:
    //numberが負のときの処理
default:
    //numberが0のときの処理
}

Int.maxなどを用いずに範囲指定したい場合も実行できます。
処理を行わない時はbreakで中断します。

ViewController.swift
let number = Int.random(in: 0...10)
switch number{
case 1...5:
    //numberが1~5のときの処理
case 6...10:
    //numberが6~10のときの処理
default: break
}

最後に

自分自身、あまりswitch文を用いずにif文のみで解決してきたところがあったので、
内容に間違いがあるかもしれません。その際はご指摘のほどよろしくお願いします。

参考文献

この記事は以下の情報を参考にして執筆しました。

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