Swift ざっくり文法 (4)
- Class
import Foundation class Myclass { let msg:String let name:String? init(msg:String = "hello") { self.msg = msg self.name = nil } init(msg:String = "hello", name:String) { self.msg = msg self.name = name } func hello() { var helloMsg:String if let user = name { helloMsg = user + "san" + msg } else { helloMsg = msg } print(helloMsg) } }
import UIKit class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let myObj = Myclass() myObj.hello() // hello let myObjWithMsg = Myclass(msg: "good night") myObjWithMsg.hello() // good night let myObjWithName = Myclass(name: "Alex") myObjWithName.hello() // Alex、hello let myObjWithMsgAndName = Myclass(msg: "good night", name: "Alex") myObjWithMsgAndName.hello() // Alex、good night } --- }
- Convenience initializer
class Myclass { let msg:String let name:String? - init(msg:String = "hello") { - self.msg = msg - self.name = nil - } - init(msg:String = "hello", name:String) { + init(msg:String, name:String) { self.msg = msg self.name = name } + convenience init (msg:String = "hello") { + self.init(msg: msg, name: "Anonymous") + } }
class ViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let myObj = Myclass() - myObj.hello() // hello + myObj.hello() // Anonymous, hello let myObjWithMsg = Myclass(msg: "good night") - myObjWithMsg.hello() // good night + myObjWithMsg.hello() // Anonymous, good night - let myObjWithName = Myclass(name: "Alex") - myObjWithName.hello() // Alex、hello let myObjWithMsgAndName = Myclass(msg: "good night", name: "Alex") myObjWithMsgAndName.hello() // Alex、good night } }
convenience initializerを使うと、複数のinitializerがあるときに、別のinitializerを呼ぶことができる。
- stored property と、computed property
- stored propertyは、定数・変数で定義される
- computed propertyは、関数を介して値をやり取りする。値を保持しておらず、設定値を内部的に宣言しておいた定数や変数に設定して保管する
class Circle { var radius:Double = 1.0 // stored property var area:Double { // computed property get{ // property への参照 return radius * radius * Double.pi } set(meseki){ // property への値の設定 radius = sqrt(meseki / Double.pi) } } } let myCicle = Circle() print("\(myCicle.radius)") // 1.0 print("\(myCicle.area)") // 3.14159265358979 myCicle.area *= 2 print("\(myCicle.radius)") // 1.4142135623731 print("\(myCicle.area)") // 6.28318530717959 myCicle.radius = 3.0 print("\(myCicle.radius)") // 3.0 print("\(myCicle.area)") // 28.2743338823081
read only の property
class Circle { var radius:Double = 1.0 var area:Double { get{ return radius * radius * Double.pi } - set(meseki){ - radius = sqrt(meseki / Double.pi) - } } } let myCicle = Circle() myCicle.radius = 3.0 print("\(myCicle.radius)") // 3.0 print("\(myCicle.area)") // 28.2743338823081 + myCicle.area = 300 // error: cannot assign to property: 'area' is a get-only property
Read onlyであれば以下のようにも書ける
class Circle { var radius:Double = 1.0 var area:Double { - get{ return radius * radius * Double.pi - } } }
- property observer ( propertyに値がsetされたことをwillSet, didSetで知ることができる )
- willSetは値が更新される直前に呼ばれ、新しくsetされる値に
newValue
でアクセスできる - didSetは値が更新された直後に呼ばれ、更新前の値に
oldValue
でアクセスできる
- willSetは値が更新される直前に呼ばれ、新しくsetされる値に
class Player { var times = 0 var level:Int { willSet { print("------") print("willSet \(newValue)") } didSet { if oldValue != level { times += 1 print("\(times) update\n\(oldValue) -> \(level)") } else { print("no changes") } } } init () { level = 0 } } var thePlayer = Player() thePlayer.level = 10 thePlayer.level = 10 thePlayer.level = 20 // ------ // willSet 10 // 1 update // 0 -> 10 // ------ // willSet 10 // no changes // ------ // willSet 20 // 2 update // 10 -> 20
- Class property
class Car { static var count = 0 var moving = false func start() { Car.count += 1 moving = true } func stop() { if Car.count > 0 { Car.count -= 1 moving = false } } } let car1 = Car() let car2 = Car() print("\(Car.count)") // 0 car1.start() car2.start() print("\(Car.count)") // 2 car2.stop() print("\(Car.count)") // 1
- Computed class propety
class MyClass { static var radian:Double = 0.0 class var degree:Double { get { return radian * 90/Double.pi } set(dosu){ radian = dosu * Double.pi/90 } } } MyClass.degree = 18 let katamuki = MyClass.degree print("\(katamuki)") // 18.0 MyClass.radian = Double.pi/2 let katamuki2 = MyClass.degree print("\(katamuki2)") // 45.0
- Class method
class Message { class func hello() -> String { return "hello" } } let msg = Message.hello() print(msg)
- Access Right
- access rightを省略すると
internal
になる。 - class が
fileprivate
だと、property/methodをinternal
にすることはできない。 - fileprivate(set) だとfile外からは、read onlyになる
- access rightを省略すると
access right | --- |
---|---|
open | --- |
public | Inheritanceとoverrideができない。 |
internal | module外からアクセスできない |
fileprivate | ファイル外からアクセスできない |
private | class外からアクセスできない |
- Extension
class Player { var name:String = "" func hello() { print("やあ!" + name) } } extension Player { var who:String { get { return name } set(value) { name = value } } func bye() { print("good bye " + name) } } let obj = Player() obj.who = "sam" // やあ!sam obj.hello() obj.bye() // good bye sam
- Inheritance
- A classを継承したB classを作成する。
- A class は、B classのsuperclass
- B class は、A classのsubclass
- B class -> A class
- 1つのclassが直接継承できるclassは一個だけ
- A classを継承したB classを作成する。
--- class ViewController: UIViewController { --- }
override func viewDidLoad() { // superclass のviewDidLoad()を上書き super.viewDidLoad() // superclassのメソッドを実行 // Do any additional setup after loading the view, typically from a nib. } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. }
- final ( 継承を禁止したいclass, override されては困るメソッドに付ける。 )
final class MyClass { func hello() { print("hello") } }
class MyClass { final func hello() { print("hello") } }
- Protocol ( classが必ず実装しなければならないpropertyやmethodを指定した仕様書のようなもの。実装しないとエラーになる。 )
- 読み書き可能なpropertyには、
{get set}
をつける - protocolは他のprotocolを継承できる
- 読み書き可能なpropertyには、
protocol GameProtocol { var gamePoint:Int {get} func hit() func miss() } - class MyGame:GameProtocol { + class MyGame:GameProtocol { // protocol requires function 'miss()' with type '() -> ()'; do you want to add a stub? private var total = 0 var gamePoint: Int { return total } func hit() { total += 10 print("hit! +10") } - func miss() { - total /= 2 - print("you miss, half") - } + // func miss() { + // total /= 2 + // print("you miss, half") + // } } let myGameObj = MyGame() myGameObj.hit() // hit! +10 print(myGameObj.gamePoint) // 10 myGameObj.miss() // you miss, half print(myGameObj.gamePoint) // 5 myGameObj.hit() // hit! +10 print(myGameObj.gamePoint) // 15
- Enumeration ( 複数の値を一つの型として宣言するために使用。Swiftの列挙型は値だけではなく、propertyやメソッドを持つことができる。)
enum MensSize { case S case M case L case XL } enum WomenSize { case XS, S, M, L } var mySize = MensSize.M mySize = .S // 型推論で、mySizeは、MensSize型になる var herSize:WomensSize herSize = .XS print(mySize) // S print(herSize) // XS
enum Direction:Int { case forward = 1 case backword // 2 case right // 3 case left // 4 } let muki1 = Direction.forward let muki2 = Direction.backword let muki3 = Direction.right let muki4 = Direction.left print(muki1.rawValue) // 1 print(muki2.rawValue) // 2 print(muki3.rawValue) // 3 print(muki4.rawValue) // 4
let muki5 = Direction(rawValue: 3) if let muki = muki5 { // muki5はnilかもしれないので、Optional Bindingになっている。 print(muki) }
- Enum で型を列挙する
enum Pattern { case Monotone(_:PColor) case Border(color1:PColor, color2:PColor) case Dots(base:PColor, dot1:PColor, dot2:PColor) enum PColor:String { case red = "red" case green = "緑" case yellow = "yellow" case white = "白" } } let shirt1 = Pattern.Monotone(.red) let shirt2 = Pattern.Border(color1: .white, color2: .red) let shirt3 = Pattern.Dots(base: .yellow, dot1: .white, dot2: .green)
- Propertyを持ったEnum
enum Ticket { case Gold, A, B static var name = "入場券" var area:String { get { switch self { case .Gold: return "Gold sheet" case .A: return "A sheet" case .B: return "B sheet" } } } var price:Int { get { switch self { case .Gold: return 24000 case .A: return 5000 case .B: return 2000 } } } } Ticket.name = "hoge live" print(Ticket.name) // hoge live let ticket = Ticket.A print(ticket) // A print(ticket.price) // 5000 print(ticket.area) // A sheet
- Methodを持ったEnum
enum Signal:String { case Green = "green" case Red = "red" var color:String { return self.rawValue } static func description() -> String { return "red or green signal" } func isRun() -> Bool { if self == .Green { return true } else { return false } } mutating func turn() { // 自身を変更するメソッドには `mutating` をつける必要がある if self == .Green { self = .Red } else { self = .Green } } } let text = Signal.description() print(text) // red or green signal var lamp = Signal.Green print(lamp.color) // green print(lamp.isRun()) // true lamp.turn() print(lamp.color) // red print(lamp.isRun()) // false
- Struct ( classと違って継承はできない )
struct Box { let width:Int let height:Int let size:String let tanka:Int var kosu:Int var price:Int { return tanka*kosu } init(width:Int, height:Int, tanka:Int, kosu:Int){ self.width = width self.height = height self.tanka = tanka self.kosu = kosu if (width+height) < 250 { size = "M" } else { size = "L" } } func sellprice(nebiki:Int = 0) -> Int { return price - nebiki*kosu } mutating func discount(count: Int) { kosu -= count } } var box = Box(width: 120, height: 80, tanka: 700, kosu: 6) print(box) // Box(width: 120, height: 80, size: "M", tanka: 700, kosu: 6) let selling_price = box.sellprice(nebiki: 10) print(selling_price) // 4140 box.discount(count: 5) print(box) // Box(width: 120, height: 80, size: "M", tanka: 700, kosu: 1)
- Structのcopy
- Structはclassのobjectと違って、参照型ではなく、値型
- つまりvariable aに入っているStructをvariable bに代入すると参照ではなく、値が複製されて新しいStructとして代入される
- String, Array, DictionaryはStruct、だから参照型ではなく、値型
class BoxClass { var color:String = "red" } struct BoxStruct { var color:String = "red" } // class let cBox1 = BoxClass() let cBox2 = cBox1 cBox2.color = "green" // struct let sBox1 = BoxStruct() var sBox2 = sBox1 sBox2.color = "green" print("cbox1: \(cBox1.color)") // green print("cbox2: \(cBox2.color)") // green print("sbox1: \(sBox1.color)") // red print("sbox2: \(sBox2.color)") // green
Structのsubscript
Struct, subscript
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 + String(size) if let value = data[key] { return value } else { return 0 } } set { let key = color + String(size) data[key] = newValue } } } var shoes = Stock(name: "Tiger") shoes["green", 24.5] = 3 shoes["green", 25.0] = 5 shoes["red", 26.0] = 5 print(shoes.name) // Tiger print(shoes["green", 24.5]) // 3 print(shoes["green", 25.0]) // 5 print(shoes["red", 26.0]) // 5 shoes["green", 24.5] -= 2 print(shoes["green", 24.5]) // 1 print(shoes["black", 24.5]) // 0
- Structのprotocol
protocol Monster { var monsterName:String {get} var hp:Int {get set} mutating func updateHP(pt:Int) } struct Bokemon: Monster { private(set) var monsterName: String // propertyがread onlyなので、private(set)を付ける var hp: Int mutating func updateHP(pt: Int) { hp += pt } } var monster = Bokemon(monsterName: "swifty", hp: 200) print(monster.monsterName) // swifty print("HP \(monster.hp)") // 200 monster.updateHP(pt: 30) print("HP \(monster.hp)") // 230