Swift 3 - Passing Variables and Functions Between View Controllers

风流意气都作罢 提交于 2019-12-13 06:48:24

问题


I am currently making a test app where you can draw and send pictures using multipeer connectivity. There is a connection view controller for the host and a separate one for the other peers. When peers have connected the host will play the game and all the peer's view controllers will go to the drawing VC proving they are connected. However, when I want to send data in the drawing VC, the console says the connected peers the session is 0 even though there are connected peers. I can test that because when the disconnect I get the change state notice in the console. So can someone please show me what is wrong with my code? Thanks.

Ps I am fairly new to iOS development so my code may have some major problems.

Connection Manager File:

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)
}

Browser File

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)
        }
    }
}

The searching controller is the same as the browser except it advertises instead and sends the data when the play button is clicked.

And finally the drawing controller (This is the one with the problem, and I removed all the drawing code)

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.
}

}

Sorry for the weird formatting Xcode copies in a weird way the doesn't keep tabbing. Thanks in advanced, Matt.


回答1:


I was creating a new instance of the class when I called it in the different classes. That is why all my values that had not been initialized were equal to nil. This is the way I fixed it...

let connectionManager = ConnectionManager()

this was creating a instance and not a reference.

to

var connectionManager: ConnectionManager?

this is creating a reference to the class that already exists.

The other thing I had to do was when I segue to another view controller, pass all the values forward.

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

I hope this helps anyone else who is having this issue.



来源:https://stackoverflow.com/questions/42966582/swift-3-passing-variables-and-functions-between-view-controllers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!