最近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)
let tapleLabel = (price:100,tax:8)
let seikyugaku = tapleLabel.price + tapleLabel.tax
println(seikyugaku)
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("どっちも異常")
}
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)
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だったら別の値を使いたい、というとき
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")
}
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))
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とつける
- swift 1.1だと使えないようでエラーになる
- クラスメンバについて、参考になりそう
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
- メソッドのオーバーライド
- オーバーライドするときはメソッドの前に
override
つける
- オーバーライドしたメソッドの中でsuper.medthod()よべばスーパークラスのが実行される
- final - 継承やオーバーライドを禁止する
- final class Human{}
- final func method()
- プロトコル
- extension
- 既存のクラスを書き換えたり継承することなく機能を拡張できる
- Stringとかintも拡張出来る
- 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 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 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 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と同じくイニシャライザを作れる
- classは参照型だが、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])