アットウィキロゴ

swift

概要

iosアプリを作成するプログラミング言語のこと
objectv-cに変わって主流になっている。
2014年に登場したので、まだ若い言語
でも大人気
モダンで実行が高速

対象バージョン
swift4(2017/12/4までは最新)

開発環境
xcode (試した時は9.1)
mac (osはSierra)

言語を試す環境
Playgroundというコード記述ワークスペースがある。
コードを記述したらすぐに実行できる。
試すには最適な環境


基本的な書き方
構文の末に ; をつけてもいいしつけなくてもいい
if / switch では {} でくくってはいけない
なぜなら optional binding ができなくなるから
switch だとコンパイルエラーになる

変数
構文に色々なパターンがある
  • 型宣言パターン
var 変数名: 型名
ex)
var num: Int
var text: String

  • 型が不定で代入時に自動で決まるパターン
注意:宣言と同時に値を代入しないとエラーになる
ex)
var num = 10 // 自動で型がintに

定数
構文に色々なパターンがある
  • let 定数名: 型名
ex)
let num: int
num = 10 // 一度だけ代入が可能
num = 20 // エラーになる

  • 型が不定で代入時に自動で決まるパターン
注意:宣言と同時に値を代入しないとエラーになる
ex)
let num = 10 // 自動で型がintに

型キャスト
文字列 to 数字
var stringTonum = Int("4")!

注意
int(文字列)の戻り値は optinal型なので unwrappyする必要がある。

数字 to 文字列
var intTostring = String(3)

文字列の場合はクラスのインスタンスをそのまま返すので optinal unwrappy はいらない

optinal
要約
nil代入を許可する定数・変数の特殊型のこと

宣言方法
var x: int?
x = nil

var y: Int
y = nil // コンパイルエラーになる

if文

if x == 0 {
}
else {
}

C/C++とほぼ変わらない
違いは条件文に () がないくらい
()をつけることもできるが optinal binding を使うとエラーになる

三項演算子が使える
ex)
print( y == 10 ? "ok" : "ng")

optinal bindding
optinal型で nil チェックをして同時に変数に代入してその変数を扱う仕組み
nilチェックと値がある時の変数代入を同時にしてくれる

ex)
var opTest: Int? = nil
opTest = 3
if let n = opTest {
    print("\(n)")
 

}

switch文

ex)
switch( y ) {
case 1:
    print("1")
 
case 2:
    print("2")
 
    // 複数指定
case 3, 4:
    print("3/4")
 
    //5 ~ 9までの値が対象
case 5..<10:
    print( y )
 
    // 10 ~ 12までの値が対象
case 10...12:
    print(y)
 
    // caseに該当しない時
default:
    break;
 

}

while文

for文

配列

タプル

集合

辞書

関数

class
クラス継承
クラス static
クラスのメソッド
クラスのメソッドのoverride
クラスのメソッドのfinal
クラスのプロパティのゲッター・セッター

protcol

extension

クラス型は参照・int/double/bool/構造体は値渡し

列挙型

構造体

guard

例外処理

ジェネリクス

optinal claining

impilcit unwrappy optinal

試したコード
// 定数
let msg = "test";
let testing: String;
let testing2: String;
 
var x = "go";
x = String(5);
 
print(x);
// 文字列に変数を埋め込むには \(変数) にする必要がある
print("msg is \(msg)");
 
// 定数は宣言だけすると一度だけ代入することが可能(C・C++にはないっすわ〜)
testing = "testing";
 
if( msg == "test" )
{
    testing2 = "testing2 : true";
}
else
{
    testing2 = "testing2 : false";
}
print(testing2);
 
var textNumber: String = "5";
// 変数・定数に直接代入する場合は!をつけてoptional型から変換した型に直す
let y = Int(textNumber)!;
print(y);
 
// 数値に変換して定数の代入もしてくれる
if let number = Int(textNumber)
// 下記の方法ではエラーとなる
// かっこ内で定数の参照範囲が閉じているから、それを考えるとかっこはない方がいいね
//if( let number = Int(textNumber) )
{
    print("変換成功");
}
 
