はてな教科書の「プログラミング言語 Swift」を読んでます 4
https://github.com/hatena/Hatena-Textbook/blob/master/swift-programming-language.md
のんびり読んでいきます。
Reference types
参照型の値は、変数間で同じ状態を共有する。
参照型の変数の場合、オブジェクトの参照先をコピーして、オブジェクトの中身自体は共有してる、という感じ。
271> class DecoString { 272. var string: String 273. init(_ given: String) { 274. self.string = given 275. } 276. func printWithDecoration() { 277. print(string) 278. } 279. } 280> var decoStr1 = DecoString("first") decoStr1: DecoString = { string = "first" } 281> var decoStr2 = decoStr1 decoStr2: DecoString = { string = "first" } 282> decoStr1.string = "second" 283> decoStr2.printWithDecoration() second
Classes
コンストラクタはinit
で記述。
271> class DecoString { 272. var string: String 273. init(_ given: String) { 274. self.string = given 275. } 276. func printWithDecoration() { 277. print(string) 278. } 279. }
Automatic Reference Counting
- 参照型の値は参照カウント方式のメモリ管理が行われる
- コンパイル時に参照カウントの増減処理がコンパイラによって挿入される
- 変数にインスタンスへの参照が格納されるとき参照カウントは1増え、その変数がスコープを外れるとき参照カウントは1減る
- 参照カウントが1以上ならインスタンスはメモリ上に保持される(メモリリーク)
- 2つのインスタンスが互いに参照しあう場合は、片方を弱い参照にする
- 弱い参照の変数は必ず Optional である
- 弱い参照は
weak
キーワード、あるいはunowned
キーワードを使って設定する - クロージャは基本的にキャプチャした参照型の値について強い参照を持っている
- クロージャにおいても、必要に応じて
weak
やunowned
の弱い参照にする必要がある
- クロージャにおいても、必要に応じて
// キャプチャで `weak` の弱い参照にするときのシンタックス 310> class Dog { 311. } 312> let dog = Dog() dog: Dog = {} 313> let callDog = { [weak dog] (message: String) -> String in 314. return "\(dog!), \(message)." 315. } callDog: String -> String = 0x0000000101e13000 $__lldb_expr343`__lldb_expr_342.(closure #1) at repl342.swift 316> callDog("stay") $R58: String = "Dog, stay."
Properties and methods
Stored Properties
- Stored プロパティは let や var で値を保持する。
- enum型には持たせられない
- .propertyNameでアクセス可能
- lazyキーワードで遅延初期化が可能
// 遅延初期化の例 317> class DataFormatter { 318. var format: String = "" 319. } 320. 321. class DataPrinter { 322. lazy var formatter = DataFormatter() 323. var data: [String] = [] 324. } 325> 326> let printer = DataPrinter() printer: DataPrinter = { formatter.storage = nil data = 0 values } 327> printer.formatter $R59: DataFormatter = { format = "" } 328> printer $R60: DataPrinter = { formatter.storage = (format = "") { format = "" } data = 0 values }
Computed Properties
Computed プロパティでは他の情報から計算可能な値をプロパティとして提供できる。
少し計算して返していたメソッドなどを Computed
プロパティとして定義すると良さそうです。
329> struct Square { 330. var length : Double = 0.0 331. var area: Double { 332. get { 333. return pow(length, 2) 334. } 335. set(newArea) { 336. length = sqrt(newArea) 337. } 338. } 339. } 340> var square1 = Square() square1: Square = { length = 0 } 341> square1.length = 3.0 342> square1.area $R61: Double = 9 343> square1.area = 10 344> square1.length $R62: Double = 3.1622776601683795 345>
また、getブロックしか利用しない場合は、get/setブロックを省略することができます。
Property Observers
willSet
やdidSet
ブロックを用いてプロパティの値の変化の前後に何らかの処理を行うことができます。- 特に指定していない場合、各ブロックでnewValue や oldValue で変更の前後の値を得ることができます。
- またdidSetで値を別の値に変更することも可能です。
346> struct Dam { 347. let limit = 100.0 348. var waterLevel = 0.0 { 349. willSet { 350. print("\(newValue - waterLevel) will change") 351. } 352. didSet { 353. if waterLevel > limit { 354. print("Bursted") 355. waterLevel = limit 356. } 357. print("\(waterLevel - oldValue) did change") 358. } 359. } 360. } 361> var dam = Dam() dam: Dam = { limit = 100 waterLevel = 0 } 362> dam.waterLevel = 120 120.0 will change Bursted 100.0 did change
Type Properties
type
キーワードを使って、型に対する変数が作れます。いわゆるクラス変数。
Methods
- 型は関数を持つことができて、これをメソッドという
- メソッドの実装ではselfキーワードで自身を指す
- 自身の内部状態を変化させるものには
mutating
キーワードをfunc
の前につけます - enumの場合はselfに直接代入することで状態を変化させます
363> enum Weekly { 364. case Monday 365. case Tuesday 366. case Wednesday 367. case Thursday 368. case Friday 369. case Saturday 370. case Sunday 371. 372. mutating func past() { 373. switch self { 374. case .Monday: 375. self = .Tuesday 376. case .Tuesday: 377. self = .Wednesday 378. case .Wednesday: 379. self = .Thursday 380. case .Thursday: 381. self = .Friday 382. case .Friday: 383. self = .Saturday 384. case .Saturday: 385. self = .Sunday 386. case .Sunday: 387. self = .Monday 388. } 389. } 390. } // enum型はその中のどれか、みたいな形で初期化するのだった... 391> var day = Weekly() repl.swift:391:11: error: 'Weekly' cannot be constructed because it has no accessible initializers var day = Weekly() ^ 391> var day = Weekly.Monday day: Weekly = Monday 392> day.past() 393> day $R63: Weekly = Tuesday 394> day.past() 395> day $R64: Weekly = Wednesday 396> day.past() 397> day $R65: Weekly = Thursday
Type Methods
static
をつけることで、タイプメソッドとなります。Rubyのクラスメソッドのように、self
は型自身を指します。
メソッドは static
, プロパティは type
.
Subscripts
これ、数値によるUtil的なものか、case分の代わりに使うことがあるようにしか見えないのですが、書き始めると変わるのでしょうか...
398> struct OddNumbers { 399. subscript(index: Int) -> Int { 400. return index * 2 401. } 402. } 403> let odds = OddNumbers() odds: OddNumbers = {} error: could not fetch result -- Couldn't apply expression side effects : Couldn't dematerialize odds: corresponding symbol wasn't found 404> odds $R66: OddNumbers = {} 405> odds[3] $R67: Int = 6
今日はここまで...。