Swift 3 - 在视图控制器之间传递变量和函数

Swift 3 - Passing Variables and Functions Between View Controllers

我正在制作一个测试应用程序,您可以在其中使用多点连接绘制和发送图片。

主机有一个连接视图控制器,其他对等点有一个单独的连接视图控制器。当对等点连接后,主机将玩游戏,所有对等点的视图控制器将转到绘图 VC 证明它们已连接。

但是,当我想在绘图中发送数据时 VC,控制台显示已连接的对等点会话为 0,即使有已连接的对等点。我可以测试它,因为当断开连接时,我会在控制台中收到更改状态通知。我的代码有什么问题?

连接管理器文件:

import UIKit
import MultipeerConnectivity

class ConnectionManager: NSObject {

var localPeerId = MCPeerID(displayName: UIDevice.current.name)
var service = "PI-Connect"
var session: MCSession
var browser: MCNearbyServiceBrowser
var advertiser: MCAdvertiserAssistant
var connectionDelegate: ConnectionManagerDelegate?
var serviceDelegate: ServiceManagerDelegate?
var gameStarted : Bool

override init() {

    self.session = MCSession(peer: self.localPeerId)
    self.browser = MCNearbyServiceBrowser(peer: self.localPeerId, serviceType: service)
    self.advertiser = MCAdvertiserAssistant(serviceType: service, discoveryInfo: nil, session: session)
    gameStarted = false
    
    super.init()
    
    self.session.delegate = self
    self.browser.delegate = self
    self.advertiser.delegate = self
    
}

func startBrowsing() {
    browser.startBrowsingForPeers()
}
func stopBrowsing() {
    browser.stopBrowsingForPeers()
}
func startAdvertising() {
    advertiser.start()
}
func stopAdvertising() {
    advertiser.stop()
}

func startGame(gameStarted: String) {
    NSLog("%@", "Start game: \(gameStarted) to \(session.connectedPeers.count) peers")
    if session.connectedPeers.count > 0 {
        do {
            try session.send(gameStarted.data(using: .utf8)!, toPeers: session.connectedPeers, with: .reliable)
        }
        catch let error {
            NSLog("%@", "Error for sending: \(error)")
        }
    }
}

func sendImage(imageData: Data) {
    displayConnectedPeers()
    NSLog("%@", "Attempting to send image to \(session.connectedPeers.count) peers")
    if session.connectedPeers.count > 0 {
        do {
            try session.send(imageData, toPeers: session.connectedPeers, with: .reliable)
            NSLog("%@", "Image sent")
        }
        catch let error {
            NSLog("%@", "Error for sending image: \(error)")
        }
    }
}

func displayConnectedPeers() {
    NSLog("%@", "Connected peers: \(session.connectedPeers.count)")
}
}

extension ConnectionManager: MCNearbyServiceBrowserDelegate {
func browser(_ browser: MCNearbyServiceBrowser, didNotStartBrowsingForPeers error: Error) {
    NSLog("%@", "didNotStartBrowsingForPeers: \(error)")
}

func browser(_ browser: MCNearbyServiceBrowser, foundPeer peerID: MCPeerID, withDiscoveryInfo info: [String : String]?) {
    NSLog("%@", "foundPeer: \(peerID)")
    NSLog("%@", "invitePeer: \(peerID)")
    browser.invitePeer(peerID, to: session, withContext: nil, timeout: 10)
    }

func browser(_ browser: MCNearbyServiceBrowser, lostPeer peerID: MCPeerID) {
    NSLog("%@", "lostPeer: \(peerID)")
    self.connectionDelegate?.foundHost(manager: self)
}
}

extension ConnectionManager: MCAdvertiserAssistantDelegate {
func advertiserAssistantDidDismissInvitation(_ advertiserAssistant: MCAdvertiserAssistant) {
    NSLog("%@", "Peer dismissed connection")
}

func advertiserAssistantWillPresentInvitation(_ advertiserAssistant: MCAdvertiserAssistant) {
    NSLog("%@", "Peer accepted connection")
}
}

