Swiftの文法などのメモ

最近Swiftの勉強をしていて、詳細!Swiftを読みながらメモを書いた。
他のSwift本と読み比べはしてないので比較は出来ないけど、サンプル数多いし説明もわかりやすいので良いと思う。

以下のメモはブログに公開はしてるけど、自分が後で見返す際に書いたメモなので、他の誰が見てもよくわからないと思う。

数値の3桁区切り

  • 数字はアンダースコア付けれる(可読性向上)
    • 122_100_100 は 122100100と評価される

タプル

  • 復数の値を扱える。型がバラバラでも良い。
    • 配列と似ているが、タプルは追加や削除したりなどは出来ない。
    • 変数の上書きは可能
let product = ("Swift",2014,10.2)
var guest:(String, String, Int) = ("ほしかわ","star",22)
guest = ("star","hoshi",11)
println(guest)
println(guest.0)
println(guest.1)
  • jsonみたいな書き方もできるみたいだ
let tapleLabel = (price:100,tax:8)
let seikyugaku = tapleLabel.price + tapleLabel.tax
println(seikyugaku)

演算子

  • trueとfalseのトグル
flower.hidden = !flower.hidden
  • 代入演算子にはいろいろある
    • /=, %=, &&=, ||=

条件分岐

  • switchでタプル使うとき、変数として値を受け取れる
let size = (4,10)
  switch size{
    case(0,0):
      println("0,0")
    case(5...10,5...10):
      println("規定サイズ")
    case(5...10,let height):
      println("高さ異常\(height)")
    case(let width,5...10):
      println("横異常\(width)")
    default:
      println("どっちも異常")
  }
  • switch で where 使える

for文

  • for in で辞書型を扱うとき、いい感じに扱える
let pokemon = [1:"ふしぎだね",2:"ふしぎそう",3:"ふしぎばな",4:"ひとかげ"]
for (k,v) in pokemon{
  println(v)
}
for pk in pokemon.keys{
  println(pk)
}
for pv in pokemon.values{
  println(pv)
}
  • for文に名前を付けてcontinueとかbreak出来る
xloop:for x in 1...10{
  yloop:for y in 1...10{
        if(x < y){
          print("\n")
            continue xloop
        }
        print((x,y))
      }
}

ストリング

  • 文字を繰り返すとか出来る
let stars = String(count:10,repeatedValue:Character("☆"))
println(stars)

配列

  • 繰り返しの配列とか作れる
var zeroList = [Double](count:10,repeatedValue:0.0)
println(zeroList)
  • ソート
    • sortは破壊的
    • sortedは非破壊的
  • 抽出
    • filterってかけて便利っぽい
let fil = zeroList.filter {$0 >= 5}
println(fil)

let nums = [10,20,30,40,35]
let num0to10 = filter(nums,{(num30:Int) -> Bool in
  return (num30 >= 20) && (num30 < 35)
})
println(num0to10)
  • すべての値で演算を行う
let plusOnes = nums.map{$0+1}
println(plusOnes)

辞書

  • 空の配列を作る
let sizeTable:[String:Any] = [:]
println(sizeTable)

let initDict = [String:Any]()
println(initDict)

オプショナル

  • OptionalValueがnilだったら別の値を使いたい、というとき
    • 以下の例はcountがnilなので2を使う
var count:Int?
let value = 250 * (count ?? 2)
println(value)
var str:String? = "Swift"
if let mes = str{
  println(mes + "world")
}else{
  println("hello world")
}
  • オプショナルチェインニング
    • ドットシンタックスでアクセスするときに、該当の値がnilでもエラーを回避する
class Player {
  var magic:Magic? = Magic()
}

class Magic {
  var spell:String = "puipui"
}

---------
var user:Player = Player()
var spell = user.magic?.spell as String!
println(spell)

関数

  • 可変長引数的なやつ
