はじめに
なんとなくself.email = email
みたいに使ってるけど意味を理解して使わないと不意打ちのエラーや、既存のコードを壊さないように修正するのが無理だと思ったのでまとめようと思いました。
大まかなselfの使い方
- クラスの中で現在の
インスタンス
にアクセスする時に利用する。
なんでわざわざself
を使うのか?
例:
class User {
var name: String
init(name: String) {
self.name = name
}
}
上記の例の場合、init
の引数にname
があり、User
構造体のなかにもname
というプロパティが定義されています。
この場合
init(name: String) {
name = name
}
ってかくと、どっちがどっちかわからなくなりますよね?それを防ぐために使います。(こうするとエラーが起きますね)
self
とつけてるほうがUser
クラスで定義したプロパティで、ついてないほうが引数です。
ちなみに
init(nickName: String) {
name = nickName
}
のようにするとself
をつけなくてもいいです。
- クロージャ内でインスタンスをキャプチャするために
self
をつける
*
キャプチャとは
クロージャが定義された時点で、クロージャが外部の変数や定数を保持することです
色々用語があってわかりにくいので実装例をあげますね
class Example {
var value = 10
func doSomething() {
let closure = { [weak self] in
guard let instance = self else { return }
print(self.value)
}
closure()
}
}
- この場合では
self
をキャプチャ -
self
はExsample
クラスのインスタンスを指し、その中のvalue
を使えるようにしています。
これをこう思いました
「え?クラスの中にクロージャがかかれてるならself
つけなくてもよくない?」
しかし、これはswift
のルールで「そういうもの」らしいです。
ちなみにクロージャについて知らない人は「名前がない関数」としてこの記事を読んでください。
- 型(class, enum, struct)そのものを使いたいとき
// 型そのものを参照する
class Dog {
var name: String
required init(name: String) {
self.name = name
}
func bark() {
print("\(name) is barking!")
}
}
// インスタンスを生成する
func createDogInstance() {
let dogType: Dog.Type = Dog.self
let myDog = dogType.init(name: "Buddy")
myDog.bark() // Output: Buddy is barking!
}
あまり書くことがないので、どういう時型そのものを使いたい時と型そのものを操作しない時の違いを書いておきます
-
型そのものを使いたい時
結論: 新しいものを作りたい時
例:モンハンで新しいキャラクターを作りたくなった時、まず性別を選ぶと思います
let characterType = Female.self
これで女性のキャラクターを選ぶ
let newCharacter = characterSex.init()
これでキャラクターを作成 -
型そのものを操作しない
結論: 既存のものを使う時
例:
let myCharacter = Female()
もうすでにいるキャラクターを使う
型そのものを操作する: 新しいものを作ったり、選んだりしたい時に使います。
型そのものを操作しない: もう決まったものをそのまま使う時に使います。
用語の意味
参照
オブジェクト(データ)の「場所」を指し示すこと
class Person {
var name: String
init(name: String) {
self.name = name
}
}
ここでいう参照とは例えばiPhoneのアプリのメモリ内でPerson
インスタンスが保存されてる場所のこと
実際に参照するのは
let person1 = Person(name: "Taro")
こんな感じ
強参照
あるインスタンス(h)が他のインスタンス(Hoge)を参照する際のデフォルト(何も設定しなかった時)の参照方法です
class Hoge {}
var h: Hoge? = Hoge()
循環参照
強参照が相互に依存し合い、メモリが解放されない状態になること
どういうことか?
class Person {
var name: String
var closure: (() -> Void)?
init(name: String) {
self.name = name
self.closure = { [self] in
print("My name is \(self.name)")
}
}
}
var person: Person? = Person(name: "Taro")
self.closure = { [self] in
print("My name is \(self.name)")
}
このクロージャ内でのself.name
の self
はPeroson
インスタンスを参照すること
ただ、Person
インスタンスもクロージャを参照([self]を使っているので)しているので循環参照が起きている
対策としては
class Person {
var name: String
var closure: (() -> Void)?
init(name: String) {
self.name = name
self.closure = { [weak self] in
if let self {
print("My name is \(self.name)")
}
}
}
}
のように[weak self]
をつける
参考文献
-
selfの意味
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/methods/
(The self property
の箇所に記述があります。)
https://ramble.impl.co.jp/7560/#toc3
https://teratail.com/questions/284199 -
クロージャの中に書く場合
https://docs.swift.org/swift-book/documentation/the-swift-programming-language/closures/#Capturing-Values -
[weak self]
について詳しく
https://zenn.dev/mhackit/articles/a0b1c6e780c3c6aabe45
https://qiita.com/reo0612/items/b0d1ee00ebf3a0e7c857
https://qiita.com/neppana_developer/items/5538971b84a3b6d23926
https://qiita.com/hinakko/items/e6272661abdba9f77c5e
https://supportdoc.net/support-swift/reference.html#:~:text=%E3%80%8C%E5%8F%82%E7%85%A7%EF%BC%88Reference%E3%80%81%E3%83%AA%E3%83%95%E3%82%A1%E3%83%AC%E3%83%B3%E3%82%B9%EF%BC%89,%E5%90%8D%E3%81%A7%E8%A1%A8%E3%81%99%E3%81%93%E3%81%A8%E3%81%A7%E3%81%99%E3%80%82