extension ConnectionManager: MCSessionDelegate {
func session(_ session: MCSession, peer peerID: MCPeerID, didChange state: MCSessionState) {
    NSLog("%@", "peer \(peerID) didChangeState: \(state)")
    self.connectionDelegate?.foundHost(manager: self)
}

func session(_ session: MCSession, didReceive data: Data, fromPeer peerID: MCPeerID) {
    
    NSLog("%@", "didReceiveData: \(data)")
    
    if gameStarted == false {
        stopBrowsing()
        self.connectionDelegate?.hostInitsGame(manager: self)
        NSLog("%@", "Game Started")
        gameStarted = true
    }
    
    if gameStarted == true {
        self.serviceDelegate?.changeImage(manager: self, imageData: data)
    }
}

func session(_ session: MCSession, didReceive stream: InputStream, withName streamName: String, fromPeer peerID: MCPeerID) {
    NSLog("%@", "didReceiveStream")
}

func session(_ session: MCSession, didStartReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, with progress: Progress) {
    NSLog("%@", "didStartReceivingResourceWithName")
}

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

extension browsingForPeers : ConnectionManagerDelegate {

func foundHost(manager: ConnectionManager) {
    OperationQueue.main.addOperation {
        if self.connectionManager.session.connectedPeers.count > 0 {
            self.header.text = "\(self.connectionManager.session.connectedPeers[0].displayName)'s game"
            self.activityMonitor.alpha = 0
        }
        if self.connectionManager.session.connectedPeers.count == 0 {
            self.header.text = "Searching for game"
            self.activityMonitor.alpha = 1
        }
    }
}

func hostInitsGame(manager: ConnectionManager) {
    OperationQueue.main.addOperation {
        self.switchViewControllers(active: true)
    }
}
}

extension ViewController : ServiceManagerDelegate {
func changeImage(manager: ConnectionManager, imageData: Data) {
    self.imageView.image = nil
    self.imageView.image = UIImage(data: imageData)
}

}

protocol ConnectionManagerDelegate {
func hostInitsGame(manager: ConnectionManager)
func foundHost(manager: ConnectionManager)
}

protocol ServiceManagerDelegate {
func changeImage(manager: ConnectionManager, imageData: Data)
}

浏览器文件

import UIKit

class browsingForPeers: UIViewController {

    let connectionManager = ConnectionManager()
    @IBOutlet weak var header: UITextField!
    @IBOutlet weak var activityMonitor: UIActivityIndicatorView!

    override func viewDidLoad() {
        super.viewDidLoad()
        connectionManager.connectionDelegate = self
        connectionManager.startBrowsing()
//        Constants().host = false
    }

    func switchViewControllers(active: Bool) {
        if active == true {
            performSegue(withIdentifier: "browsingToDrawing", sender: self)
        }
    }
}

搜索控制器与浏览器相同,只是它会广告并在单击播放按钮时发送数据。

最后是绘图控制器(这是有问题的那个,我删除了所有绘图代码)

import UIKit
import MultipeerConnectivity

class ViewController: UIViewController {
    var globalConstant: Constants?
    
    let connectionManager = ConnectionManager()

    @IBOutlet var imageView: UIImageView!
    @IBOutlet weak var more: UIButton!
    @IBOutlet weak var brushOptions: UIButton!
    @IBOutlet weak var colorOptions: UIButton!
    @IBOutlet weak var eraser: UIButton!
    
    @IBOutlet weak var brushSml: UIButton!
    @IBOutlet weak var brushMed: UIButton!
    @IBOutlet weak var brushLrg: UIButton!
    
    @IBOutlet weak var redButton: UIButton!
    @IBOutlet weak var orangeButton: UIButton!
    @IBOutlet weak var yellowButton: UIButton!
    @IBOutlet weak var greenButton: UIButton!
    @IBOutlet weak var lightBlueButton: UIButton!
    @IBOutlet weak var blueButton: UIButton!
    @IBOutlet weak var pinkButton: UIButton!
    @IBOutlet weak var greyButton: UIButton!
    @IBOutlet weak var blackButton: UIButton!
    
    @IBOutlet weak var slider: UISlider!
    
    var uiimage: UIImage!
    var ciimage: CIImage!
    var data: Data!
    
    
    override var prefersStatusBarHidden: Bool {
        return true
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        connectionManager.serviceDelegate = connectionManager.connectionDelegate as! ServiceManagerDelegate?
        NSLog("%@", "View loaded with \    (connectionManager.session.connectedPeers.count) peers") //Outputs 0
    //        connectionManager.session.disconnect()
    //        NSLog("%@", "Disconnected")

    @IBAction func doneButtonClicked(_ sender: UIButton) {
        imageView.isUserInteractionEnabled = false 
        uiimage = imageView.image
        if uiimage != nil {
            data = UIImagePNGRepresentation(uiimage)
            connectionManager.sendImage(imageData: data)
            imageView.image = nil
            imageView.image = UIImage(data: data)
        }
    }
    
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }
}

当我在不同的 class 中调用它时,我正在创建 class 的新实例。这就是为什么我所有未初始化的值都等于 nil 的原因。这是我修复它的方式...

let connectionManager = ConnectionManager()

这是在创建实例而不是引用。

var connectionManager: ConnectionManager?

这是在创建对已存在的 class 的引用。

我必须做的另一件事是当我转到另一个视图控制器时,向前传递所有值。

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let destinationViewController = segue.destination as? ViewController {
        destinationViewController.connectionManager = self.connectionManager
    }
}

我希望这对遇到此问题的其他人有所帮助。