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

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

新規登録して質問してみよう
ただいま回答率
85.44%
変数

変数は、プログラミングにおいて値や文字列などのデータを保持できる仕組みを指します。自由に名前を付けることができるため、管理しやすくなるのが特徴です。プログラムで変数の宣言を行い、値を代入して利用。保持したデータが通用する範囲でローカル変数とグローバル変数に分けられます。

Swift

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

Q&A

解決済

1回答

916閲覧

値渡しした変数を別viewで型変換するとnilになってしまいます…

KaoruYoshida

総合スコア36

変数

変数は、プログラミングにおいて値や文字列などのデータを保持できる仕組みを指します。自由に名前を付けることができるため、管理しやすくなるのが特徴です。プログラムで変数の宣言を行い、値を代入して利用。保持したデータが通用する範囲でローカル変数とグローバル変数に分けられます。

Swift

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

0グッド

0クリップ

投稿2022/06/04 12:23

編集2022/06/04 12:29

前提

Calendarを表示し、選択日と今日の日付の差を取り出して
それを別のビューで四則演算をするシステムを作っております。

まずCalendarTestView内では、
選択日から今日までの日数をdayStringという変数で定義し、
それを@BindingでString型で定義したdayとして返しています。

そのdayをAchievementViewに値渡しし四則演算したいです。

値渡しし、AchivementViewでTextとして表示できたのですが、それをIntに型変換する際にnilエラーが出てしまいます。

実現したいこと

  • AchievementView内でdayを四則演算したい

エラーメッセージ

下のソースコードで「ここでエラー」と書いてあるところ、
dayをInt型に変換しているところに以下のエラーメッセージが発生しました。

Thread 1: Fatal error: Unexpectedly found nil while unwrapping an Optional value

dayがなぜnilになっているのか?どのように変えたらnilで無くなるのか?
SwiftUI初心者なので、理由含め教えてくだされば幸いです。

全体のコードはこちらです↓

該当のソースコード

CalendarTestView.swift

