Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

【初学者/自分用】未経験者が学ぶべき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』をお忘れずに👇👇👇それでは

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away