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

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

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

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

Q&A

解決済

1回答

457閲覧

関数の中で配列に要素を追加したいのですが、エラーが発生しました。

soarthesky

総合スコア3

Xcode

Xcodeはソフトウェア開発のための、Appleの統合開発環境です。Mac OSXに付随するかたちで配布されています。

Swift

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

0グッド

0クリップ

投稿2022/07/23 14:06

前提

SwiftUIで食材を賞味期限順に並び替えるシステムを作っています。
配列に要素を追加しようとしたところ以下のエラーメッセージが発生しました。

実現したいこと

  • 日付でソートした配列の順序変更を、その他の配列(nameとdate)にも適用させる

発生している問題・エラーメッセージ

Cannot use mutating member on immutable value: 'self' is immutable

該当のソースコード

Swift

1func dateSort()-> Int{ 2 for dataForConversion in date { 3 let formattedDate = dateFromString(string: dataForConversion, format: "y/M/d") 4 formattedDateArray.append(formattedDate)//ここにエラーが出ます 5 } 6 let dateSorted = formattedDateArray.enumerated().sorted { $0.element < $1.element } 7 for indexPathRow in 0..<formattedDateArray.count { 8 let originalIndex = dateSorted[indexPathRow] 9 dateArray.append(date[originalIndex.offset])//ここにエラーが出ます 10 nameArray.append(name[originalIndex.offset])//ここにエラーが出ます 11 } 12 return nameArray.count 13 }

全体のコード

Swift

1import SwiftUI 2struct ContentView: View { 3 var name:[String] = ["玉ねぎ", "じゃがいも", "にんじん", "牛肉", "きのこ"] 4 var date:[String] = ["2022/7/25","2022/7/24","2022/7/26","2022/7/27","2022/7//28"] 5 var formattedDateArray:[Date] = [] 6 var dateArray:[String] = [] 7 var nameArray: [String] = [] 8 func dateFromString(string: String, format: String) -> Date { 9 let formatter: DateFormatter = DateFormatter() 10 formatter.calendar = Calendar(identifier: .gregorian) 11 formatter.dateFormat = format 12 return formatter.date(from: string)! 13 } 14 func dateSort()-> Int{ 15 for dataForConversion in date { 16 let formattedDate = dateFromString(string: dataForConversion, format: "y/M/d") 17 formattedDateArray.append(formattedDate) 18 } 19 let dateSorted = formattedDateArray.enumerated().sorted { $0.element < $1.element } 20 for indexPathRow in 0..<formattedDateArray.count { 21 let originalIndex = dateSorted[indexPathRow] 22 dateArray.append(date[originalIndex.offset]) 23 nameArray.append(name[originalIndex.offset]) 24 } 25 return nameArray.count 26 } 27 @State private var searchText = "" 28 var body: some View { 29 VStack { 30 NavigationView { 31 List { 32 ForEach(searchResults, id: \.self) { name in 33 Text(name) 34 } 35 } 36 .searchable(text: $searchText, prompt: "食材の検索") 37 .keyboardType(.default) 38 .navigationTitle("全ての食材") 39 } 40 List(0 ..< dateSort(), id:\.self) { item in 41 Text(nameArray[item]) 42 } 43 } 44 } 45 var searchResults: [String] { 46 if searchText.isEmpty { 47 return name 48 } else { 49 return name.filter{ $0.contains(searchText) } 50 } 51 } 52}

質問

エラーの原因はなんでしょうか。
もしよろしければ、mutatingとはなんなのかと解決方法も教えてほしいです。

試したこと

XCodeの指示に従ってmutating funcにしてみましたが、

Swift

1mutating func dateSort()-> Int{ 2 for dataForConversion in date { 3 let formattedDate = dateFromString(string: dataForConversion, format: "y/M/d") 4 formattedDateArray.append(formattedDate) 5 } 6 let dateSorted = formattedDateArray.enumerated().sorted { $0.element < $1.element } 7 for indexPathRow in 0..<formattedDateArray.count { 8 let originalIndex = dateSorted[indexPathRow] 9 dateArray.append(date[originalIndex.offset]) 10 nameArray.append(name[originalIndex.offset]) 11 } 12 return nameArray.count 13 }

こちらでエラーが発生しました。
Cannot use mutating member on immutable value: 'self' is immutableとでました。

Swift

1List(0 ..< dateSort(), id:\.self) { item in 2 Text(nameArray[item]) 3 }

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

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

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

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

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

guest

回答1

0

ベストアンサー

基本的な前提の共有ができていませんので、どこから説明すれば良いのかわからないところではありますが・・
mutatingキーワードは値型の中に定義されているプロパティをインスタンスメソッドから変更するためのSwiftの仕組みのようです(雑すぎますでしょうか・・)。

Modifying Value Types from Within Instance Methods
(機械翻訳)構造体や列挙型は値型です。デフォルトでは、値型のプロパティは、そのインスタンスメソッド内から変更することはできません。
しかし、特定のメソッド内で構造体や列挙型のプロパティを変更する必要がある場合、そのメソッドのミューテート動作を選択することができます。この場合、メソッド内部からそのプロパティをミューテート(変更)することができ、メソッドが終了すると、その変更は元の構造体に書き戻されます。また、このメソッドは暗黙のselfプロパティに完全に新しいインスタンスを割り当てることができ、この新しいインスタンスはメソッドの終了時に既存のインスタンスを置き換えます。
https://docs.swift.org/swift-book/LanguageGuide/Methods.html#ID239

値型と参照型の特徴は次のリンク先などを翻訳して見てみると良いかもしれません。

Structures and Enumerations Are Value Types
(機械翻訳)値型とは、変数や定数に代入されるとき、あるいは関数に渡されるときに値がコピーされる型のことです。
https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html#ID88
Classes Are Reference Types
(機械翻訳)参照型は、値型とは異なり、変数や定数に代入される際や関数に渡される際にコピーされることはない。コピーではなく、同じ既存のインスタンスへの参照が使用されます。
https://docs.swift.org/swift-book/LanguageGuide/ClassesAndStructures.html#ID89

できるだけ質問欄のコードを活かして修正するとしたら次のような感じはいかがでしょうか。
*nameとdateが別の配列になっているとソートなどの扱いが面倒になりますので、これらもstructなどでまとめて扱う方が良いかもしれません

swift

1import SwiftUI 2struct ContentView: View { 3 var name:[String] = ["玉ねぎ", "じゃがいも", "にんじん", "牛肉", "きのこ"] 4 var date:[String] = ["2022/7/25","2022/7/24","2022/7/26","2022/7/27","2022/7/28"] 5 var formattedDateArray:[Date] = [] 6 var dateArray:[String] = [] 7 var nameArray:[String] = [] 8 func dateFromString(string: String, format: String) -> Date { 9 let formatter: DateFormatter = DateFormatter() 10 formatter.calendar = Calendar(identifier: .gregorian) 11 formatter.dateFormat = format 12 return formatter.date(from: string)! 13 } 14 // イニシャライザでプロパティを設定してみました 15 init() { 16 for dataForConversion in date { 17 let formattedDate = dateFromString(string: dataForConversion, format: "y/M/d") 18 formattedDateArray.append(formattedDate) 19 } 20 let dateSorted = formattedDateArray.enumerated().sorted { $0.element < $1.element } 21 for indexPathRow in 0..<formattedDateArray.count { 22 let originalIndex = dateSorted[indexPathRow] 23 dateArray.append(date[originalIndex.offset]) 24 nameArray.append(name[originalIndex.offset]) 25 } 26 } 27 @State private var searchText = "" 28 var body: some View { 29 VStack { 30 NavigationView { 31 List { 32 ForEach(searchResults, id: \.self) { name in 33 Text(name) 34 } 35 } 36 .searchable(text: $searchText, prompt: "食材の検索") 37 .keyboardType(.default) 38 .navigationTitle("全ての食材") 39 } 40 .navigationViewStyle(StackNavigationViewStyle()) 41 // nameArray.countにしてみました 42 List(0 ..< nameArray.count, id:\.self) { item in 43 Text(nameArray[item]) 44 } 45 } 46 } 47 var searchResults: [String] { 48 if searchText.isEmpty { 49 return name 50 } else { 51 return name.filter{ $0.contains(searchText) } 52 } 53 } 54}

コメントありがとうございます。
追記です。

structでまとめるとはどういうことでしょうか?

nameとdateをstructで1行のデータにまとめる感じです。
次のようなイメージでしょうか。

swift

1import SwiftUI 2struct ContentView: View { 3 var array: [SampleStruct] = [ 4 SampleStruct(name: "玉ねぎ", date: "2022/7/25"), 5 SampleStruct(name: "じゃがいも", date: "2022/7/24"), 6 SampleStruct(name: "にんじん", date: "2022/7/26"), 7 SampleStruct(name: "牛肉", date: "2022/7/27"), 8 SampleStruct(name: "きのこ", date: "2022/7/28"), 9 ] 10 @State private var searchText = "" 11 var body: some View { 12 VStack { 13 NavigationView { 14 List { 15 ForEach(searchResults, id: \.self) { name in 16 Text(name) 17 } 18 } 19 .searchable(text: $searchText, prompt: "食材の検索") 20 .keyboardType(.default) 21 .navigationTitle("全ての食材") 22 } 23 .navigationViewStyle(StackNavigationViewStyle()) 24 List(0 ..< sortedArray.count, id:\.self) { item in 25 Text(sortedArray[item].name) 26 } 27 } 28 } 29 var searchResults: [String] { 30 let nameArray = array.map({ $0.name }) 31 if searchText.isEmpty { 32 return nameArray 33 } else { 34 return nameArray.filter{ $0.contains(searchText) } 35 } 36 } 37 var sortedArray: [SampleStruct] { 38 array.sorted(by: { $0.formattedDate < $1.formattedDate }) 39 } 40} 41struct SampleStruct { 42 var name: String 43 var date: String 44 var formattedDate: Date { 45 dateFromString(string: date, format: "y/M/d") 46 } 47 func dateFromString(string: String, format: String) -> Date { 48 let formatter: DateFormatter = DateFormatter() 49 formatter.calendar = Calendar(identifier: .gregorian) 50 formatter.dateFormat = format 51 return formatter.date(from: string)! 52 } 53}

SwiftUIのチュートリアルを一通りやってみるのも良いかもしれませんね。
https://developer.apple.com/tutorials/swiftui/building-lists-and-navigation

投稿2022/07/23 16:12

編集2022/07/23 23:29
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

soarthesky

2022/07/23 16:18

回答ありがとうございます! structでまとめるとはどういうことでしょうか? 教えていただけると嬉しいです。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問