質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

Q&A

解決済

1回答

5947閲覧

[Swift] プロトコルで get set を指定したにもかかわらず set できない

MasakiHori

総合スコア3384

Swift

Swiftは、アップルのiOSおよびOS Xのためのプログラミング言語で、Objective-CやObjective-C++と共存することが意図されています

0グッド

0クリップ

投稿2017/06/11 01:21

編集2017/06/11 03:25

環境

  1. Xcode 8.3.3
  2. Swift 3.x

発生している問題

型がAny?で扱いにくいrepresentedObjectを扱いやすくるすため以下のようなプロトコルとエクステンションを作りました。

swift

1import Cocoa 2 3protocol RepresentedObjectable { 4 5 associatedtype RepresentedObject 6 7 var associatedObject: RepresentedObject? { get set } 8} 9 10extension RepresentedObjectable where Self: NSViewController { 11 12 var associatedObject: RepresentedObject? { 13 get { 14 return representedObject as? RepresentedObject 15 } 16 set { 17 representedObject = newValue 18 } 19 } 20}

しかし、このassociatedObjectに値を代入しようとするとcannot assign to property: 'self' is immutableというコンパイルエラーが発生します

swift

1class AAA: NSViewController, RepresentedObjectable { 2 3 typealias RepresentedObject = [String] 4 5 func hoge(_ s: [String]) { 6 associatedObject = s // ここでコンパイルエラー 7 } 8 9 func fuga() -> [String]? { 10 return associatedObject // こちらは問題ない 11 } 12}

お聞きしたいこと

  1. なぜ {get set}としているのに set できないのか
  2. どうすれば set できるようになるのか

以上よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

関係ありそうな、こんな記事がありました。

Protocol-Oriented Problems and the Immutable 'self' Error

引用1:

Swift

1enum Direction { 2 case None, Forward, Backward, Up, Down, Left, Right 3} 4 5protocol VehicleType { 6 var speed: Int { get set } 7 var direction: Direction { get } 8 mutating func changeDirectionTo(direction: Direction) 9 mutating func stop() 10} 11 12extension VehicleType { 13 mutating func stop() { 14 speed = 0 15 } 16} 17 18class Car: VehicleType { 19 var speed = 0 20 private(set) var direction: Direction = .None 21 22 func changeDirectionTo(direction: Direction) { 23 self.direction = direction 24 25 if direction == .None { 26 stop() 27 } 28 } 29}

引用2:

What does “Cannot use mutating member on immutable value: ‘self’ is immutable” mean?

Understanding the Error
There are three insights that help to clarify the error.

  1. Recall that the protocol VehicleType declares that stop() is a mutating method. We declared it like this because stop() changes the value of a property, speed, and we are required to mark it as mutating in case value types conform.
  2. VehicleType’s protocol extension provides a default implementation for stop().
  3. Car is a reference type.

引用3:

stop() is a mutating method, with a default implementation, that the compiler expects will change self. But Car is a reference type. That means the self—the reference to the Car instance that is used to call stop()—that is available within changeDirectionTo(_:) is immutable!

Thus, the compiler gives us an error because stop() wants to mutate self, but the self available within changeDirectionTo(_:) is not mutable.

引用4:

Three Solutions
There are three principal ways to solve this problem.

  1. Implement a non-mutating version of stop() on Car.
  2. Mark the VehicleType protocol as class only: protocol VehicleType: class { ... }.
  3. Make Car a struct.

Swiftの理解がまだ浅いため、解釈を間違えているかもしれませんが、今回の質問者さんのケースですと

  • associatedObjectのセッターはオブジェクトの状態を変化させる、暗黙的mutatingメソッドと解釈される...mutatingメソッドは通常不変なstructのプロパティを書き換えることができ、selfまでも書き換えられるらしいので(新しいstructのインスタンスができて、それを参照するようになるということ?)、このセッターは潜在的にselfを書き換えうる?
  • このプロパティに値をセットする時、暗黙の引数としてselfが渡される
  • Swiftは(structは許すが)classであるAAAのself書き換えを許さないためエラーを出す

という状況なんでしょうか...?
とりあえず筆者の方の第2の解決案の、プロトコルをclass専用にする方法で

Swift

1protocol RepresentedObjectable : class { 2 3 associatedtype RepresentedObject 4 5 var associatedObject: RepresentedObject? { get set } 6}

としてみるとどうでしょう。

投稿2017/06/11 10:09

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

MasakiHori

2017/06/11 11:24

class 専用のプロトコルにすることでコンパイル可能になりました 原因に関してはまだきちんと理解できてないのでいろいろ調べようと思います。 ありがとうございました
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問