func sum(numbers:Double...) -> Double{
  var total:Double = 0
  for num in numbers{
    total += num
  }
  return total
}

println(sum(1,2,3,4,3,3,4,3,3))
  • 引数に初期値を設定する
    • 引数3つあって、そのうち1つだけ初期値なしとかも出来るけど、呼ぶときはフォーマット合わせる必要ある。
func customer(who:String = "客") -> String{
  return who + "様こんちは"
}
println(customer(who:"ほしかわ"))
println(customer())
  • 関数の引数は基本的にletだけど、varと明示すれば書き換えられる
func price(var yen:Int) -> Int{
  let tax = 1.08
  yen = Int(floor(Double(yen)*tax))
  return yen
}

println(price(100))
  • 外部引数名
    • 関数を使うときの引数を指定させる
    • 外部引数名と引数名が同じの場合、#つけるといける
func bmi(weight kg:Double, height cm:Double)->Double{
  if cm == 0 {return -1}
  var result = kg/pow(cm*0.01,2)
  result = round(result*10)/10.0
  return result
}
func kngk(#tnk:UInt,ks:UInt) -> UInt{
  return tnk*ks
}

println(bmi(weight:55,height:170))
println(kngk(tnk:250,ks:3))
  • 引数や戻り値が配列の関数
    • Arrayのように型を指定する
func arrayByInt(#array:Array<Int>, num:Int) -> Array<Int>{
  var result = Array<Int>()
  for value in array{
    result.append(value*num)
  }
  return result
}

println(arrayByInt(array:[1,2,5,6,4,6],num:3))
func calc(#a:Int, b:Int) -> Int{
  return a + b;
}
func calc(#c:Int, d:Int) -> Int{
  return c + d;
}
func calc(#a:Int, b:Int, c:Int) -> Int{
  return a + b + c;
}

println(calc(a:1,b:2))
println(calc(c:1,d:2))
println(calc(a:1,b:2,c:3))
  • ジェネリックな関数
    • 引数の方を()のように指定することで、型を未定のまま定義できる
func makeArray<T>(items:T ...) -> [T]{
  var array = [T]()
  for item in items {
    array += [item]
  }
  return array
}

println(makeArray(3,5,3,3,5,"fa"))
println(makeArray("23213","ffa","lfajf"))
  • 関数の引数を関数にする
    • 引数の関数の引数の型とかもかく
    • 引数なのか関数なのかわけがわからなくなってきた
    • 型をたくさん書くのだるい
func helloUser(user:String) -> String {
  return("\(user)さん、はろー")
}
func command(someFunc:String -> String,user:String) -> String{
  let msg = someFunc(user)
    return msg
}

println(command(helloUser,user:"hoshikawa"))
  • returnで関数を返すことも出来る
    • 戻り値の型をちゃんと書くこと、それ以外はJSと似てる
    • なのでソースコードは書かない

クロージャ

// クロージャ
let closureNum = [1,4,0,5,2,4]
let array1 = map(closureNum, {(let v:Int) -> Int in
  return v * 2
})
println(array1)
  • 型推論が適用されるので型宣言を省略出来る
  • 戻し値の式だけでreturnも省略できる
let array3 = map(closureNum, {v in v * 2})
println(array1)
let array4 = map(closureNum){$0 * 2}
println(array4)
//クロージャ
func dicMap(var dic:Dictionary<String,Int>, closure:(String, Int) -> (String, Int))
  -> Dictionary<String,Int>{
    for (key,value) in dic{
      let (theKey,newValue) = closure(key,value)
        dic[theKey] = newValue
    }
    return dic
}

// dicMapを使う
let abcDic = ["a":3,"b":6,"c":1]
let result = dicMap(abcDic){(key:String,value:Int)->(String,Int) in
  return (key,value*2)
}
println(result)

Class

class MyClass{
  let msg:String
  let name:String?

