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

Posted

技术标签:

【中文标题】Swift 3 - 在视图控制器之间传递变量和函数【英文标题】:Swift 3 - Passing Variables and Functions Between View Controllers 【发布时间】:2017-03-23 03:12:03 【问题描述】:

我目前正在制作一个测试应用程序,您可以在其中使用多点连接绘制和发送图片。主机有一个连接视图控制器,其他节点有一个单独的视图控制器。当对等点连接后,主机将开始玩游戏,所有对等点的视图控制器将转到绘图 VC,以证明它们已连接。但是,当我想在绘图 VC 中发送数据时,控制台说连接的对等方会话为 0,即使有连接的对等方。我可以测试它,因为当断开连接时,我会在控制台中收到更改状态通知。那么有人可以告诉我我的代码有什么问题吗?谢谢。

Ps 我对 ios 开发相当陌生,所以我的代码可能存在一些重大问题。

连接管理器文件:

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.



抱歉,Xcode 以一种奇怪的方式复制了奇怪的格式,并没有继续使用标签。提前感谢,马特。

【问题讨论】:

您的连接管理器类不是单例。 browseForPeers viewcontroller 和 ViewController viewcontroller 有不同的连接管理器对象,你只能在 browseForPeers 上开始浏览。 好的,因为他们确实连接并共享数据。当我切换视图控制器时,它就搞砸了。我认为我没有正确传递变量。有什么想法吗? 有人有什么想法吗?我相信这可能与@koropok 所说的将值向后或向前传递有关。谢谢 绘图控制器中的 ConnectionManager 对象没有调用 startBrowsing 函数。 【参考方案1】:

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

let connectionManager = ConnectionManager()

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

var connectionManager: ConnectionManager?

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

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

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

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

【讨论】:

以上是关于Swift 3 - 在视图控制器之间传递变量和函数的主要内容,如果未能解决你的问题,请参考以下文章

Swift 3 - 在视图控制器之间传递数据,然后再传递给另一个 2

快速在视图之间传递和调用变量和函数

在 Swift 中的视图控制器之间传递自定义类数据

使用 segue 在 View Controller 之间传递变量

Swift 3:如何动态加载图像并将变量传递给第二个视图控制器?

swift 4 中使用 performSegue 打开的关闭页面时,如何在视图控制器和 TableViewController 之间传递数据?