MCSessionState меняется с подключения на неподключенное состояние

Всякий раз, когда я пытаюсь подключиться к узлу с помощью Multipeer Connectivity Framework состояние партнера меняется с MCSessionState.Connecting на MCSessionState.NotConnected.

Вот порядок событий, которые я запускаю:

  1. Симулятор рекламирует службу через MCNearbyServiceAdvertiser.
  2. iPhone ищет сервис через MCNearbyServiceBrowser< /а>.
  3. iPhone находит симулятор и немедленно приглашает его к сеансу через invitePeer(_:toSession:withContext:timeout:).
  4. Наконец, симулятор принимает приглашение, используя advertiser(_:didReceiveInvitationFromPeer:withContext:invitationHandler:).

Примечания:

  • Несмотря на то, что я не требую безопасности, я принимаю любые сертификаты, отправленные клиентами в случае, если это ошибка.

Вот код, который я использую:

import UIKit
import MultipeerConnectivity

class ViewController: UIViewController {
    var advertiser: MCNearbyServiceAdvertiser!
    var browser: MCNearbyServiceBrowser!
    var session: MCSession!

    override func viewDidLoad() {
        super.viewDidLoad()
        let localPeerID = MCPeerID(displayName: UIDevice.currentDevice().name)
        session = MCSession(peer: localPeerID, securityIdentity: nil, encryptionPreference: MCEncryptionPreference.None)
        session.delegate = self
    }

    @IBAction func hostTapped(sender: AnyObject) {
        let localPeerID = MCPeerID(displayName: UIDevice.currentDevice().name)
        advertiser = MCNearbyServiceAdvertiser(peer: localPeerID, discoveryInfo: nil, serviceType: "abc")
        advertiser.delegate = self
        print("started advertising")
        advertiser.startAdvertisingPeer()
    }

    @IBAction func connectTapped(sender: AnyObject) {
        let localPeerID = MCPeerID(displayName: UIDevice.currentDevice().name)
        browser = MCNearbyServiceBrowser(peer: localPeerID, serviceType: "abc")
        browser.delegate = self
        print("started searching")
        browser.startBrowsingForPeers()
    }
}

extension ViewController: MCNearbyServiceAdvertiserDelegate {
    func advertiser(advertiser: MCNearbyServiceAdvertiser, didReceiveInvitationFromPeer peerID: MCPeerID, withContext context: NSData?, invitationHandler: (Bool, MCSession) -> Void) {
        print("accepting invitation from \(peerID.displayName)")
        invitationHandler(true, session)
    }

    func advertiser(advertiser: MCNearbyServiceAdvertiser, didNotStartAdvertisingPeer error: NSError) {
        print("did not start advertising \(error)")
    }
}

extension ViewController: MCSessionDelegate {
    func session(session: MCSession, peer peerID: MCPeerID, didChangeState state: MCSessionState) {
        print("\(peerID.displayName) changed state: \(state.toString())")
    }

    func session(session: MCSession, didReceiveData data: NSData, fromPeer peerID: MCPeerID) {

    }

    func session(session: MCSession, didReceiveStream stream: NSInputStream, withName streamName: String, fromPeer peerID: MCPeerID) {

    }

    func session(session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, withProgress progress: NSProgress) {

    }

    func session(session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, atURL localURL: NSURL, withError error: NSError?) {

    }

    func session(session: MCSession, didReceiveCertificate certificate: [AnyObject]?, fromPeer peerID: MCPeerID, certificateHandler: (Bool) -> Void) {
        certificateHandler(true)
    }
}

extension ViewController: MCNearbyServiceBrowserDelegate {
    func browser(browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {
        print("found \(peerID.displayName), inviting to session")
        browser.invitePeer(peerID, toSession: session, withContext: nil, timeout: 30)
    }

    func browser(browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
        print("lost \(peerID.displayName)")
    }
}

extension MCSessionState {
    func toString() -> String {
        switch self {
        case .Connected:    return "Connected"
        case .Connecting:   return "Connecting"
        case .NotConnected: return "Not Connected"
        }
    }
}

Здесь есть аналогичный вопрос, однако связанный код устарел и больше недоступен. Кроме того, проблема заключалась в том, что использовался один и тот же объект сеанса.


person Senseful    schedule 30.11.2015    source источник


Ответы (2)


Всегда можно просто создать его как константу для класса!

class ViewController: UIViewController {
    var advertiser: MCNearbyServiceAdvertiser!
    var browser: MCNearbyServiceBrowser!
    var session: MCSession!

    let localPeerID = MCPeerID(displayName: UIDevice.currentDevice().name)
    ...
}
person Reid    schedule 10.03.2016

Я использовал разные экземпляры MCPeerID. для MCSession, MCNearbyServiceAdvertiser и MCNearbyServiceBrowser.

Чтобы исправить это, я создал переменную экземпляра MCPeerID:

var localPeerID: MCPeerID?

override func viewDidLoad() {
    // ...
    localPeerID = MCPeerID(displayName: UIDevice.currentDevice().name)
    // ...
}

... и использовал его вместо того, чтобы создавать их как локальные переменные (let localPeerID = ...).

Теперь он правильно переходит из состояния connecting в состояние connected.

person Senseful    schedule 30.11.2015
comment
У меня была такая же проблема. Спасибо, что поделился. - person Cesar Barscevicius; 05.05.2016
comment
Лично я не сторонник принудительной развертки в производственном коде, если только с этим действительно ничего не поделаешь. Это можно было бы сделать значительно безопаснее, установив его как константу и инициализировав в точке объявления или отложенной загрузки :) - person Kane Cheshire; 28.12.2016