问题描述
我正在研究 swiftUI 中的 Peer 连接,我创建了一个简单的 Todo 列表,使用 MultipeerConnectivity 将数据发送到关闭的设备。
我设法连接了 2 个设备并接收了数据(当 didReceive 数据触发时我在调试控制台上看到它),但我找不到解决我的 SwiftUI 视图没有更新的解决方案,我必须终止应用程序并重新启动以查看收到的项目。
我有一个带有@Published 数组存储的 DataManager 类:TodoModel,其中保存了所有待办事项。
使用 func newTodo 我将待办事项添加到数组并发送到另一个设备,视图在设备发送器中正确更新,但在设备接收器上没有。
class DataManager: ObservableObject {
let objectwillChange = PassthroughSubject<Void,Never>()
static let shared = DataManager()
typealias Storage = [TodoModel]
init() {
loadData()
}
@Published var isRefreshing : Bool = false { // debugging
willSet {
objectwillChange.send()
}
}
@Published var storage : [TodoModel] = []{
willSet {
objectwillChange.send()
}
}
var resource : String = ""
func loadData() {
if let data = UserDefaults.standard.data(forKey: "salva") {
do {
let decoder = PropertyListDecoder()
storage = try decoder.decode(Storage.self,from: data)
} catch {
debugPrint(error.localizedDescription)
}
}
}
func save() {
dispatchQueue.main.async {
self.objectwillChange.send()
let encoder = PropertyListEncoder()
encoder.outputFormat = .xml
do {
let data = try encoder.encode(self.storage)
UserDefaults.standard.set(data,forKey: "salva")
} catch {
debugPrint(error.localizedDescription)
}
}
}
func newTodo(name: String,received: Bool = false,closure: ()->()) {
let new = TodoModel(nome: name)
self.objectwillChange.send()
storage.insert(new,at: 0)
save()
closure()
if received { return}
// send to peer if receive is false
if PeerToPeerManager.shared.mcSession.connectedPeers.count > 0 {
PeerToPeerManager.shared.sendTodo(new)
debugPrint("send todo with Peer")
}
}
func cartellaDocuments() -> String {
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory,.userDomainMask,true)
//print(paths[0])
return paths[0]
}
}
在我的 PeerToPeerManager 类中,我处理响应“didReceive data”并将接收到的 todo 放入数组存储中。 存储是一个@Published 数组应该更新视图,但它不起作用..我找不到原因??
class PeerToPeerManager: NSObject,ObservableObject,MCAdvertiserAssistantDelegate {
override init() {
super.init()
startPTPM()
}
static let shared = PeerToPeerManager()
var peerID: MCPeerID!
var mcSession: MCSession!
var serviceAdvertiser : MCNearbyServiceAdvertiser!
@Published var statusconnession = ""
@Published var showReqActionSheet : Bool = false // attiva la finestra richiesta accetta o no
@Published var requestPeer : MCPeerID!
var acceptClosure : ((Bool,MCSession?) -> ())!
@Published var debugSessionState = false
@Published var debugStartHosting = false
func startPTPM() {
peerID = MCPeerID(displayName: UIDevice.current.name)
mcSession = MCSession(peer: peerID,securityIdentity: nil,encryptionPreference: .required)
debugPrint("SESSIONE INIZIATA \(mcSession.myPeerID)")
debugSessionState.toggle()
mcSession.delegate = self
}
func startHosting() {
self.serviceAdvertiser = MCNearbyServiceAdvertiser(peer: peerID,discoveryInfo: nil,serviceType: "swiftu-simptod")
self.serviceAdvertiser.delegate = self
self.serviceAdvertiser.startAdvertisingPeer()
debugStartHosting.toggle()
}
func sendTodo(_ todo:TodoModel) {
if mcSession.connectedPeers.count > 0 {
let encoder = PropertyListEncoder()
encoder.outputFormat = .xml
do {
let data = try encoder.encode(todo)
try mcSession.send(data,toPeers: mcSession.connectedPeers,with: .reliable)
} catch {
debugPrint(error.localizedDescription)
}
}
}
func advertiserAssistantwillPresentInvitation(_ advertiserAssistant: MCAdvertiserAssistant) {
debugPrint("Presenta l'invito?")
}
}
extension PeerToPeerManager: MCSessionDelegate {
func session(_ session: MCSession,peer peerID: MCPeerID,didChange state: MCSessionState) {
switch state {
case MCSessionState.connected:
print("Connesso: \(peerID.displayName)")
dispatchQueue.main.async {
self.statusconnession = "CONnesSO a \(peerID)"
}
case MCSessionState.connecting:
print("Sto connettendo: \(peerID.displayName)")
dispatchQueue.main.async {
self.statusconnession = "CONNECTING"
}
case MCSessionState.notConnected:
print("Non connesso: \(peerID.displayName)")
dispatchQueue.main.async {
self.statusconnession = "NON CONnesSO"
}
@unkNown default: break
}
}
func session(_ session: MCSession,didReceive data: Data,fromPeer peerID: MCPeerID) {
debugPrint("Ricevuta todo")
do {
let decoder = PropertyListDecoder()
let todo = try decoder.decode(TodoModel.self,from: data)
DataManager.shared.newTodo(name: todo.nome) {
debugPrint("Ricevuta todo")
}
} catch {
debugPrint(error.localizedDescription)
}
}
func session(_ session: MCSession,didStartReceivingResourceWithName resourceName: String,fromPeer peerID: MCPeerID,with progress: Progress) {
DataManager.shared.resource = resourceName
DataManager.shared.isRefreshing = true
}
func session(_ session: MCSession,didFinishReceivingResourceWithName resourceName: String,at localURL: URL?,withError error: Error?) {
DataManager.shared.isRefreshing = false
DataManager.shared.resource = ""
}
func session(_ session: MCSession,didReceive stream: InputStream,withName streamName: String,fromPeer peerID: MCPeerID) {
}
}
extension PeerToPeerManager: MCNearbyServiceAdvertiserDelegate {
func advertiser(_ advertiser: MCNearbyServiceAdvertiser,didReceiveInvitationFromPeer peerID: MCPeerID,withContext context: Data?,invitationHandler: @escaping (Bool,MCSession?) -> Void) {
acceptClosure = invitationHandler
requestPeer = peerID
showReqActionSheet = true
}
func accept() {
self.acceptClosure(true,mcSession)
}
func rifiuta() {
self.acceptClosure(false,nil)
}
func advertiser(_ advertiser: MCNearbyServiceAdvertiser,didNotStartAdvertisingPeer error: Error) {
debugPrint("%@","didNotStartAdvertisingPeer: \(error)")
}
}
这里是我的 ContentView
struct ContentView: View {
@Observedobject var dm : DataManager // why not working??
@Observedobject var ptpm : PeerToPeerManager // why not working??
@State var addItem = false
@State var item: String = ""
//peerstuff
@State var isActionSheetShown = false //
@State var isPeerChooserShown = false
var body: some View {
NavigationView{
vstack(alignment:.leading) {
HStack{
Text("Status sessionState")
Text("\(String(ptpm.debugSessionState))")
}.padding()
HStack{
Text("StartHosting")
Text("\(String(ptpm.debugStartHosting))")
}.padding()
HStack{
Text("Connession status")
Text("\(String(ptpm.statusconnession))")
}.padding()
List{ // ------- WHY NOT UPDATING...??
ForEach(dm.storage) { item in
Text(item.nome)
}
}.listStyle(PlainListStyle())
if addItem {
HStack(alignment: .top) {
TextField("add here",text: $item)
.padding(.bottom,30)
.padding().textFieldStyle(RoundedBorderTextFieldStyle())
Button("Add") {
dm.newTodo(name: item) {
}
}.padding()
}
.background(Color.green.frame(height: 100,alignment: .center))
}
}
.edgesIgnoringSafeArea(.bottom)
.navigationBarTitle(Text("Todo"),displayMode: .inline)
.navigationBarItems(leading: buttonPTP,trailing: buttonAdd )
.actionSheet(isPresented: $ptpm.showReqActionSheet,content: {
actionSheetConfirm
})
.sheet(isPresented: self.$isPeerChooserShown) {
MultipeerbrowserView(dismissFlag: self.$isPeerChooserShown)
}
}
}
var buttonAdd: some View {
Button(action: { withAnimation { self.addItem.toggle() } }) {
Image(systemName: !addItem ? "plus.circle.fill" : "minus.circle.fill").imageScale(.large)
}
}
// richiesta
var buttonPTP: some View {
Button(action: { self.isActionSheetShown = true }) {
Image(systemName: "person.crop.circle.fill.badge.plus").imageScale(.large)
}.actionSheet(isPresented: $isActionSheetShown) { actionSheet }
}
var actionSheet: ActionSheet {
ActionSheet(title: Text("Connessione P2P"),message: Text("diventa host o connettiti ad un host"),buttons: [
/// # primo pulsante
.default(Text("diventa Host")) {
self.ptpm.startHosting()
},/// # secondo pulsante
.default(Text("Connettiti")) {
self.isPeerChooserShown = true // fa partire il browser di apple per selezionare utenti
},/// # pulsante Annulla
.cancel { debugPrint("Toccato: Annulla") }
]
)
}
var actionSheetConfirm: ActionSheet {
ActionSheet(title: Text("Richiesta di accesso da \(ptpm.requestPeer.displayName)"),message: Text("per lo scambio di todo tra device"),buttons: [
/// # primo pulsante
.default(Text("Accetta")) {
self.ptpm.accept()
},/// # pulsante Annulla
.cancel(Text("Annulla")) {
self.ptpm.rifiuta()
}
]
)
}
}
import SwiftUI
@main
struct createPeeerApp: App {
var body: some Scene {
WindowGroup {
ContentView(dm: DataManager(),ptpm: PeerToPeerManager())
}
}
}
问题: 我不明白为什么我的 swift 列表没有更新,因为 storage 是 @Published array ,如果我是发件人并将 todo 添加到 array 它会自动更新,但是当我从 didReceive data func 将数据附加到存储时它不会更新清单。
感谢帮助
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)