  init(msg:String = "hello"){
    self.msg = msg
  }
  init(msg:String,name:String){
    self.msg = msg
      self.name = name
  }

  func hello(){
    var helloMsg:String
    if let user = name {
      helloMsg = user+"さん。"+msg
    } else{
      helloMsg = msg
    }
    println(helloMsg)
  }
}

----------------

let myObj = MyClass(msg:"MyClass")
myObj.hello()
let myObj2 = MyClass(msg:"MyClass",name:"starhoshi")
myObj2.hello()
  • convenience init
    • initを呼ぶinitを作れる。引数をみると何が呼ばれるのか、違いがわかる
class MyClass{
  let msg:String
  let name:String

  init(msg:String,name:String){
    self.msg = msg
    self.name = name
  }

  convenience init(msg:String = "hello"){
    self.init(msg:msg,name:"匿名")
  }

  func hello(){
    var helloMsg = name + "さん。" + msg
    println(helloMsg)
  }
}

-----------------

let myObj = MyClass(msg:"hello!")
myObj.hello()
let myObj2 = MyClass(msg:"hello!",name:"starhoshi")
myObj2.hello()
let myObj3 = MyClass()
myObj3.hello()
class MyGame{
  class let version:String = "1.0.0"
  class var userCount:UInt= 3
}
class MyClass{
  class func GoodMorning() -> String{
    return "GoodMorning"
  }
}

-------------------

let myObj4 = MyClass.GoodMorning()
println(myObj4)
  • Computedプロパティ
    • ↔Storedプロパティ
    • Computedプロパティそのものは値を保持していない
    • 参照に対してはget,設定に対してはsetメソッドを使う
      • computedプロパティを使う側からすれば、Storedプロパティと区別はつかない
class MyClass{
    var radius:Double = 1.0
    var area:Double{
        get{
            return radius * radius * M_PI
        }
        set(menseki){
            radius = sqrt(menseki / M_PI)
        }
    }
}

---------------

var myCircle = MyClass()
println(myCircle.radius)
println(myCircle.area)

myCircle.area *= 2
println(myCircle.radius)
println(myCircle.area)
  • プロパティオブザーバー
    • プロパティに値がセットされたことをwillSetとdidSetで監視できる
class MyClass{
    init(){
        level = 0
    }

    var times = 0;
    var level:Int{
        willSet{
            if level != newValue{
                println("\(level) -> \(newValue)")
            }
        }
        didSet{
            if oldValue != level{
                ++times
                println("\(times)回目の更新")
            }
        }
    }
}

----------------
var thePlayer = MyClass()
thePlayer.level = 10
thePlayer.level = 10
thePlayer.level = 15
//0 -> 10
//1回目の更新
//10 -> 15
//2回目の更新
  • lazyプロパティ
    • lazy var みたいにStoredプロパティにlazy付けうと遅延評価になる
    • 参照されるまで初期化されない
class MyClass(){
    lazy var home = HomeClass()
    func who(){
        println(home.owner)
    }
}

class HomeClass{
    var owner = "yoshiyuki oshige"
}

--------------------
var home = MyClass()
home.who()
classここから下は長くなるためソースはなし
  • アクセス権
    • クラス・プロパティ・メソッドにはアクセス権を設定できる
    • internal
      • 他のファイルからでもアクセス可能(デフォルト)
    • private
      • 同一ファイル内でのみアクセス可能
      • ptivare(set)とするとリードオンリーになる
    • public
      • どこからでもアクセス可能(一般には使用しない)
  • メソッドのオーバーライド
  • final - 継承やオーバーライドを禁止する
    • final class Human{}
    • final func method()
  • プロトコル
    • javaでいうinterface
  • extension
    • 既存のクラスを書き換えたり継承することなく機能を拡張できる
    • Stringとかintも拡張出来る
      • js のプロトタイプ拡張みたいな感じか