1import SwiftUI 2import FSCalendar 3import UIKit 4 5struct CalendarTestView: UIViewRepresentable { 6 @Binding var selectedDate: Date 7 func makeUIView(context: Context) -> UIView { 8 9 typealias UIViewType = FSCalendar 10 11 let fsCalendar = FSCalendar() 12 13 fsCalendar.delegate = context.coordinator 14 fsCalendar.dataSource = context.coordinator 15 16 return fsCalendar 17 } 18 19 func updateUIView(_ uiView: UIView, context: Context) { 20 } 21 22 func makeCoordinator() -> Coordinator{ 23 return Coordinator(self) 24 } 25 26 class Coordinator: NSObject, FSCalendarDelegate, FSCalendarDataSource { 27 var parent:CalendarTestView 28 29 init(_ parent:CalendarTestView){ 30 self.parent = parent 31 } 32 33 func calendar(_ calendar: FSCalendar, didSelect date: Date, at monthPosition: FSCalendarMonthPosition) { 34 // ***** 選択した日付をバインディングのselectedDateへ設定します 35 parent.selectedDate = date 36 } 37 38 } 39} 40 41struct CalendarApealView: View { 42 43 @Environment(\.presentationMode) var presentationMode: Binding<PresentationMode> 44 @State private var date: Date = Date() 45 @Binding var day: String //ここでdayを定義?? 46 var differString: String { 47 let calendar = Calendar.current 48 //today1は今日の日付 49 let today1 = Date() 50 let today2 = calendar.dateComponents([.year, .month, .day], from: today1) 51 let today3 = calendar.date(from: DateComponents(year: today2.year, month: today2.month, day: today2.day))! 52 let date2 = calendar.dateComponents([.year, .month, .day], from: date) 53 let date3 = calendar.date(from: DateComponents(year: date2.year, month: date2.month, day: date2.day))! 54 let result = calendar.dateComponents([.day], from: date3, to: today3) 55// UserDefaults.standard.set(differString, forKey: "differString") 56 return "\(result.day!)" 57 } 58 var body: some View { 59 VStack(){ 60 Text("When did you start this food style?") 61 .font(.title2) 62 CalendarTestView(selectedDate: $date) 63 .frame(height: 400) 64 HStack(){ 65 Text(differString) 66 .font(.title) 67 .padding() 68 .foregroundColor(Color(red: 0.324, green: 0.758, blue: 0.49)) 69 Text("Days") 70 .font(.title2) 71 } 72 Button(action: { 73 day = differString 74 self.presentationMode.wrappedValue.dismiss() 75 }) { 76 Text("confirm") 77 .font(.title2) 78 .padding(16) 79 .background(Color(red: 0.324, green: 0.758, blue: 0.49)) 80 .foregroundColor(Color.white) 81 .cornerRadius(10) 82 } 83 } 84 } 85}

AchievementView.com

1struct AchievementView: View { 2 @State var showsheet: Bool = false 3 @State var showinfo: Bool = false 4 init(){ 5 //ナビゲーションバーの背景色の設定 6 UINavigationBar.appearance().barTintColor = greenColor 7 } 8 9 @State private var day = "" 10 @State private var isShowSubView = false 11 var body: some View { 12 13 NavigationView { 14 HStack { 15 ZStack { 16 VStack{ 17 HStack { 18 ScrollView{ 19 Image("IMG_7771") 20 .resizable() 21 .clipShape(Circle()) 22 .overlay(Circle().stroke(Color.white, lineWidth: 2)) 23 .frame(width: 100, height: 100) 24 .shadow(radius: 5) 25 Text("Name") 26 .font(.title) 27 Text("Name Record ...") 28 .font(.title) 29 HStack{ 30 Text(day) 31 .font(.largeTitle) 32 .foregroundColor(Color(red: 0.324, green: 0.758, blue: 0.49)) 33 34 Text("DAYS") 35 .padding() 36 .font(.title) 37 38 Button(action: { 39 self.isShowSubView = true 40 }, label: { 41 Text("edit") 42 .foregroundColor(Color.gray) 43 }) 44 45 NavigationLink(destination: CalendarApealView(day: $day), isActive: $isShowSubView) { 46 EmptyView() 47 } 48 } 49 HStack{ 50 Text("\((Int(day))!*100)") //ここでエラー 51 .font(.largeTitle) 52 .foregroundColor(Color(red: 0.324, green: 0.758, blue: 0.49)) 53 Text("L") 54 .padding(.leading, 40) 55 .font(.title) 56 } 57 } 58 } 59 } 60 } 61 } 62 .navigationTitle("Achievement") 63 .toolbar{ 64 ToolbarItemGroup(placement: .navigationBarTrailing) { 65 Button { 66 showsheet.toggle() 67 } label: { 68 Label("Setting", systemImage: "gearshape") 69 } 70 .sheet(isPresented: $showsheet, content: { 71 SettingView() 72 }) 73 } 74 } 75 } 76 } 77} 78

補足情報(FW/ツールのバージョンなど)

macOS バージョン12.3.1
2.6 GHz 6コアIntel Core i7
Xcodeバージョン13.3.1

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

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

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

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

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

guest

回答1

0

ベストアンサー

dayがIntに変換できない場合はエラーになってしまうようですので、
次のように初期値を設定してみたらどうでしょうか。
(本当は計算する項目はあまりStringで扱わない方が良いのかもしれません)

@State private var day = "0"


You use optionals in situations where a value may be absent. An optional represents two possibilities: Either there is a value, and you can unwrap the optional to access that value, or there isn’t a value at all.
オプショナルは、ある値が存在しないかもしれない状況で使用します。オプショナルは、2つの可能性を表します。値があり、その値にアクセスするためにオプショナルをアンラップするか、あるいは値が全くないかです。

Because the initializer might fail, it returns an optional Int, rather than an Int. An optional Int is written as Int?, not Int. The question mark indicates that the value it contains is optional, meaning that it might contain some Int value, or it might contain no value at all. (It can’t contain anything else, such as a Bool value or a String value. It’s either an Int, or it’s nothing at all.)
イニシャライザが失敗する可能性があるため,Intではなく,オプションのIntを返しています.オプショナルなIntはIntではなくInt?と表記されます。クエスチョンマークは、それが含む値がオプションであることを示します。つまり、何らかのInt値を含むかもしれないし、全く値を含まないかもしれません。(Bool値やString値のような、他のものを含むことはできません。それはInt値であるか、または全く何もないかです)。
https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html#ID330

Swiftのオプショナルの型について、
Int型にnilを設定することはできませんが、
Int?はオプショナルのIntなのでnilを設定することができます。

(Int(day))!
このInt(day)の部分のコードについて、
dayが数値ではない"a"などの値も考えられるため
オプショナルのInt型(Int?)が返ってきます。
*数値ではない(Intに変換できない)場合はnilになります
""も数値に変換できませんのでnilになります

Once you’re sure that the optional does contain a value, you can access its underlying value by adding an exclamation point (!) to the end of the optional’s name. The exclamation point effectively says, “I know that this optional definitely has a value; please use it.” This is known as forced unwrapping of the optional’s value:
オプショナルに値があることを確認したら、オプショナル名の最後に感嘆符 (!) をつけてその値にアクセスすることができます。感嘆符は、「このオプショナルには確かに値があります。これは、オプショナル値の強制アンラップとして知られています。
https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html#ID332

この!は強制アンラップというそうですが、
オプショナルなInt型(Int?)を通常のInt型に変換することができます。

(Int(day))!の部分のコードでは、
オプショナルのInt型(Int?)はそのままでは計算できないため
!をつけてアンラップしていると思います。
ですがnilが設定されたオプショナルのInt型(Int?)はアンラップすることができずエラーになっていると思います。
「オプショナルに値があることを確認したら、」と公式のドキュメントに記載されている通り、
強制アンラップをする際はnilではないことを確認しないといけないようです。


dayの初期値に"0"を設定するのではなく、
別の実装としてもう一つ書いてみます。

Optional Binding
You use optional binding to find out whether an optional contains a value, and if so, to make that value available as a temporary constant or variable. Optional binding can be used with if and while statements to check for a value inside an optional, and to extract that value into a constant or variable, as part of a single action. if and while statements are described in more detail in Control Flow.
オプショナルバインドは、オプショナルに値が含まれているかどうかを調べ、含まれていれば、その値を一時的な定数または変数として使用できるようにするために使用します。オプショナルバインドは、if や while 文と一緒に使うことで、オプショナル内の値をチェックし、その値を定数や変数に取り込んで、一つの動作にすることができます。if と while 文については、制御フローで詳しく説明します。

swift

1if let actualNumber = Int(possibleNumber) { 2 print("The string \"\(possibleNumber)\" has an integer value of \(actualNumber)") 3} else { 4 print("The string \"\(possibleNumber)\" couldn't be converted to an integer") 5} 6// Prints "The string "123" has an integer value of 123"

https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html#ID333

オプショナルバインディングを使うと次のような感じでしょうか。
ちょっと冗長的かもしれません。。
オプショナルの型がnilではない場合に一時的な変数(ここではintという名前の変数にしました)に設定して、
ifのtrueの方を実行してくれます。
nilの場合はifのfalseの方を実行してくれます。

swift

1if let int = Int(day) { 2 Text("\(int*100)") 3 .font(.largeTitle) 4 .foregroundColor(Color(red: 0.324, green: 0.758, blue: 0.49)) 5} else { 6 Text("") 7 .font(.largeTitle) 8 .foregroundColor(Color(red: 0.324, green: 0.758, blue: 0.49)) 9}

投稿2022/06/04 14:32

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

KaoruYoshida

2022/06/05 09:22

解決しました。今回も本当にありがとうございます! オプショナル型は中々分かりづらいですね…勉強頑張ります笑
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.44%

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

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

質問する

関連した質問