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

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

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

解決済

SwiftUI iPhoneとapplewatchの相互通信可能アプリ作成

emthy
emthy

総合スコア16

1回答

0リアクション

0クリップ

241閲覧

投稿2022/09/16 02:25

前提

プログラミング初心者、そして初めての質問ですので、至らない点多々あると思いますが、xcode,アプリ作成に詳しい方、回答していただけたら幸いです。

SwiftUIでWatch 側のアニマルリストをタップすると選択されたアニマルの絵文字とテキストおよびタップ時の時刻をiPhone 側にバックグラウンドで送信し,iPhone のアプリ起動時に受信して画面更新するアプリを作ることを目標にしています。

使用開発ソフトはXcodeでiosAppWithWatchAppを選択しました。開発モジュールはstoryboardではなくswiftUIです。

参考にしたサイトは以下になっており、コードをコピペさせていただきました。
https://qiita.com/MilanistaDev/items/0ce079b255034be84472
成功例をコピぺしたにもかかわらず、うまく機能しなかったので、なぜエラーが発生してしまっているのか教えていただけると嬉しいです。

実現したいこと

ここに実現したいことを箇条書きで書いてください。

  • ▲▲機能を動作するようにする

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

エラーメッセージ(私の知識が乏しく、どのコードを載せれば解決につながるのか予想がつかなかったため、一応全てのファイルのコードを記します。) エラーは発生行付近にコメントアウトして記してあります。 iPhone側のファイル ・AnimalListApp(エラーなし) import SwiftUI @main struct AnimalListApp: App { var body: some Scene { WindowGroup { ReceiverView() } } } ・ContentView import SwiftUI struct ReceiverView: View { @StateObject var viewModel = ReceiverViewModel() var body: some View { List { //エラー① Generic parameter 'Content' could not be inferred,②Explicitly specify the generic arguments to fix this issue ForEach(viewModel.records, id: \.self) { record in VStack(alignment: .leading) { Text(record.animal.emoji + record.animal.name) .font(.body) .padding(.vertical, 4.0) Text(record.timeStamp.toString()) .font(.footnote) .foregroundColor(.gray) } } } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ReceiverView() } } ・ReceiverViewModel(追加ファイル) import WatchConnectivity final class ReceiverViewModel: NSObject, ObservableObject { @Published var records: [Record] = [] private let session: WCSession init(session: WCSession = .default) { self.session = session super.init() self.session.delegate = self session.activate() } } extension ReceiverViewModel: WCSessionDelegate { func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { if let error = error { print(error.localizedDescription) } else { print("The session has completed activation.") } } func sessionDidBecomeInactive(_ session: WCSession) { } func sessionDidDeactivate(_ session: WCSession) { } func session(_ session: WCSession, didRecieveUserInfo userInfo: [String : Any] = [:]) { guard let data = userInfo["record"] as? Data, let record = try? JSONDecoder().decode(Record.self, from: data) else { // エラー③ Cannot find 'Record' in scope return } self.records.append(record) } } applewatch側のファイル ・AnimalListApp(エラーなし) import SwiftUI @main struct AnimalListApp: App { @SceneBuilder var body: some Scene { WindowGroup { NavigationView { AnimalListView() } } WKNotificationScene(controller: NotificationController.self, category: "myCategory") } } ・ContentView import SwiftUI struct AnimalListView: View { private let viewModel = AnimalListViewModel() var body: some View { List { ForEach(animals, id: \.self) { animal in Button { // Send Animal viewModel.transfer(animal: animal) } label: { HStack(spacing: 16.0) { Text(animal.emoji) .font(.title) Text(animal.name) } .padding(.vertical, 20.0) } } } .listStyle(CarouselListStyle()) } } struct ContentView_Previews: PreviewProvider { static var previews: some View { AnimalListView() } } ・Record(追加ファイル、エラーなし) import Foundation struct Record: Hashable, Codable { var animal: Animal var timeStamp: Date } ・Animal(追加ファイル、エラーなし) import Foundation struct Animal: Hashable, Codable { var name: String var emoji: String } let animals: [Animal] = [ Animal(name: "ネコ", emoji: "🐱"), Animal(name: "イヌ", emoji: "🐶"), Animal(name: "ハムスター", emoji: "🐹"), Animal(name: "ドラゴン", emoji: "🐲"), Animal(name: "ユニコーン", emoji: "🦄"), ] ・AnimalListViewModel(追加ファイル、エラーなし) import WatchConnectivity final class AnimalListViewModel: NSObject { private let session: WCSession init(session: WCSession = .default) { self.session = session super.init() self.session.delegate = self session.activate() } func transfer(animal: Animal) { let record = Record(animal: animal, timeStamp: Date()) guard let data = try? JSONEncoder().encode(record) else { return } let userInfo: [String: Any] = ["record": data] self.session.transferUserInfo(userInfo) } } extension AnimalListViewModel: WCSessionDelegate { func session(_ session: WCSession, activationDidCompleteWith activationState: WCSessionActivationState, error: Error?) { if let error = error { print(error.localizedDescription) } else { print("The session has completed activation.") } } } ・NotificationController ・NotificationView ・ComplicationController は変更なしなので記載省かせていただきます。

試したこと

エラーについて検索をかけてみたのですが、該当する情報が見つからず、困っています。

全てのエラーはおそらく変数RecordがiPhone側のアプリに登録されていないことが原因なのですが、applewatch側で用いたRecordをiphone側ファイルでも同様に宣言しなくてはいけないのでしょうか。

試しにAnimal,Recordファイルをiphone側のファイルにコピペしてみましたが、次は別のエラーが発生し、
ContentViewのListの中にある.toString()がDateに対応していないというエラーが出てしまいました。

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

Xcode Version 13.4.1 (13F100)

以下のような質問にはリアクションをつけましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

リアクションが多い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

下記のような質問は推奨されていません。

  • 間違っている
  • 質問になっていない投稿
  • スパムや攻撃的な表現を用いた投稿

適切な質問に修正を依頼しましょう。

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
86.12%

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

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

質問する

関連した質問

同じタグがついた質問を見る