Swift基礎 メモ

変数・定数と型

変数の宣言
var…再代入可能
let…再代入不可

型の指定
文字列 let xx: String = "oo"
数値 let xx: Int = 1
連続した数値 let xx: Range = 1…5(1~5という意味 1..>5で1~4で処理できる。)
真偽判定 let xx: Bool = true (!trueといった感じで!をつけることで逆の意味を持つ)
なんでも型 let xx: Any(文字や画像、音声などなんでも入れることができる。ただ、何が入っているのか分からなくなるので、取り扱いには注意が必要。使用例:Twitterでツイートする時など)

演算
==…右辺と左辺の一致
!=…右辺と左辺が一致しない
&&…andの意味
||…orの意味

配列
定義…let stringArray: xx = ["a","b","c"]
取り出し…xx[0]
追加…xx.append("d")
一部削除…xx.remove(at: 0)
全てに適応…xx.map({$0 +"です"})
一定の条件を満たしたものを取り出し…xx.filter{ $0 % 2 == 0}
配列内検索…xx.contain("a") (aがxxにあればtrueなければfalseを返す)

optional型
値があるかないかを求める変数。これから値が入ってくるかも!?という時に使うことが多い。
使用例:Twitterのホーム画像(設定している人もいればしていない人もいるので、設定していない人=NIL 、設定している人=UIimageみたいな感じ)

let age: Int? = nilという書き方で定義する。
またオプショナル型から整数部分だけを取り出すときはage!と感じ関数の後ろに ! を記述する。
オプショナル型にも関わらず ! をつけずにageで取り出そうとするとnilの有無に関わらずエラーとなるので注意。また、nilにも関わらず ! をつけて取り出そうとする場合、エラーにはならないがアプリがフリーズする。
! は中身はnilでないのでエラーを出さないでねと示すこと。
なお、age! を何回も使う場合は面倒なので、
let age: Int! = 25という書き方で宣言時に ! を付け加えることができる。ただこの時ageにnilが入る処理は行ってはならない。
つまりStoryboardとSwiftファイルを紐づけた時に↓のように書くのはlabelを宣言するのに!を省略するための文言であると言える。

@IBOutlet weak var label: UIlabel!

オプショナル型の活用例

var hoge: string?
print(hoge) //nilが帰ってくる

//if letz
if let unrappedhoge = hoge{ 
   print(unrappedhoge) //hogeがnilの場合ifが実行されない。
}

//nilの置き換え
let hoge = hoge ?? 10 //nilであれば10に置き換える。

制御構文

if文

//普通のif
let number = 1
if number == 1{
      処理
}else if number == 2{
   処理
}

//swich文
switch numberText{
case "one":
   処理
case "two":
   処理
case "three":
   処理
default:
   該当なし
}

繰り返し

//for-in
let array = [1,2,3]

for number in array{
   処理
}

//while
let number = 3
while number <= 3{
   処理
   number += 1
}

関数

基本的な関数

//引数なし
func Hello () {
   print("Hello")
}
hello()

//引数あり
func say(xx: String){
   print(xx)
}
say(xx: Hello)

//引数と戻り値あり
func double(number: Int) -> Int{
   let result = number * 2
   return result
}
let doubleNumber = double(number: 10)

//複数の引数
func sum(first: Int, second: Int) -> {
   return first + second
}
let sumNumber = sum(first: 1, second: 2)

//引数のデフォルト値
func say(text: String = "Hello"){
   処理
}
say()

Class、またそれに近しいもの


class…設計図。他の言語でよくあるいつものやつ。
classの中にある関数をメソッドという。
UI周りは基本的にはAppleが作っているclassを用いいれば実装できる。
↓は音量とかを調節するテンプレートでUIKitに内蔵されているクラスをインスタンス化した物。

var slider = UISlider()

インスタンス化した後は、↓のようにプロパティ(classで定義されている変数)を変更することができる。ちなみに↓は音量をマックスにするようなテンプレート。

slider.value = 1.0

また、クラスに定義された関数(メソッド)を↓のように
インスタンス名.メソッド名(定められている引数)
を渡すことによって実行することができる。
ちなみに↓は音量を半分までアニメーションを用いて設定するメソッド

slider.setValue(0.5, animated: true)

Appleが便利なclassを作ってくれているが、時には自作しなければならない。
↓が自作の例。TaiyakiというクラスにnakamiプロパティとsayNakamiメソッドを作っている。その後インスタンスを生成してプロパティの中身を変えて、メソッドを実行したもの。

class Taiyaki{
    var nakami = "アンコ"
    func sayNakami (){
        print("中身は\(nakami)です")
    }
}

var taiyaki = Taiyaki()
taiyaki.nakami = "クリーム"
taiyaki.sayNakami() //中身はクリームです

struct…データ構造示すときに使われる型

//struct(classと同じ機能を持つ型。データ構造や何かの値を示すときに使われやすい)
struct car{
   var maker = "TOYOTA"
   var name = "プリウス"
   var door = 5
   func curaction(){
       print("プー")
   }
}
let myCar = car()
print(myCar.maker)
car.curaction()

