Swift Learning


node
var spaceship: SKSpriteNode!
var bird = SKSpriteNode()
let player = SKSpriteNode(imageNamed: "girl")
var hearts: [SKSpriteNode] = []
______________________
toggle
var toggle:Bool = true

 func toggleTest() {
  if(toggle){
    videoNode.play()
    toggle = false;
 }else{
   videoNode.pause()
   toggle = true;
 }
_________________________
配列
var word: [String] = []  //空の要素
var namber = [String]()
var data = Array()

var hearts: [SKSpriteNode] = []
var possibleEnemies = ["ball", "hammer", "tv"]
var obstacles: [SKSpriteNode] = []
var items = [String]()
var teleport = [CGPoint]()
var scores: [Int] = [0, 0]
__________________
CGPoint
anchorPoint の初期値は
CGPoint(x: 0.5, y: 0.5)
scene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
ImageNode.anchorPoint = CGPoint(x: 0.5, y: 0.5)//center
ImageNode.position = CGPoint(x: size.width * 0.5, y: size.height * 0.5)
let center = CGPoint(x: frame.midX, y: frame.midY)
label.text = "Hello World!"
label.position = CGPoint(x: self.frame.midX + 200, y: self.frame.midY + 450)
_________________________
SKLabelNode
var scoreLabel: SKLabelNode!
var score: Int = 0 {
didSet {
scoreLabel.text = "SCORE: \(score)"
}
}
class HelloLabel: SKLabelNode {
 init(fontNamed: String) {
   super.init(fontNamed: fontNamed)
   self.text = "Hello, World!"
   self.fontSize = 65;
   self.position = CGPoint(x: 400, y: 500);
 }
}
class GameScene: SKScene {
 override func didMoveToView(view: SKView) {
//let myLabel = SKLabelNode(fontNamed:"Chalkduster")
//myLabel.text = "Hello, World!";
//myLabel.fontSize = 65;
//myLabel.position = CGPoint(x: 400, y: 500);
 let myLabel = HelloLabel(fontNamed: "Chalkduster")
 self.addChild(myLabel)
 }
}
func createScore() {
    scoreLabel = SKLabelNode(fontNamed: "Optima-ExtraBlack")
    scoreLabel.fontSize = 24
    scoreLabel.position = CGPoint(x: frame.midX, y: frame.maxY - 60)
    scoreLabel.text = "SCORE: 0"
    scoreLabel.fontColor = SKColor.black
// scoreLabel.fontName = "Avenir"
// scoreLabel = SKLabelNode(text: "kaisu: 0kai")
    addChild(scoreLabel)
}
________________________
Button(spritekit)

TappedNodes(参照)

//////////////////////
変数・定数 / データ型

// 定数は let
// 変数は var

let msg: String = "hello world"

// Int型で定数定義
let i: Int = 10
let i = 10

// Float Double
let d = 53.8

// String
let s = "hello"

// Bool true/false
let flag = true

var x = "five"
x = String(5)

 
演算子

// 数値
print(10 / 3) // 3
print(10.0 / 3) // 3.3333
print(10 % 3) // 1

var y = 10
//y = y + 5
y += 5
print(y) // 15


// 文字列
print("hello " + "world")
print("y is \(y)")
print("y2 is \(y * 2)")


// 論理値 true false
print(true && false) // false
print(true || false) // true
print(!true) // false

 
条件分岐(if / switch)

// if文
let score = 40
let result: "" // String

// 基本
if score > 80 {
    result = "great"
} else if score > 60 {
    result = "good"
} else {
    result = "so so ..."
}

// 条件演算子
// 条件 ? A : B
result = score > 80 ? "great" : "so so ..."



// switch文
let num = 15

// 基本
switch num {
case 0:
    print("zero")
case 1, 2, 3:
    print("small")
case 4...6:
    print("4/5/6")
case 7..<9:
    print("7/8")
case let n where n > 20:
    print("\(n) is huge!")
default:
//    print("n.a.")
    break
}

 
繰り返し(for / while)

// for 変数 in データの集合 { 処理 }
// break
// continue

for i in 0...5 {
    if i == 3 {
//        break
        continue
    }
    print(i)
}

// while

var n = 10

while n < 3 {
    print(n)
    n += 1
}

//repeat {
//    print(n)
//    n += 1
//} while n < 3

 
配列

// 配列は全て中身が同じ型になる
// 可変長で、繰り返し処理も可能

// 基本
var scores: [Int] = [50, 40]

// 型省略
var scores = [50, 40]

// 取り出し
print(scores[0]) // 50

// 更新
scores[1] = 30

// その他
print(scores.count) // 2
print(scores.isEmpty) // false


// 空の配列
var names = [String]()

// 追加
names.append("田中")
names.append("鈴木")
names += ["佐藤"]

// forで取り出し
for name in names {
    print(name)
}

 
集合(Set)

// 基本(setは重複無視される)
var winners: Set = [3, 5, 8, 8]

// 型の省略
var winners: Set = [3, 5, 8, 8]

// 取り出し
print(winners.contains(3))

// 追加
winners.insert(10)

// 削除
winners.remove(5)

// 空の集合
let s = Set()
print(s.isEmpty)

// 集合の演算
let a: Set = [1, 3, 5, 8]
let b: Set = [3, 5, 8, 9]

print(a.union(b)) // 和集合
print(a.intersection(b)) // 積集合
print(a.subtracting(b)) // 差集合

 
タプル

// タプルは、最初に定義したときに長さが固定(可変長ではない)
// また、型の場所も固定になる(最初の定義時に1番目が文字列型、二番目が数値型だったら、再代入する場合も1番目が文字列型、二番目が数値型でなければならず、違う場合エラーが出る)

var items = ("apple", 5)
print(items.0)
items.1 = 8
print(items)

let (product, amount) = items
print(product)
print(amount)

let (product, _) = items
print(product)

var items = (product: "apple", amount: 5)
print(items.product)

 
辞書(Dictionary)

// 基本
var sales: Dictionary<string, int=""> = ["a": 200, "b": 300]

// 型を省略
var sales = ["a": 200, "b": 300]

// 更新
sales["b"] = 500

// 辞書からの取り出しはオプショナル型を含む可能性があるためunwrap
print(sales["a"] ?? "n.a.")

// 値の追加
sales["c"] = 400

// countで数を取り出す
print(sales.count)

// タプルで分けて取り出す
for (key, value) in sales {
    print("\(key): \(value)")
}

// 空の辞書
let d = [String: Int]()
print(d.isEmpty)

 
Optional型

// nilの可能性を含む型
// 値を取り出す場合はunwrapする必要がある

// 基本
let s: Optional = nil

// 省略形
let s: String? = nil

// unwrapその1
if s != nil {
    print(s!) // unwrap
}

// unwrapその2 (Optional Binding)
if let value = s {
    print(value)
}

// unwrapその3
print(s ?? "this is nil!")

 
inoutキーワード

// 関数の引数は基本は「定数」となる
// 引数で受けた変数に再代入したい場合はinoutキーワードを使う

func add10(x: inout Int) {
    x = x + 10
    print(x)
}

var i = 10
add10(x: &i) // 20
print(i) // 20(iの中身が再代入された値で保存される)

 
 
まとめ

Swiftはバージョンで互換性がなくなって過去のバージョンで作ってたアプリが壊れるらしい。

////////////////////////////////////////////////////////////////////////////
Class
基本

// クラスは「型」として扱う
// 頭は大文字

class User {
    let name: String // propertyと呼ぶ
    var score: Int // property
    init() {
        self.name = "me!"
        self.score = 23
    }
}

// 基本
let user: User = User()

// 省略形
let user = User() // instance

// アクセス・値の変更
print(user.name)
print(user.score)
user.score = 26
print(user.score)

 
イニシャライザ

// 初期化メソッドのこと

class User {
    let name: String
    var score: Int
		
    // イニシャライザ使用時
    init(_ name: String, _ score: Int) {
        self.name = name
        self.score = score
    }
		
    // 引数がなかった時(default設定)
    init() {
        self.name = "bob"
        self.score = 30
    }
}

//let tom = User(name: "tom", score: 23)
let tom = User("tom", 23)
print(tom.name)
print(tom.score)

let bob = User()
print(bob.name)
print(bob.score)

 
計算プロパティ(getとset)

// プロパティを動的に計算させることも可能

class User {
    let name: String
    var score: Int
		
    // 計算プロパティ
    var level: Int {
        get {
            return Int(self.score / 10)
	    // 自明の時はselfの省略可能
        }
        set {
	    // 渡された値をnewValueで受け取ることができる
            if newValue >= 0 {
                score = newValue * 10
            }
        }
    }
		
      // getのみの場合
//    var level: Int {
//        return Int(score / 10)
//    }

    init(_ name: String, _ score: Int) {
        self.name = name
        self.score = score
    }
}

let tom = User("tom", 23)

// getが動く
print(tom.level) // 23/10 = 2

// setに対して値を渡す
tom.level = 5
// すると、scoreが書き換わる
print(tom.score) // 50
// マイナスの値は、newValue >= 0の条件より反応しない
tom.level = -3
// したがって、変化せず50のまま
print(tom.score) // 50

 
プロパティの値の監視(willSetとdidSet)

// willSetとdidSetでプロパティの値の変化を監視できる

class User {
    let name: String
    var score: Int {
		
	// プロパティの値が変わる前の処理
        willSet {
            print("\(score) -> \(newValue)")
	    // newValueで変化後の値を取得可能
        }
				
	// プロパティの値が変わった後の処理
        didSet {
            print("Changed: \(score - oldValue)")
	    // newValueで変化後の値を取得可能
        }
    }
		
    // プロパティが最初に初期化される時は
    // willSetとdidSetは実行されない
    init(_ name: String, _ score: Int) {
        self.name = name
        self.score = score
    }
}

let tom = User("tom", 23)
tom.score = 53
tom.score = 40

 
メソッド作成

class User {
    let name: String
    var score: Int
    init(_ name: String, _ score: Int) {
        self.name = name
        self.score = score
    }
    // method
    func sayHi(_ msg: String) {
        print("\(msg) \(name)")
    }
}

let tom = User("tom", 23)
tom.sayHi("hola")

 
継承

class User {
    let name: String
    var score: Int
    init(_ name: String, _ score: Int) {
        self.name = name
        self.score = score
    }
		
    func sayHi() {
        print("hi \(name)")
    }
    // 頭にfinalをつけるとoverrideされない
}

class AdminUser: User {
    func sayHello() {
        print("hello \(name)")
    }
		
    // 親クラスメソッドの上書き
    override func sayHi() {
        print("[admin] hi \(name)")
    }
}

let tom = User("tom", 23)
let bob = AdminUser("bob", 33)
print(bob.name)
print(bob.score)
bob.sayHi()
bob.sayHello()

 
型プロパティ、型メソッド

class User {
    let name: String
    var score: Int
		
    // 頭にstaticで型プロパティ
    static var count = 0
		
    init(_ name: String, _ score: Int) {
        self.name = name
        self.score = score
				
        // インスタンス化されるたびに、+1
        User.count += 1
    }
    func sayHi() {
        print("hi \(name)")
    }
		
    // override可能な型メソッドにする場合はstaticではなくclass func
    class func getInfo() {
        print("\(count) instances")
    }
}

class AdminUser: User {
    func sayHello() {
        print("hello \(name)")
    }
    override func sayHi() {
        print("[admin] hi \(name)")
    }
    override class func getInfo() {
        print("[admin] \(count) instances")
    }
}

User.getInfo() // 0

let tom = User("tom", 23)
User.getInfo() // 1

AdminUser.getInfo() // 1

let bob = AdminUser("bob", 33)
AdminUser.getInfo() // 2

 
型キャスト(as)

// as  : キャストが成功すると保証されるときに使用(アップキャストなど)
// as! : 強制ダウンキャストの際に使用
// as? : ダウンキャストが成功するか分からない場合に使用(失敗すると戻り値はnil)

class User {
    let name: String
    init(_ name: String) {
        self.name = name
    }
}
class AdminUser: User {}

let tom = User("tom")
let bob = AdminUser("bob")

// User型の配列
// AdminUser型はUser型を継承していることをswiftが判別してくれていて
// エラー出ない
let users: [User] = [tom, bob]

for user in users {
		
    // as?(型キャスト)
    // あるクラスを、他のクラスに変換すること
    // if let文と組み合わせて、
    // AdminUserのみ名前を表示させている
		
    // こっちは一旦User型のuserをAdminUser型に変えてみて、
    // うまくいく場合はuにuserが代入される
    if let u = user as? AdminUser {
        print(u.name)
    }
	
    // こっちはまずuserがAdminUser型か確認している
    // User型のuserをAdminUser型に変えて、
    // 且つoptional型をunwrapする
    if user is AdminUser {
        let u = user as! AdminUser
        print(u.name)
    }
}

 
protocol

// クラスに対して「このプロパティやメソッドは絶対実装してね」という約束をさせるために利用する
// Protocolは継承と違って複数適合させることができる
// Protocol自体がProtocolを継承できる

protocol Printable {
    // 読み込み
    var type: String { get }
	
    // 読み書き可能
    var count: Int { get set }
	
    func printout()
}

class User: Printable {
    let type = "Laser"
    var count = 0
    let name: String
	
    init(_ name: String) {
        self.name = name
    }
	
    func printout() {
        count += 1
        print("\(type): \(count)")
    }
}

let tom = User("tom")
tom.printout()
tom.printout()
tom.printout()

 

extension

// 既存の型に新しいプロパティやメソッドを追加できる仕組み

// String型の拡張
extension String {
    var length: Int {
        return self.characters.count
    }
}

let msg = "hello"

// lengthが使用可能
print(msg.length)


// protocolとextensionを組み合わせる
protocol Printable {
    func printout()
}

extension Printable {
    func printout() {
        print("now printing...")
    }
}

// User型にprotocolを適用
class User: Printable {
    let name: String
    init(_ name: String) {
        self.name = name
    }
}

let tom = User("tom")
tom.printout() // now printing...

//////////////////////////////////////

https://whatsupguys.net/?p=2130

値型と参照型

// Int, Double, Array .. -> 値型
// Class -> 参照型
// 値型と参照型で再代入したときの挙動が異なる

// 値型の場合
var original = 10
var copy = original // originalの値そのもの
original = 20
print(original) // 20
print(copy) // 10

class User {
    var name: String
    init(_ name: String) {
        self.name = name
    }
}

// 参照型の場合
var original = User("tom")
var copy = original // originalが格納されている場所
original.name = "bob"
print(original.name) // "bob"
print(copy.name) // "bob"

 
構造体(struct)

// 構造体
// - クラスとほぼ同機能
// - 値型
// - 継承ができない
// - extension, protocolは使える
// 基本的に一回作ったら値が変わってほしくないようなデータに使用

//class User {
struct User {
    var name: String
    init(_ name: String) {
        self.name = name
    }
	
    // 本来構造体では値の変更ができない
    // 明示的にmutatingを用いると値の変更が可能
    mutating func changeName() {
        self.name = name.uppercased()
    }
}

var original = User("tom")
var copy = original // copy: originalの値
original.name = "bob"
print(original.name) // bob
print(copy.name) // tom

 
列挙型(enum)

// 関連する値をまとめて型にする
// 列挙型は値型

// enumちょっとよくわからん、まだ勉強が必要

enum Direction {
    case right
    case left
}

var dir: Direction.right

switch (dir) {
case .right:
    print("right")
case .left:
    print("left")
}

enum Direction: Int {
    case right = 1
    case left = -1
}

print(Direction.right.rawValue)

 
ジェネリクス

// 汎用化されたデータ型

// TはTypeのT

//func getThree(x: Int) {
func getThree(x: T) {
    print(x)
    print(x)
    print(x)
}
// Int型だけでなく、どの型が引数に与えられても対応できる
getThree(x: 5)
getThree(x: "hello")
getThree(x: 2.3)

subscript

// クラス、構造体、列挙型などにインデックスをつけられる

class Team {
    var members = ["aaa", "bbb", "ccc"]
	
    // インスタンスにインデックスが付与されていた時反応
    subscript(index: Int) -> String {
        get {
            return members[index]
        }
        set {
            members.insert(newValue, at: index)
        }
    }
}

var giants = Team()
print(giants[1]) // bbb
giants[3] = "ddd"
print(giants[3]) // ddd

 
guard文

// 異常処理をわかりやすく書くための仕組み

// if letで書く場合
func sayHi(_ msg: String?) {
    if let s = msg {
        print(s)
    } else {
        print("value not set!")
    }
}

// early returnの場合
func sayHi(_ msg: String?) {
    if msg == nil {
        print("value not set!")
        return
    }
    print(msg!)
}

// guardで書く場合
func sayHi(_ msg: String?) {
    guard let s = msg else {
        print("value not set!")
        return
    }
    print(s)
}

sayHi(nil)
sayHi("hello")

 
例外処理

// 列挙型でエラーパターンを定義
enum LoginError: Error {
    case emptyName
    case shortName
}

class User {
    let name: String
    init(_ name: String) {
        self.name = name
    }
	
    // 例外発生の可能性がある場合、throwsを使う
    func login() throws {
        guard name != "" else {
            throw LoginError.emptyName
        }
        guard name.count > 5 else {
            throw LoginError.shortName
        }
        print("login success")
    }
}

let tom = User("tom")
let tom = User("takahashi")
let tom = User("")

// do catchでエラー表示
do {
    try tom.login()
} catch LoginError.emptyName {
    print("please enter your name")
} catch LoginError.shortName {
    print("too short")
}

 
Optional Chaining

// オプショナル型のnilチェックをスッキリ書くためのもの
// 変数が nil だったら nil を、そうではなかったらその値を含む Optional 型を返す
// nilだった場合も、単に返り値がnilになるだけでエラーにならない

// 非オプショナル型の場合...
//class User {
//    var name: String = ""
//}
//
//let user: User()
//user.name = "him"
//let s = user.name.uppercased()
//print(s)

// オプショナル型の場合
class User {
    // optional宣言の省略型
    var name: String? = ""
}

// optional宣言の省略型
var user: User?
user = User()

// Optional Chaining(後ろに?をつける)
user?.name = "him"
if let s = user?.name?.uppercased() {
    print(s)
}

 
暗黙的 unwrap optional

// Implicitly Unwrapped Optional
// 宣言で「!」をつけることで、値を使う時にUnwrapしなくてもいいOptional型だと理解する

// 通常のoptional型定義(後ろに?)
//var msg: String?

// Implicitly Unwrapped Optional(後ろに!)
var msg: String!
msg = "hello"

// 本来ならunwrap処理が必要であるが、
//if msg != nil {
//    print(msg!)
//}
// この場合はunwrap不要で利用できる
print(msg)
</string,>