簡體   English   中英

Swift MultipeerConnectivity無條件崩潰DateComponentsBridgeFromObjectiveC

[英]Swift MultipeerConnectivity crash DateComponents unconditionallyBridgeFromObjectiveC

我有一個可重復的崩潰,以EXC_BREAKPOINT結尾,如下圖所示:

MultipeerConnectivity崩潰

重現崩潰的步驟:

  1. 連接兩個設備
  2. 使用func sendResource開始傳輸(在resourceURL:URL,withName resourceName:String,toPeer peerID:MCPeerID,withCompletionHandler completionHandler:((Error?) - > Void)?= nil) - > Progress?
  3. 通過調用func disconnect()斷開啟動傳輸的設備

編輯:通過調用Progress.cancel()來重現崩潰的另一種方法步驟:

  1. 連接兩個設備
  2. 開始傳輸並存儲Progress對象let progress:Progress = session.sendResource(...)
  3. 對進度對象調用取消,導致其他設備崩潰progress.cancel()

我在線上的代碼didFinishReceivingResourceWithName:

func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL, withError error: Error?) {
    // transfer to local URL
    MusicDownloadRequestor.sharedInstance.finishReceivingSongUploadAtLocalURL(tempUrl: localURL)
}

看起來我的代碼在堆棧跟蹤中看起來不像...

* thread #25: tid = 0x806ec, 0x0000000100944af4 libswiftFoundation.dylib`static Foundation.DateComponents._unconditionallyBridgeFromObjectiveC (Swift.Optional<__ObjC.NSDateComponents>) -> Foundation.DateComponents with unmangled suffix "_merged" + 96, queue = 'com.apple.MCSession.callbackQueue', stop reason = EXC_BREAKPOINT (code=1, subcode=0x100944af4)
frame #0: 0x0000000100944af4 libswiftFoundation.dylib`static Foundation.DateComponents._unconditionallyBridgeFromObjectiveC (Swift.Optional<__ObjC.NSDateComponents>) -> Foundation.DateComponents with unmangled suffix "_merged" + 96
frame #1: 0x0000000100114c60 MyAppSwift`@objc NetworkManager.session(MCSession, didFinishReceivingResourceWithName : String, fromPeer : MCPeerID, at : URL, withError : Error?) -> () + 168 at NetworkManager.swift:0
frame #2: 0x00000001a1dda028 MultipeerConnectivity`__79-[MCSession syncCloseIncomingStream:forPeer:state:error:reason:removeObserver:]_block_invoke + 208
frame #3: 0x0000000100c05258 libdispatch.dylib`_dispatch_call_block_and_release + 24
frame #4: 0x0000000100c05218 libdispatch.dylib`_dispatch_client_callout + 16
frame #5: 0x0000000100c12aec libdispatch.dylib`_dispatch_queue_serial_drain + 1136
frame #6: 0x0000000100c08ce0 libdispatch.dylib`_dispatch_queue_invoke + 672
frame #7: 0x0000000100c14e2c libdispatch.dylib`_dispatch_root_queue_drain + 584
frame #8: 0x0000000100c14b78 libdispatch.dylib`_dispatch_worker_thread3 + 140
frame #9: 0x000000018c2a32a0 libsystem_pthread.dylib`_pthread_wqthread + 1288
frame #10: 0x000000018c2a2d8c libsystem_pthread.dylib`start_wqthread + 4

更新#1:將堆棧跟蹤添加為文本

更新#2:在崩潰中找到了可能的領先優勢, 這是另一個無條件的BrianFromObjectiveC崩潰

我認為問題是URL被傳遞給didFinishReceivingResourceWithName為nil,但參數是非可選的。 這是有道理的,因為如果文件無法傳輸,則URL不會是最終的休息位置。 有什么方法可以解決這個問題或攔截錯誤嗎?

我認為這是一個Apple bug。 有沒有人建議做一個解決方案?

使用混合和匹配功能,我能夠將我的MCSessionDelegate轉換為Objective-C,然后將參數傳遞給Swift。 檢查傳入的值后,我確認URL類型的變量“localURL”實際上是nil,這意味着它應該被聲明為可選。 我向Apple提交了一份錯誤報告。