// switch
let testSwitchNum = 30;
 
switch testSwitchNum
{
case 0:
    print("0");
 
// 複数指定が可能
case 1, 2, 3:
    print("1, 2, 3");
 
// 数字の場合だと min...max で指定できる
case 4...6:
    print("4/5/6");
 
// 数字の場合だと min..<max でmaxは含めないようにできる
case 7..<9:
    print("7/8");
 
// 条件に一致した場合 n 変数に代入して処理が書ける
case let n where n > 20:
    print("\(n) is huge!");
 
default:
    break;
}
 
// ループ条件
// ある要素全てを舐めるものになっている
for i in 0...3
{
    print(i)
}
 
// この書き方はNG
//for i in 2
//{
//    print(i)
//}
//
var i = 0
while i < 3
{
    print(i);
    i += 1
}
 
// nilを変数・定数に代入するには optional 識別子を追加する
// optional 識別子はswift4 ではなくなっている
// 代わりに型のサフェックスに? / ! をつけることになった。
var testOptional: String!
testOptional = String("success2")
 
/*
 optional て何?
 変数・定数にnilを代入できる特殊な型
*/
 
// 条件文にoptional変数を行い、かつ代入をするこのやり方を optional binding という
if let inOptional = testOptional
{
    print(inOptional)
}
else
{
    print("testOptional is nil")
}
 
// 配列
var array = [10, 20]
for num in array
{
    print(num)
}
 
// 空の配列を作成
var names = [String]()
names.append("kuronokur")
names.append("tonakai")
names.append("the end")
 
print(names.isEmpty)
print(names.count)
for name in names
{
    print(name)
}
 
// 配列の初期設定
var numarray: [Int] = [1, 2, 3]
for num in numarray
{
    print(num)
}
 
// タプル
// 各要素に名前付きの変数を定義できる
// pythonと違って代入できる
/*
    特徴
        各要素に名前付き変数が定義
        各要素を一つずつ変数に代入できる
        各要素の型はバラバラで問題なし!
 */
var tapul = (index1: "test", index2: 2)
print(tapul)
print(tapul.index1)
print(tapul.index1)
 
// タプルの要素を個別に代入することができる
var (text, _) = tapul
print("text is \(text)")
 
// 集合
// 要素の順序はバラバラになる
/*
    和集合・積集合・差集合などもできる
 */
var setting: Set<Int> = [1, 3, 4]
print(setting)
print(setting.isEmpty)
print(setting.contains(1))
setting.insert(4)
setting.insert(10)
print(setting)
 
setting.remove(1)
print(setting)
 
var setA: Set = [1, 2, 5, 6, 7]
var setB: Set = [3, 4, 5]
 
print(setA.union(setB))
print(setA.intersection(setB))
print(setA.subtracting(setB))
 
// 辞書
var dic = ["test": 1, "test2": 2]
for (key, value) in dic
{
    print("\(key), \(value)")
}
print(dic["test"] ?? "n.a")
 
var dicEmpty = [String: Int]()
print(dicEmpty.isEmpty)
dicEmpty["yamada"] = 10
print(dicEmpty.isEmpty)
 
// 関数
func sayHi()
{
    print("hi")
}
 
// 戻り値の書き方は Objectv-C に似ている
func sayHi2() -> String
{
    return "hi2"
}
print(sayHi2())
 
// 関数の引数
// 引数名の前にラベル付けができる
func sayHi3(from name: String)
{
    print("hi \(name)");
}
 
// ラベル指定して引数値を指定
sayHi3(from: "tonakai")
 
// 引数名の前にラベルなしができる
// _ をつけることでラベルなしにできる
func sayHi4(_ name: String)
{
    print("hi \(name)")
}
 
// ラベルなしで引数値を指定
sayHi4("tonakai")
 
// 関数の引数 inout
// 要するにポインタです。
func addNumber(num: inout Int)
{
    num += 10
    print(num)
}
 
var addNum: Int = 5
addNumber(num: &addNum)
print(addNum)
 
// プロトコルはクラスの雛形ですね。
// インターフェイスを定義する
protocol Pritable {
    // getのみなら定数とする
    var type: String { get }
    var counter: Int { get set }
    func printout()
}
 
// クラスについて
class User : Pritable
{
    let type = "Laser"
    var counter: Int = 10
    func printout() {
        self.counter += 1
        print("\(self.type), \(self.counter)")
    }
 
    let name: String
    var score: Int {
        // プロパティが変化するとキックする関数
        // イニシャライズでは呼ばれないです。
        //   C#にこんな機能はないっす。どちらかというとUE4よりの機能
        willSet {
           // プロパティが変わる前
            // newValueで変更後の値
           print("\(score) -> \(newValue)")
        }
 
        didSet {
            // プロパティが変わった後
            // oldValueで変更前の値
            print("Changed -> \(score - oldValue)")
        }
    }
 
    // C#のようにゲッター・セッターのプロパティを実装可能
    var level: Int {
        get {
            return 10
        }
 
        set {
            score = 10
        }
    }
 
    // ゲッターのみを作れる
    var level2: Int {
        return 30
    }
 
    //static var count: Int = 0
    static var count: Int = 0
 
    init(_ name: String, _ score: Int)
    {
        // プロパティを参照する時はクラスの所有とみなすために self. をつけるのがいい
        self.name = name
        self.score = score
 
        User.count += 1
    }
 
    init()
    {
        // プロパティを参照する時はクラスの所有とみなすために self. をつけるのがいい
        self.name = "me"
        self.score = 100
 
        User.count += 1
    }
 
    //  継承先で override ができないようにする
    final func sayHi() {
        print("hi")
    }
 
    // staic method を継承先で override するには static -> classに変える
    class func getInfo() {
        print("\(User.count) is instances")
    }
}
 
class AdminUser : User {
    // 基本クラスのメソッドを派生させる
//    override func sayHi() {
//        super.sayHi()
//        print("hello")
//    }
 
    // 基本クラスの static method をoverride している
    override class func getInfo() {
        print("Admin \(User.count) is instances")
    }
}
 
User.getInfo()
var user = User()
print(user.name)
print(user.score)
user.score = 12
user.sayHi()
User.getInfo()
 
AdminUser.getInfo()
var adminUser = AdminUser()
adminUser.sayHi()
AdminUser.getInfo()
adminUser.printout()
 
// 型キャスト
let users = [User(), AdminUser()]
for cast_user in users {
    if cast_user is AdminUser {
        // クラス型のチェックができる
    }
 
    // 型キャストして optinaol bindding している
    if let u = cast_user as? AdminUser {
        print(u.name)
    }
}
 
// 拡張
// 既存のクラスにプロパティを追加することができる
extension String {
    var length: Int {
        return self.count
    }
}
 
var textName: String = "textName"
print(textName.length)
 
// protcol型で宣言した関数を定義をすることができる
protocol ExtensionTest {
    func msg()
}
 
// 継承先で関数を定義することなくイケル!
extension ExtensionTest {
    func msg() {
        print("msg")
    }
}
 
class ExtensionTestClass: ExtensionTest {
}
 
var extensionTestClass = ExtensionTestClass()
extensionTestClass.msg()
 
// Int, double, float, boolなどの型で変数を代入する時は値のコピーをして代入元の中身に影響を与えない
// しかしクラスは参照になるので、代入元の値が変わると代入先の値も変わる。
// 当然代入先の値が変わると、代入元の値も変更されるので注意!
// クラスで値をコピーしたい場合はどないせいと?
 
// 構造体
protocol SandBoxDataInterface {
    mutating func msg2()
}
// クラス用に書けてかつ型の変数で代入すると値渡しになる
// protocol はイケル
// でも継承はだめ
struct SandBoxData: SandBoxDataInterface {
    var name: String
 
    init() {
        self.name = "test"
    }
 
    // method がくせ 関数構文の先頭に mutating 識別子をくっつける
    mutating func msg() {
        print("\(self.name)")
    }
 
    mutating func msg2() {
        print("msg2 is \(self.name)")
    }
}
 
var instanceSandBoxData = SandBoxData()
var instanceSanbBoxData2 = instanceSandBoxData
instanceSandBoxData.name = "sand"
instanceSandBoxData.msg()
instanceSanbBoxData2.msg()
instanceSanbBoxData2.msg2()
 
// 列挙型
enum Direction {
    case right
    case left
}
 
var dir: Direction
dir = .right
dir = Direction.right
switch( dir ) {
    case Direction.left:
        print(Direction.left.hashValue)
case Direction.right:
    print(Direction.right.hashValue)
}
 
// enum に値を割り当てることも可能
enum DirectionValue: Int {
    case right = 1
    case left = -1
}
 
// 割り当てた値を表示するには rawValue プロパティでOK
print(DirectionValue.right.rawValue)
 
// ジェネリクスとは型を汎用化すること
func putData<T>(_ data: T) {
    print(data)
}
 
// 引数の型が汎用なのでどの型の値を設定できる!
// c++ だと func<型>(引数) でした!
putData(1)
putData("msg")
putData(2.3)
 
// early return style
// これは変数が異常値の場合すぐにreturnを返すスタイル
// ↓こんな感じ
//if x == nill {
//    return
//}
// やり方は知っていたが名称については今知った!
 
// guard ealry return を描きやすくしてくれる
func guardTestEalryReturn(x: String?) {
//    if( x == nil ) {
//        print("x is nil")
//        return
//    }
//    // 上のやり方もありですが
//    // nil 以外のケースではどうする
//    print(x!)
    // こうすればuncapeして扱えるが、忘れそう
    // guard を使うと解決する
    // guard を使うと early return 形式を簡単わかりやすく書ける
    // optional bindding も使える!
    guard let n = x else {
        // x が異常ならここにくる
        print("x is nil")
        return
    }
 
    // x が正常なら n に値が代入されて uncape を明示しないで使える
    // いえ〜い
    print(n)
}
 
guardTestEalryReturn(x: "success")
 
// 例外処理
// enumでエラー定義をする場合は Error を継承する必要がある
enum LoginError: Error {
    case error1
    case error2
}
 
class Login {
    var name: String
 
    init(name: String) {
        self.name = name
    }
 
    // guard と 例外処理の合わせ技
    func login() throws {
        /*
            guard 成功条件 else {
                // 失敗時の処理
            }
        */
        guard self.name != "" else {
            throw LoginError.error1
        }
 
        guard self.name.length > 5 else {
            throw LoginError.error2
        }
 
        print("login success")
    }
}
 
var log = Login(name: "tanaka")
do {
    try
        log.login()
}
catch LoginError.error1 {
    print("error1")
}
catch LoginError.error2 {
    print("error2")
}
 
// optinal chaining
// nil 許容した optional を使う時に nilチェック処理で複雑になるのを簡潔するためのもの
class OptinalChainingTest {
    // optinal型(nilを認める)
    var name: String? = nil
}
 
var optinalChainingTest = OptinalChainingTest()
if let name = optinalChainingTest.name {
    print( name )
}
var optinalChainingText2: OptinalChainingTest?
optinalChainingText2 = OptinalChainingTest()
 
// 正しく nil チェックするならこうする
if let o = optinalChainingText2 {
    if let name = o.name {
        print( name )
    }
}
// でもネストがうぜ〜
// optinal型によるプロパティが増えるたびにこうなりえるのでそれは避けたい
// これを避けるために optinal chaining がある。
// optinal変数を参照する時は名前の後ろに ? をつける
// 仮に nil だとしてもハングすることがない
if let s = optinalChainingText2?.name?.uppercased() {
    print(s)
}
// optinal型宣言の? と optinal chainingの? は別物
 
// implictity unwraap optional
// ? -> ! にするとoptinal型だけど使用する時にわざわざ ! をつけて unwrappy することはなくなる
// 結構使われているようだ!
var testMsg: String!
testMsg = "test"
if testMsg != nil {
    print(testMsg)
}
 
 

タグ:

+ タグ編集
  • タグ:
最終更新:2017年12月05日 15:10