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

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

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

Q&A

解決済

1回答

2557閲覧

swiftUI Cannot find ・・・・ in scope

masa328

総合スコア51

0グッド

0クリップ

投稿2021/11/22 11:54

編集2021/11/24 14:14

SwiftUIの素人です。エラーが消せないのでお知恵をいただきたくよろしくお願いします。
https://stackoverflow.com/questions/63765532/swiftui-how-to-run-a-timer-in-background/70046189#70046189
のサイトを参考に以下のように作成したのですが、エラーが出て理由がわかりません。

Stopwatch.swift

swiftui

1import SwiftUI 2 3struct Stopwatch: View { 4 var body: some View { 5 class Stopwatch: ObservableObject { 6 /// String to show in UI 7 @Published private(set) var message = "Not running" 8 9 /// Is the timer running? 10 @Published private(set) var isRunning = false 11 12 /// Time that we're counting from 13 private var startTime: Date? { didSet { saveStartTime() } } 14 15 /// The timer 16 private var timer: AnyCancellable? 17 18 init() { 19 startTime = fetchStartTime()//<----------- ① 20 21 if startTime != nil { 22 start() 23 } 24 } 25 } 26 27 // MARK: - Public Interface 28 29 extension Stopwatch { //<----------- ② 30 31 func start() { 32 timer?.cancel() // cancel timer if any 33 34 if startTime == nil { 35 startTime = Date() 36 } 37 38 message = "" 39 40 timer = Timer 41 .publish(every: 0.1, on: .main, in: .common) 42 .autoconnect() 43 .sink { [weak self] _ in 44 guard 45 let self = self, 46 let startTime = self.startTime 47 else { return } 48 49 let now = Date() 50 let elapsed = now.timeIntervalSince(startTime) 51 52 guard elapsed < 60 else { 53 self.stop() 54 return 55 } 56 57 self.message = String(format: "%0.1f", elapsed) 58 } 59 60 isRunning = true 61 } 62 63 func stop() { 64 timer?.cancel() 65 timer = nil 66 startTime = nil 67 isRunning = false 68 message = "Not running" 69 } 70 } 71 72 // MARK: - Private implementation 73 74 private extention Stopwatch { 75 func saveStartTime() { 76 if let startTime = startTime { 77 UserDefaults.standard.set(startTime, forKey: "startTime") 78 } else { 79 UserDefaults.standard.removeObject(forKey: "startTime") 80 } 81 } 82 83 func fetchStartTime() -> Date? { 84 UserDefaults.standard.object(forKey: "startTime") as? Date 85 } 86 } 87 } 88} 89 90struct Stopwatch_Previews: PreviewProvider { 91 static var previews: some View { 92 Stopwatch() 93 } 94} 95

ContentView.swift

import SwiftUI struct ContentView: View{ @ObservedObject var stopwatch = Stopwatch() //<----------- ③ var body: some View { VStack { Text(stopwatch.message) Button(stopwatch.isRunning ? "Stop" : "Start") { if stopwatch.isRunning { stopwatch.stop() } else { stopwatch.start() } } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }

3つエラーが出てまして、
①Cannot find 'fetchStartTime' in scope
②Declaration is only valid at file scope
③Generic struct 'ObservedObject' requires that 'Stopwatch' conform to 'ObservableObject'
です。

何かが足りないのだと思うのですが、解決できません。
ものすごく基礎的なことをお聞きしていると思うのですが、お教えいただければ幸いです。

よろしくお願いします。


その後、hoshiさんの③のコメントにあるようにstructに使えないということで、質問の上にあったStopwatch.swiftを

import SwiftUI class Stopwatch2: ObservableObject { /// String to show in UI @Published private(set) var message = "Not running" /// Is the timer running? @Published private(set) var isRunning = false /// Time that we're counting from private var startTime: Date? { didSet { saveStartTime() } }//<--④ /// The timer private var timer: AnyCancellable?// <--⑤ init() { startTime = fetchStartTime() //<--⑥ if startTime != nil { start() //<--⑦ } } } // MARK: - Public Interface extension Stopwatch { func start() { timer?.cancel() // cancel timer if any. <--⑧ if startTime == nil { //<--⑨ 以下同様のエラー多数 startTime = Date() } message = "" timer = Timer .publish(every: 0.1, on: .main, in: .common) .autoconnect() .sink { [weak self] _ in guard let self = self, let startTime = self.startTime else { return } let now = Date() let elapsed = now.timeIntervalSince(startTime) guard elapsed < 60 else { self.stop() return } self.message = String(format: "%0.1f", elapsed) } isRunning = true } func stop() { timer?.cancel() timer = nil startTime = nil isRunning = false message = "Not running" } } // MARK: - Private implementation private extension Stopwatch { func saveStartTime() { if let startTime = startTime { UserDefaults.standard.set(startTime, forKey: "startTime") } else { UserDefaults.standard.removeObject(forKey: "startTime") } } func fetchStartTime() -> Date? { UserDefaults.standard.object(forKey: "startTime") as? Date } }

のようにし、③のエラーは消えたのですが、その代わりclass Stopwatch下の各変数がCannot find '????' in scopeになってしまいます。
例えば④であれば、Cannot find 'saveStartTime' in scopeclass ⑤であればCannot find 'AnyCancellable' in scopeclass です。
class Stopwatch2: ObservableObject {以下を同一スコープの中に入れる方法がわかりません。

質問の仕方が稚拙とは思いますがよろしくお願いします。

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

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

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

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

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

hoshi-takanori

2021/11/22 13:34

① と ② は extention を書く場所がおかしい (そもそも extension にする必要はないような…) からですね。 また、③ は @ObservedObject にできるのはクラスだけで、Stopwatch のような struct には使えません。(というか、Stopwatch をプロパティにする意味が分かりません。)
masa328

2021/11/22 14:36

hoshi-takanoriさん ありがとうございます。 おっしゃる通り、extension StopwatchおよびfetchStartTimeのfuncがあるprivate extention Stopwatchもextensionやprivate extentionを取りましたが①のCannot find 'fetchStartTime' in scopeは出たままです。というか、それらを取ったらStopwatch{ }が2つできてしまって??? また、おっしゃている >また、③ は @ObservedObject にできるのはクラスだけで、Stopwatch のような struct には使えません。(というか、Stopwatch をプロパティにする意味が分かりません。) は、struct Stopwatch: View { の中に class Stopwatch: ObservableObject { を入れるのではなく、struct ContentView: View{ の中に含めるということでしょうか? すいません、多分わかる方には、馬鹿なような質問かもしれませんが、もうすこしお付き合いいただきたくよろしくお願い申し上げます。
guest

回答1

0

自己解決

hoshi-takanoriさんのコメントを良く読み返して解決しました。

① と ② の extention内のFuncは上のclassiの中に(structからclassiに変更)入れ込むことで解決しました。

ありがとうございました。

投稿2021/12/02 13:14

masa328

総合スコア51

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問