親クラス子クラス
クラスを複数作成する場合にコードの重複が発生することがある。
↓のコードはスポーツカーとトラックのclassだが最初にsupi-doが0であるということ。stopメソッドによって停止できることが一致している。もし親子クラスの概念を活用しなければその点のコードが重複してしまうことになる。

class Car{
   var supi-do = 0
   func stop(){
      print("停止")
   }
}
class SportsCar: Car{
   func drive(){
      supi-do += 10
   }
}
class Truck: Car{
   func drive(){
      supi-do += 5
   }
}

var sportsCar = SportsCar()
var truck = Truck()

sportsCar.stop()
truck.stop()

ViewControllerを作成した時最初から↓の形でUIViewControllerを継承する形になっているがこれはViewControllerがUIViewControllerの子クラスであり、UIViewControllerのプロパティやメソッドを活用できることを意味している。
またUIViewControllerの内容はoptionを押しながらクラス名をクリックしOpen in Developer Documentationをクリックすることで確認できる。

class ViewController: UIViewController

親クラスのメソッドやプロパティを上書きする時はoverrideをつけて親クラスで指定した同じ名前で定義することによって再定義することができる。またメソッドの一部を再定義したい場合は↓のようにsuperをつけることによって親クラスで定義したメソッドは生かしたまま、子クラスで上書きできる。

class Cat{
   func run(){
      print("走る")
   }
}
class Taiger: Cat{
   override func run(){
      print("時速100キロで")
      super.run()
   }
}

var taiger = Taiger()
taiger.run

init(イニシャライザ)
絶対で必要であるにも関わらずユーザーごとに設定内容が異なる場合に用いる手法。(例:iphoneの最初の設定のlangageなど。)
これまでのclass生成時にはvar maker: String = "TOYOTA"といった感じで最初からプロパティの初期値を設定しておいたが、ここが人によって異なる場合に↓のように書くことによってどういった値が入ってきても代入できるクラスを作成することができる。

//classの作成
class car{
   var maker: String
   var name: String
   var door: Int

//イニシャライザ(クラスのプロパティの初期化を行う。インスタンスを作成する際の引数を追加する。)
      init(maker: String, name : String, door: Int){
       self.maker = maker
       self.name = name
       self.door = door
      }
}
let myCar = car(maker: "NISSAN", name : "フェアレディ", door: 3)
print(myCar.maker) //NISSANが帰ってくる

クロージャ
関数やメソッドの中身を直接記入できる処理のこと。
メソッドを使うときに () -> Void という引数を求められることがある。こういったときにprint("処理完了")などの処理を直接渡すことができる。処理が複雑な場合はメソッドをどこかで宣言した後、作成したメソッドを直接実行することも可能。
↓のメソッドはUIViewControllerにあるメソッドの一つであるが、引数の3つ目にクロージャを用いている。処理が簡単なので直接書いているが、
func show(){…}
completion: show
といった感じで作成したメソッドも呼べる。

UIViewController.present(controller, animated: true, completion: {print"処理完了"})

protocol
複数のクラス間で共通の機能を約束事を定義できる。
↓のAnimalで設定した約束事(var subject, func say)はDog、Catクラスの作成時において必ず準拠しなければならなくなる。また、複数のプロトコルを設定することも可能 
↓のようにプロトコルを作成することはほとんどなく必要なプロトコルはAppleが提供してくれている。また、プロトコルのメソッドを実装するとIOSから引数としてデータを受け取ることができるため、Appleが提供しているものを多く使う傾向にある。

protocol Animal{
    var subjectName: String{ get }
    func say()
}

//以下のクラスではプロパティ(subjectName)とメソッド(say)を必ず定義しないとならない。
class Dog: Animal{
   var subjectName = "イヌ科"
   func say(){
      print("ワン")
   }
}
class Cat: Animal{
   var subjectName = "ネコ科"
   func say(){
      print("ニャー")
   }
}

erum(列挙体)
Swiftに用意されていない型を独自に定義するための機能↓のような形で宣言する。

//列挙体の定義
erum Week{
   case monday
   case tuesday
   case wednesday
   case thursday
   case friday
   case saturday
   case sumday
}

//変数に代入
var today = Week.monday

一つの実践例として↓のコードがある。
cameraという変数にAppleが定義したerumの型を代入したコード。
UIImagePickerControllerの下の層にSourceTypeさらにその下にcameraという型が入っている。これはカメラを起動するためのコードにあたる。

let camera = UIImagePickerController.SourceType.camera