要解決此問題,請在Objective-C中編寫MCSessionDelegate。 有幾個步驟讓Objective-C和Swift在同一個項目中一起工作, 這個頁面很好地解釋了它

這是我的代碼。

我的MCSessionDelegate標頭:

#import <Foundation/Foundation.h>
#import <MultipeerConnectivity/MultipeerConnectivity.h>
@class NetworkMCSessionTranslator;

@interface NetworkMCSessionDelegate : NSObject <MCSessionDelegate>
-(instancetype)initWithTranslator:(NetworkMCSessionTranslator*) trans;
@end

我的MCSessionDelegate實現文件:

#import "NetworkMCSessionDelegate.h"
#import "MusicAppSwift-Swift.h"

@interface NetworkMCSessionDelegate()
@property (nonatomic) NetworkMCSessionTranslator *translator;
@end

@implementation NetworkMCSessionDelegate

/*
 create a NetworkMCSessionDelegate and pass in a swift translator
 */
-(instancetype)initWithTranslator:(NetworkMCSessionTranslator*) trans{
    if(self = [super init]){
        self.translator = trans;
    }
    return self;
}

/*
 Indicates that an NSData object has been received from a nearby peer.
 */
- (void)session:(MCSession *)session didReceiveData:(NSData *)data fromPeer:(MCPeerID *)peerID{
    [self.translator networkSession:session didReceive:data fromPeer:peerID];
}

/*
 Indicates that the local peer began receiving a resource from a nearby peer.
 */
- (void)session:(MCSession *)session didStartReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID withProgress:(NSProgress *)progres{
    [self.translator networkSession:session didStartReceivingResourceWithName:resourceName fromPeer:peerID with:progres];
}

/*
 Indicates that the local peer finished receiving a resource from a nearby peer.
 */
- (void)session:(MCSession *)session didFinishReceivingResourceWithName:(NSString *)resourceName fromPeer:(MCPeerID *)peerID atURL:(NSURL *)localURL withError:(NSError *)error{
    [self.translator networkSession:session didFinishReceivingResourceWithName:resourceName fromPeer:peerID at:localURL withError:error];
}

/*
 Called when the state of a nearby peer changes.
 */
- (void)session:(MCSession *)session peer:(MCPeerID *)peerID didChangeState:(MCSessionState)state{
    [self.translator networkSession:session peer:peerID didChange:state];
}

/*
 Called when a nearby peer opens a byte stream connection to the local peer.
 */
- (void)session:(MCSession *)session didReceiveStream:(NSInputStream *)stream withName:(NSString *)streamName fromPeer:(MCPeerID *)peerID{
    // not expecting to see any of this
}

@end

我的Swift文件收集來自委托的流量:

import Foundation
import MultipeerConnectivity

@objc class NetworkMCSessionTranslator: NSObject{
    public func networkSession(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState){
        ...
    }

    public func networkSession(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID){
        ...
    }

    public func networkSession(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, withError error: Error?){
        // !!! Notice localURL is now an OPTIONAL !!!
    }

    public func networkSession(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress){
        ...
    }

}

祝好運!

只是讓人們知道xcode 9 beta 1的發布已經修復了這個bug。根據文檔和我的測試,at localurl參數現在是預期的可選項: https//developer.apple.com/documentation/multipeerconnectivity/ mcsessiondelegate / 1406984-會議

只需更新到xcode9的最新版本即可解決此問題。

在iOS 7和xcode 8及更高版本中,使用localURL作為可選項更改您的功能

使用此功能

func session(_ session: MCSession, didFinishReceivingResourceWithName         
resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL?, 
withError error: Error?) {

    if (localURL != nil) {
       //enter code here
   }
}

代替

func session(_ session: MCSession, didFinishReceivingResourceWithName         
resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL, 
withError error: Error?) {

}

所以,這個功能解決了我的崩潰問題。 如果在xcode 8中顯示任何警告,請忽略它。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM