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

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

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

Q&A

解決済

1回答

567閲覧

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

emthy

総合スコア17

0グッド

0クリップ

投稿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)

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

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

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

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

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

guest

回答1

0

ベストアンサー

applewatch側で用いたRecordをiphone側ファイルでも同様に宣言しなくてはいけないのでしょうか。

https://github.com/MilanistaDev/WatchConnectivitySampleForSwiftUI2

GitHubのコードを見ると、
RecordとAnimalの
File inspectorのTarget Membershipは
次のものにチェックが入っているようですね。

  • WatchConnectivitySampleForSwiftUI2
  • WatchConnectivitySampleForSwiftUI2 WatchKit Extension

WatchOSの方に定義しているけれども、
iOSでも使えるようにしている感じでしょうか。


ContentViewのListの中にある.toString()がDateに対応していないというエラーが出てしまいました。

Data+Extensionというファイルがあるみたいです。
ここでtoString()のメソッドを定義しているみたいです。


記事を書いている人も、記事にしたタイミングでミスもあるかもしれませんので、
GitHubのコードを取得した方が早いかもしれませんね。


SwiftUIのチュートリアルも参考にしてみると良いかもしれませんね。
https://developer.apple.com/tutorials/swiftui/creating-a-watchos-app

File inspectorのサンプル画像です。

投稿2022/09/16 04:51

編集2022/09/16 04:54
退会済みユーザー

退会済みユーザー

総合スコア0

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

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

emthy

2022/09/16 05:54

Githubにコードが添付されていること初めて気づきました💦 教えていただいた通りにTargetMembership使い、Data+Extensionファイル追加したところうまく動作しました!! 本当にありがとうございます🙇
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問