delegate
クラスの特定の処理が完了した後に他のクラスに特定の処理をさせる構文。
あるクラスだけでは処理できない命令をそのクラスの代わりに行うクラス。
例を挙げると弁護士。自分ではできないけど代理人(弁護士)を立てて裁判することが多い。それと考え方が近い。
↓のコードは
1〜3行目のプロトコルを用いてLawyer(弁護士)にdefend(弁護能力)があるかどうかのチェックを行っている。(delegate構文を使う上では必須)
5~10行目で↑で弁護能力があると確認できたものにのみ弁護士の権利を与えている。
12~15行目はdefender(被告人)のクラスを作る。この時delegate: LawyerLicense?を用いて弁護士プロパティを埋める。

protocol LawyerLicense{
   func defend()
}

class Lawyer:LawyerLicense{
   func defend(){
      print("意義あり")
   }
}

class defender{
   var delegate: LawyerLicense?
}

let taro = defender() //被告人を生成
taro.delegate = Lawyer() //taroに弁護士つける
taro.delegate!.defend() //弁護人が意義あり!と弁護する

型キャスティング
現在のクラスの型を親クラスや子クラスに振り替える機能。
例えば以下のようにAnimal<Mamal(哺乳類)<Dogというクラスがあったときに、そのclassの関係性は以下のようになる。

class Animal{}
class Mammal:Animal{}
class Dog:Mammal{}

var dog:Mammal = Dog{}

この時、var dog:Mammal = Dog()とった形でdogをより上位の型(Mammal)に入れることはできる。しかしながらMammalに入ったdogをDog型に入れる(ダウンキャスティングという。)時はas! Dogという宣言をしなければならない。具体的には↓の通り

class Animal{}
class Mammal:Animal{}
class Dog:Mammal{}
class Cat:Mammal{}

var mammals:[Mammal] = [Dog(),Cat()]
var dog:Dog = mammals[0] as! Dog

Extension
classないしはSwiftファイルを分割するためにクラスや型に拡張機能を持たせる。

//extensionの使い方
class User{
   var name = "Undefined"
}

extension User{
   func printUserName(){
      print(name)
   }
}
let user = User()

//classや型に対してextensionを追加することでユーザー定義関数っぽいないものを作れる
extension Int{
   var increasedValue: Int{
      return self + 1
   }
}
let one = 1
print(one.increasedValue)

ライフサイクル
画面が表示から非表示になるまでのサイクル(順番)

//表示
//1
override func loadView(){
   super.loadView()
}
//2
override func viewDidLoad(){
   super.viewDidLoad()
}
//3 表示されるたびに呼び出される(画面遷移から戻ってきた時など)
override func viewWillAppear(_ animated: Bool){
   super.viewWillAppear(animated)
}
//4 レイアウト生成開始
override func viewWillLayoutSubviews(){
   super.viewWillLayoutSubviews()
}
//5  レイアウト生成終了
override func viewDidLayoutSubviews(){
   super.viewDidLayoutSubviews()
}
//6 表示されるたびに呼び出される(画面遷移から戻ってきた時など)
override func viewDidAppear(_ animated: Bool){
   super.viewDidAppear(animated)
}

//非表示
//7 表示されるたびに呼び出される(画面遷移から戻ってきた時など)
override func viewDidDisppear(_ animated: Bool){
   super.viewWillAppear(animated)
}
//8
override func viewDidDisppear(_ animated: Bool){
   super.viewWillAppear(animated)
}

get,set
get…参照している値に変化があった時に呼ばれるもの
set…自分自身の値に変更があった時に呼ばれるもの

var price = 100
var taxRate = 1.1
var includePrice {
   get{
      return price * taxRate
   }

      set(value){
      price = value * 3
      taxRate = 1.0
   }
}
print(includPrice) //110円

price = 200
print(includPrice) //220円

includPrice = 200
print(includPrice) //600円

解説:
getのみの場合includPrice = 200といった感じで直接代入しようとするとエラーになる。
get,setの場合includPrice = 200といった直接代入が可能になる。 直接代入した場合はsetが走った後にgetが走る。
上のケースではincludPrice = 200にした場合、includPriceを呼び出した場合、setのvalueに200が代入され、priceが600となりtaxRateが1になった後、getが走ってincludPrice 600円が帰ってくる。

コールバック…処理後に呼ばれる処理
使用例:
通信後の非同期処理
同じような処理をした後に別々の処理を行いたい場合。
ViewModelのロジック処理後にレイアウトの処理を行いたい場合。

private func calc(completion: (Int) -> Void){
   let num = 1
   let result = num * 10

   completion(result)
   print(”計算の結果”/(result)) //10が帰ってくる
}

calc{ result in
   let sum = result * 3
   print("計算後の処理/(sum)") //30が帰ってくる
}

参考文献

絶対に挫折しないIPhoneアプリ「超」入門
https://www.sbcr.jp/product/4815604622/
【Swift5対応】絶対に挫折しない!未経験者がゼロからiOSアプリを開発するための全て!
https://www.udemy.com/share/104WBk3@k3v0P7MHXUknIdYXw3VHbE3U80spyw5kuRfG64OA3oNT8m0eQQkJDQjGsjkZN56Nxg==/


この記事が気に入ったらサポートをしてみませんか?