Xcodeにはplaygroundっていうのがあって、ビルド無しでswiftを動かせる。簡単なswiftの学習やちょっとしたコードの確認をするのに便利。
画面右側に結果がすぐさま表示される。
またタイムラインを使って画面左側にも大きめに表示できる。
タイムラインを使うとiphone上にどのように画面に見えるかがわかるので開発に便利。
playgroundにもコンソールがある。ここに標準出力ができる。
playgroundを使えば簡単な実行結果を得ることができる。
しかし‥さっそく動きがおかしいんだが??
playgroundの右側にもコンソールにも実行結果が出なくなった。。
画面上部のRunning sampleのところは実行中アイコンがくるくる回ってるし。。
mac初心者なんでこれが何を意味してるのかわからない。。もしかしてフリーズ中??
Swiftにおける\()での式展開
swiftにも式展開がある。rubyで言うところの#{}と同じ使い方ができる。
記述の方法はバックスラッシュ\(変数)とやる。Windowsキーボードだとバックスラッシュが出ないので\マークで代わりに記述する。
これで
\(変数)
animal = "犬"
print ("私の好きな動物は\(animal)です")
[/code]
とやることができる。
そうすると標準出力には「私の好きな動物は犬です」と表示される。
Swiftでの変数の宣言
Swiftでは変数を宣言する際には
var fruit = "りんご"
var tel = "0801-234-5678"
var fujisan = 3776
[/code]
のように先頭にvarと記述して続いて変数を宣言することができる。変数の型については指定せずに宣言するようだ。文字列(string)や整数(integer)や小数点付き数値(Double)などを代入することができる。
Swiftでの定数の宣言
定数というのは値が変わらない(変えられない)変数のこと。これを宣言するには以下のようにする。
let fujisan = 3776
let syuto = "東京都"
[/code]
このように先頭にletと記述して定数名を書くことで値が固定される。この値に何か代入しようとすればエラーになる。
Swiftでの配列の宣言
var ar = []
[/code]
とやると配列の宣言ができる。けどエラーが出る。
error: empty collection literal requires an explicit type
空のコレクションリテラルには明示的な型が必要です。配列を空で宣言するときは型を指定しなきゃいけないようです。しかしテックキャンプの教科書ではそんなエラーが出るとか解決策とかは書かれていませんでした。どうすればいいんだろう。
型を指定して配列を宣言するには
var ar:[String] = []
[/code]
のようにやればエラーが出なくなった。
馴染みのない宣言の仕方なので戸惑いますね。覚えておかないと。
配列への要素の追加は 変数.append()
配列の要素の削除は 変数.remove(at: 整数)
配列の要素の下図を取り出すには 変数.count
rubyと似てるなぁ。
辞書型
Swiftではハッシュのことを辞書型と呼ぶらしい。
実際に空の辞書型を作るには以下のようになる。
var 辞書型名 = Dictionary<キーの型, データの型>()
ハッシュと呼ぶより辞書型と読んだほうがしっくりくるから個人的には好きだ。キーもデータも型を指定できる。
最初から値を入れるなら以下のようになる。
var hito = ["名前":"山田太郎", "年齢":"30", "性別":"男", "出身":"福岡"]
[/code]
キー:値
の順番。個人的にはrubyより書きやすいなと思った。
辞書型のデータを削除するには
hito.removeValue(forKey: “年齢”)
とやれば削除できる。追加は簡単で
hito[“キー”] = “値”
と入れれば良い。(String型の場合)
Playgroundがしばしばフリーズする
「playground フリーズ」で検索するとXcodeの2018年時点でよくフリーズするという書き込みやFAQを見つける事ができた。
解決策は無くXcodeの再起動でやり直すことでちゃんと出力(右側のウィンドウや、コンソール)が出来ることもある。
うーん、学習開始から暗雲だなこりゃ。
Swiftでの条件分岐やループ処理
if文、switch文、while文はC言語とほぼ同じように記述できることがわかった。
for文はちょっと違う。
var sum = 0
for i 1 ... 10 {
sum += i
}
[/code]
とやるとiが1~10まで変わって10回繰り返す。
for i 1 ..< 10 [/code] とすればiは10未満(つまり9)まで9回繰り返す。
for a in arry {
}
[/code]
のように配列を指定すると、全配列の要素に対して繰り返し処理を行う。またaにはarryの1つ1つの要素が代入されていく。つまり1回めのaにはarry[0]が入り、2回目のループにはaにはarry[1]が入っていくことになる。
配列の他に辞書型でも同じようにできる。
for (key, person) in people {
}
[/code]
とすれば辞書型変数peopleの全要素に対して繰り返し処理を行う。その再のキーはkeyに代入され、要素の中身はpersonに代入される。つまりpeople[“名前”]=”山田太郎”であれば、1回めのループにはkeyには”名前”が入り、persionには”太郎”が入ることになる。
Swiftには関数もメソッドもある
関数の使い方は以下のようになる。
func 関数名(変数: 型) -> 戻り値の型 {
return 戻り値
}
[/code]
これも簡単だと思った。実際に引数を書くなら以下のようになる。
func sumab(a: Int, b: Int) -> Int {
return a + b
}
[/code]
このように記述。
だけどC言語とは引数の順番が違うからちょっと躓く。確かC言語だったら
int sum(int a, int b) {
return a + b;
}
[/code]
とかだったはず。
Swiftでの関数呼び出し側は、sum(a: 3, b: 5)のように変数コロンを記述する。ちゃんと変数を書かないといけないんだね。
Swiftにおけるクラス
Swiftでもクラスがあるの。「クラス」といえばオブジェクト指向なんだよな。私はオブジェクト指向がどうにも駄目でプログラミングで躓くんだ。なんとか学習をクリアしていきたいので忘れそうな点は自分の言葉で理解しておく必要がある。
まずSwiftでは関数を定義することができる。その関数をクラスの中に入れるとこれをメソッド(method)と呼ぶ。メソッドといえば直訳すると「方法」のことなんだけど理解が難しい。
例えばスライムクラスを作るとするとHPとかMPに当たるものを「プロパティ」と呼ぶ。クラス内に宣言する変数のことをプロパティと呼ぶと覚えれば良い。
それで”こうげき”や”にげる”や”なかまをよぶ”に相当するもの(行動)をメソッドと呼ぶ。このように理解している。スライムじゃなかったらクラス内に何かしらの仕事をさせる関数はメソッドになる。
クラスの宣言は
class Slime {
var hp: Int
var mp: Int
}
[/code]
このような感じで作る。でもこれだけだとエラーが出る。
error: ‘Slime’ cannot be constructed because it has no accessible initializers
これは初期値が入ってないよというエラーで、クラス内のプロパティ宣言時に初期値を与えないといけない。なので
class Slime {
var hp = 10
var mp = 1
}
[/code]
とやればエラーが消える。初期値を与えないで宣言するには以下のような方法がある。
class Slime {
var hp: Int!
var mp: Int!
var town: String!
}
[/code]
これは強制的にnilを代入することができる。Implicity Unwrapped Optional型という。
クラスからインスタンスを生成したら、プロパティに直接代入ができるようになる。
var slime1 = Slime()
slime1.hp = 10
slime1.mp = 2
slime1.town = "群馬県"
[/code]
この時点ではセッターメソッドが内部で動いてくれてるのか、直接値を代入してるのかはわかっていません。おいおい学習を進めていけばわかると思いますが。
Swiftにはタイプメソッドとインスタンスメソッドというメソッドがある
タイプメソッド→クラス名.メソッドで実行できる。インスタンスの外から実行できるメソッド。
インスタンスメソッド→インスタンス.メソッドでで実行できる。インスタンスを生成してから実行するメソッド。
これもオブジェクト指向言語でよくありますね。Rubyでもあったし。
タイプメソッドの宣言は先頭にclassを付けないといけない。
class slime {
class func about() {
print("スライムとは最弱のモンスターである")
}
}
[/code]
こういう感じ。
initメソッド
あとinitメソッドもある。これはインスタンスを生成した時に実行されるメソッドのこと。
宣言の仕方はinit()でよく。引数も指定できる。
class slime {
var name: String
var hp: Int
var mp: Int
var live: String
class func about() {
print(“スライムとは最弱のモンスターです”)
}
func nigeru() {
print(“スライムが逃げた”)
}
init(name: String, hp: Int, mp: Int, live: String) {
self.name = name
self.hp = hp
self.mp = mp
self.live = live
print(“スライム\(name)を生成しました”)
}
}
slime.about()
var slime1 = slime(name: “A”, hp: 10, mp: 2, live: “群馬県”)
print(slime1)
slime1.nigeru()
[/code]
こういう感じ。initメソッドの中でhpやmpやliveなどのプロパティの初期化を行っている。classの最初でやってるプロパティの宣言のところに!が付いていないのはinitメソッドで初期化を行うことで不要になる。
Swiftでもクラスの継承が出来る
以下のように宣言する。
class クラス名: 親クラス名 {
}
[/code]
class slime {
var name: String
var hp: Int
var mp: Int
var live: String
class func about() {
print(“スライムとは最弱のモンスターです”)
}
func nigeru() {
print(“スライムが逃げた”)
}
init(name: String, hp: Int, mp: Int, live: String) {
self.name = name
self.hp = hp
self.mp = mp
self.live = live
print(“\(name)を生成しました”)
print(“HP->\(hp)”)
print(“MP->\(mp)”)
print(“住まい->\(live)”)
}
}
slime.about()
var slime1 = slime(name: “スライムA”, hp: 10, mp: 2, live: “群馬県”)
print(slime1)
slime1.nigeru()
class HoimiSlime: slime {
override class func about() {
print(“ホイミスライムはホイミがつかえます”)
}
override func nigeru() {
print(“ホイミスライムが逃げた”)
}
}
var hoimin = HoimiSlime(name: “ホイミスライムH”, hp:15, mp:7, live: “栃木県”)
hoimin.about()
hoimin.nigeru()
[/code]
結果はこういう感じになる。
スライムとは最弱のモンスターです
スライムAを生成しました
HP->10
MP->2
住まい->群馬県
__lldb_expr_30.slime
スライムが逃げた
ホイミスライムHを生成しました
HP->15
MP->7
住まい->栃木県
ホイミスライムが逃げた
Swiftでのコメントのやりかた
行の先頭に//をつければこれで1行コメントアウトになる。
複数行のコメントは/*と*/で囲めばOK
// 1行コメント
/*
hoimin.about()
hoimin.nigeru()
*/
[/code]
こういう感じ。C言語と同じやな。
SwiftにはOptional型という型がある
これは他の言語には無かった(私が経験した中では)型ですね。
Optional型は普通に宣言する変数の後ろに「?」か「!」をつける。
var live: String?
var hp: Int?
var name: String!
var age: Int!
[/code]
こんな感じ。
!と?の違い
!の方は暗黙的アンラップ型といって自分で明示的にアンラップしなくても使える。
例えば
var hp: Int! = 10
var mp: Int = 5
[/code]
この状態でhp + mpをやってもエラーが出ない。
けど?の方は自分でアンラップしてあげないといけないので。
var hp: Int? = 10
var mp: Int = 5
[/code]
ここからhp + mpをやるとエラーになっちゃう。
error: value of optional type ‘Int?’ not unwrapped; dit you mean to use ‘!’ or ‘?’?
明示的にアンラップをするには!を使う。
hp! + mp
[/code]
これでエラーが出なくなり計算もちゃんと行われる。
「ラップ」というのは文字通り「包む」とか「くるむ」の意味なのでテックキャンプのカリキュラムではダンボールをイメージしろと書かれていました。
var hp: Int? = 10
[/code]
これはダンボールの中に10が入ってるイメージ。だからそのままだとhp + mpという計算は出来ない。箱から取り出してあげる作業(アンラップ)が必要になってくると理解しました。
Optional型を使うとnilを代入することができる
Swiftは変数を宣言する際には何かしら初期値を入れないといけないけど、宣言時には初期値が決まってない場合はOptional型を使えば、例えば
var hp: Int!
[/code]
とすれば、nilで初期化されることになる。つまりnilを許容するにはOptional型として宣言しなくてはいけないということ。
オプショナルバインディングとオプショナルチェイニング
これはif文の条件分岐の時に、箱の中身がnilだとエラーになるので、それをチェックするのに使う。
これってruby on railsだと.present?メソッドみたいな感じ。
よくif文でエラー出るんだよ。この考え方はマスターしたい。
外部APIから取得したデータが空のことがあって、それを代入した先で空(nil)だと知らずに使おうとしてエラーになる‥これがよくあって対策が必要だった。
Swiftだとオプショナルバインディング、オプショナルチェイニングという方法がある。
オプショナルバインディング
変数を?のOptional型で宣言(json_station)、これがnilの状態でif文に入る。
if文で新たにvar ekiで変数を宣言してそこにjson_stationを代入している。このときekiにはnilが入るのでif文によって条件分岐になる。nilは論理演算がfalseになるのでelseの方に行くから”not found station”が表示される。
var json_station: String?
if var eki = json_station {
print(“found station \(eki)”)
} else {
print(“not found station”)
}
[/code]
結果は
not found station
なんでjson_stationという変数名にしてるかというと、以前APIからjson形式のデータを取得したことがありそのデータが空だったことがあるので、それを想定して個人的な事情。
例えば以下のようにjson_menuはOptional型で宣言しているが値(”child menu”)が入っている場合は、if文で新たにlet menu変数を宣言してそこに代入している。代入の結果menuには”child menu”という文字列が入る。if文の条件式の結果はnilではないので、上の方が動く。
var json_menu: String? = “child menu”
if let menu = json_menu {
print(“found menu -> \(menu)”)
} else {
print(“not found menu”)
}
[/code]
結果は
if文のすぐ後ろに宣言する変数のところはvarでもletでも構わないがletはやはり定数という認識。
オプショナルチェイニング
クラスのインスタンスもオプショナル型にできる。
var slime2: slime? = slime(name: "スライムB", hp: 10, mp: 2, live: "さいたま県")
slime2?.name
slime2?.nigeru()
[/code]
結果は以下のような出力になった。
“スライムB”
スライムが逃げた
以下のようにインスタンスを生成せずにOptional型にすると
var slime3: slime?
slime3?.name
slime3?.nigeru()
[/code]
これら全てnilが返る。
この方法を使えばふいにnilだったときにエラーが出ないように進めることができる。しかしnilかそうでないかを想定しながらプログラミングをしていくのは難儀ですね。