列挙型 enum

  • enumとcaseで記述する
    • 型推論が使えるので、.Sみたいに代入できる
    • enumで参照する値を作るためにはswitch caseでできる
enum MensSize{
    case S
    case M
    case L
    case XL
}
enum WomansSize{
    case S,M,L,XL
}
func packing(size:WomansSize) -> String {
  var stuff:String
    switch size {
      case .S:
        stuff = ".S"
      case .M:
        stuff = ".M"
      case .L:
        stuff = ".L"
      case .XL:
        stuff = ".XL"
    }
  return stuff
}
-----------------
println(MensSize.L)
println(WomansSize.S)
var mySize = MensSize.M
mySize = .S
println(packing(.M))
  • enumに値を定義する
    • 普通にイコールでいける
    • Intで最初だけ数値指定した場合、あとのは1ずつ増えていく
enum Direction:Int{
    case forward = 1
    case backword
    case right
    case left
}
-------------------
println(Direction.backword.rawValue)
  • enumに関数を定義する
enum Prize:Int{
    case Gold = 1,Silver,Bronze,Four,Five
    func description() -> String{
        switch self{
        case .Gold:
            return "優勝"
        case .Silver:
            return "準優勝"
        case .Bronze:
            return "じゅんじゅん優勝"
        case .Four, .Five:
            return "入賞"
        }
    }
---------------------
let myRank = Prize.Bronze
println(myRank.description())
}
  • enumで型を列挙する
  • enumの中でenumを使う
    • アクセスするにはswitch case使わないとだめ?
enum Pattern {
    case Monotone(PColor)
    case Border(c1:PColor,c2:PColor)
    enum PColor:String{
        case red = "red"
        case green = "green"
        case blue = "blue"
    }
}
----------------------------
let shirt1 = Pattern.Border(c1: .red, c2: .green)
switch shirt1 {
case .Border(let c1, let c2):
    println(c1.rawValue,c2.rawValue)
}

struct 構造体

クラスと同じような機能を持ち、書式もほぼ同じ。
だが継承をしないのでスーパークラスを設定する書式はない。

  • structでは初期値設定できる
//初期値なし
struct ColorBox{
  var width:Int
  var height:Int
  var color:String
}
// 初期値有り
struct WhiteBox{
  var width:Int = 100
  var height:Int = 100
  var color:String = "white"
}
--------------------
var redBox = ColorBox(width: 100, height: 100, color: "red")
var theBox = WhiteBox()
println(theBox.width)
  • classと同じくイニシャライザを作れる
    • init()
  • classは参照型だが、structは値型
    • structはコピーを作成する
  • 関数とかもclassと同じく作れる
    • だが構造体自身のプロパティを変更する際に関数を使ってできない
    • mutating をつける
      • mutatingを付けたメソッド内でプロパティの変更を行う
struct Line{
    var p1:Point
    var p2:Point
    mutating func move(#h:Int,v:Int){
        p1.h += h
        p1.v += v
        p2.h += h
        p1.v += v
    }
}
------------------------
theLine.move(h:50,v:20)
let p1 = theLine.p1
let p2 = theLine.p2
println(p1.h,p1.v)
println(p2.h,p2.v)
  • subscript
    • 構造体の要素に[]を使ってアクセスできる
    • structa[1], structB["a",2]みたいにアクセスする
struct Stock {
  var name:String
    var data:[String:Int] = [:]
    init(name:String){
      self.name = name
    }
  subscript(color:String,size:Double) -> Int{
    get {
      let key = color + size.description
        if let value = data[key]{
          return value
        }else{
          return 0
        }
    }
    set{
      let key = color + size.description
        data[key] = newValue
    }

  }
}
------------------------------
var addixStock = Stock(name: "addix")
addixStock["green",24.5] = 4
addixStock["green",24.0] = 1
addixStock["green",24.5] = 7
addixStock["green",24.0] += 1
println(addixStock["green",24.0])
println(addixStock["green",24.5])