LoginSignup
51
44

More than 5 years have passed since last update.

SwiftにおけるClassとStructの使い分け

Last updated at Posted at 2015-12-13

Swiftでは型を定義する場合、次のように Value Types が好まれる傾向にあります。

  • Swift standard library の多くの型が Value Types で実装されている
    • Swift 2.0 - struct: 87 enum: 8 class: 4
  • Prefer structs over classes by Github Swift Style Guide

このエントリでは 「Referece TypesValue Types の違い」、「それぞれの型の使い分けについての私の考え」をまとめてみました。

Reference TypesValue Types の違い

= の挙動

  • Reference Types
    • インスタンスへの参照ができる
    • インスタンス自体はコピーされない
  • Value Types
    • インスタンスがコピーされる

Reference Type

class Point {
    var x: Float = 0.0
    var y: Float = 0.0
}
let p1 = Point()
let p2 = p1
p2.x = 5.0

p1.x // x: 5.0, y: 0.0
p2.x // x: 5.0, y: 0.0
  • p1, p2 には 同じ Point インスタンスの参照が保持される
  • 結果、p2.xへの変更が p1.x の値にも反映される

Value Type

struct Point {
    var x: Float = 0.0
    var y: Float = 0.0
}
let p1 = Point()
var p2 = p1
p2.x = 5.0

p1.x // x: 0.0, y: 0.0
p2.x // x: 5.0, y: 0.0
  • p1, p2 は別々の Point インスタンス
  • 結果、p2.x への変更は p1.x の値に反映されない

Mutability

  • Reference TypesValue Typeslet の意味するところが異なる。

Reference Types

  • let: 参照が不変
class Point {
    var x: Float = 0.0
    var y: Float = 0.0
}
let p = Point()
p = Point() // ERROR Cannot assign to value: 'p' is a 'let' constant
  • インスタンスの値は変更可能
p.x = 5.0

Value Types

  • let: インスタンス自体が不変。プロパティの値も変更不可。(プロパティがlet, varに関係ない)
struct Point {
    var x: Float = 0.0
    var y: Float = 0.0
}

let p = Point()
p.x = 10.0 // ERROR Cannot assign to property: 'p' is a 'let' constant

Reference Types は、letで変数を定数化しても、参照先が変更できないだけで、参照先のインスタンスの値は変更できてしまう。
よって、Value Types の方がMutabilityの管理が容易。
Reference Types にて同様のことを実現しようとすると NSStringNSMutableString みたいな関係のクラスを自前で実装する必要がある。

ここまでのまとめ

= の挙動

  • Value Types
    • インスタンスが複製される
  • Reference Types
    • インスタンスへの参照ができる

Mutability

  • Value Types
    • let によりインスタンスの値(プロパティ含む)を不変にできる
  • Reference Types
    • let でインスタンスへの参照は不変になるが、インスタンスの値は変更可能

使い分け: Reference Types / Value Types

通常、型はmutabilityの管理が容易な方が好ましい。
まず Value Types で要件を満たせないかを検討する。

Value Types

  • = において、インスタンスが複製され、独立性が維持された方が良い場合
let initialPoint = Point(x: 0, y: 0)
var circle = Shape(center: initialPoint)
let square = Shape(center: initialPoint)

// `circle` と `square` は独立したインスタンス
// それぞれが `center` を管理している
circle.center.x = 2 // {x: 2, y: 0}
square.center       // {x: 0, y: 0}

Reference Types

  • Cocoaのクラスを使う場合
    • XXXViewController, YYYTableViewCell など
  • インスタンスをMutableにして共有したい場合
 class Account {
   var balance = 0.0
 }

 class Person {
   let account: Account
   init(_ account: Account) {
     self.account = account
   }
 }

 let account = Account()

 let husband = Person(account)
 let wife = Person(account)

 husband.accout.balance += 1000
 wife.account.balance -= 500

 account.balance // 500

まとめ

Reference TypesValue Types の違い」、「使い分け: Reference Types / Value Types」についてまとめてみました。
Swift standard libraryが Value Types を多く用いているのは immutability を担保し易いからでしょう。
このエントリを書く上で色々なブログエントリを読んだのですが、
型を作る場合、まずはStructで実装できないか検討するのがSwift的に良いプラクティスなのかと思うようになりました。

References

51
44
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
51
44