Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/swift/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Swift 可重用的视图控制器,在情节提要中具有视图(一个场景中有多个)_Swift_Xcode_Uiviewcontroller_Storyboard_Uicontainerview - Fatal编程技术网

Swift 可重用的视图控制器,在情节提要中具有视图(一个场景中有多个)

Swift 可重用的视图控制器,在情节提要中具有视图(一个场景中有多个),swift,xcode,uiviewcontroller,storyboard,uicontainerview,Swift,Xcode,Uiviewcontroller,Storyboard,Uicontainerview,我正在为我的女儿和朋友们为两名玩家开发一个小型数学游戏应用程序(但我计划以后也允许单人游戏)。目前,它只适合两名玩家,两人都坐在iPhone的对面。 每个玩家都有相同的按钮,回答相同的问题。他们按下一个按钮(一个自建numpad),vc获得触摸事件,它验证答案,并根据结果生成scoreView动画并更新scoreCounters 一方的游戏逻辑已经完成了。现在我想在一个视图中重用该逻辑,并使用它两次(相同的numpad和textfields,但在相反的一侧) 但是,我找不到一个可以在vc工作的情

我正在为我的女儿和朋友们为两名玩家开发一个小型数学游戏应用程序(但我计划以后也允许单人游戏)。目前,它只适合两名玩家,两人都坐在iPhone的对面。 每个玩家都有相同的按钮,回答相同的问题。他们按下一个按钮(一个自建numpad),vc获得触摸事件,它验证答案,并根据结果生成scoreView动画并更新scoreCounters

一方的游戏逻辑已经完成了。现在我想在一个视图中重用该逻辑,并使用它两次(相同的numpad和textfields,但在相反的一侧) 但是,我找不到一个可以在vc工作的情况下拥有这样一个可重用视图的方法。我想我可以在xib中构建视图,将所有内容连接到它的视图控制器,然后以我想要的方式在我的故事板中重用视图/vc耦合。但它失败了

目前我有以下设置(注意:我现在使用的是基本视图和vcs,就像现在一样,它是用于测试的,如果一切正常,我将用真实的、稍微复杂一点的逻辑/视图替换视图和vc):

“测试”设置中的相关文件:

  • MessageView.xib
  • MessageView.swift
  • MessageViewController.swift
  • 斯威夫特
  • 主故事板
MessageView.xib在MessageView类中只有一个作为插座连接的标签,但我希望在视图控制器中有标签和按钮的插座。 MessageViewController有一个指向messageView的出口(我更喜欢出口而不是视图和动作,并且视图是direct view Controller视图,并且让vc处理所有动作和逻辑)

在我的故事板中,我有我的RootViewController(将是gameFieldViewController)。 RootViewController有一个带有两个容器的stackView。 每个容器VC的类型为MessageViewController(将是calcViewController)。 该容器VC的视图具有MessageViewWrapper类型的子视图(将是calcView)

我现在的问题是,在messageView xib中,我希望将所有操作(在该示例中只有一个标签,但它将是带按钮的计算器垫)连接到MessageViewController。这样vc就可以处理所有的逻辑。但我只能将MessageView连接到MessageViewController,因此我需要捕获视图中的所有操作,然后将所有操作委托给MessageViewController,我想,如果没有其他方法,我会这样做,但我仍然希望我只知道很少的swift+xcode

我希望有一个MessageViewController.xib,它可以像在main.storyboard中正常构建一样执行所有操作,然后我希望能够随时重用该控制器,就像在带有多个容器的stackView中一样,每个容器都有自己的vc实例,但在我看来似乎只能重用视图,不是视图控制器+视图对

问题: 有可能吗?怎样如何设置? 我尝试将MessageView.xib的文件所有者设置为MessageViewController,将Main.storyboard中容器视图的类设置为MessageViewController,然后将标签直接连接到ViewController,并从VC中修改文本,但失败了,我想这并不奇怪,但这是我唯一能想到的

下面是一些代码:

// MessageView.swift
import UIKit

@IBDesignable class MessageViewWrapper : NibWrapperView<MessageView> { }
// wrapper thingy found here 
//https://medium.com/flawless-app-stories/how-to-reuse-complex-xib-designed-views-in-storyboards-using-modern-swift-generics-property-e0b7c06b07a6
class MessageView: UIView {
    
    @IBOutlet weak var messageLabel: UILabel!
    
    var message : String = "" {
        didSet { messageLabel.text = message }
    }
}

// MessageViewController.swift
import UIKit

class MessageViewController: UIViewController {
    @IBOutlet weak var messageView: UIView!
    @IBOutlet weak var messageLabel: UILabel!
    
    override func viewDidLoad() {
        (messageView as? MessageViewWrapper)?.contentView.message = "Yeepee !!!"
    }
    
    func inHere() {
        messageLabel.text = "AHA"
    }
}

// RootViewController
import SwiftUI
class RootViewController: UIViewController {
    var vcTop: MessageViewController!

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if (segue.identifier == "topViewSegue") {
            let vc = segue.destination
            guard let vcTop = vc as? MessageViewController else {return}
            
            vcTop.inHere() // fails
        }
    }
}

// NibWrapperView.swift
import UIKit

/// Class used to wrap a view automatically loaded form a nib file
class NibWrapperView<T: UIView>: UIView {
    /// The view loaded from the nib
    var contentView: T

    required init?(coder: NSCoder) {
        contentView = T.loadFromNib()
        super.init(coder: coder)
        prepareContentView()
    }
    
    override init(frame: CGRect) {
        contentView = T.loadFromNib()
        super.init(frame: frame)
        prepareContentView()
    }
    
    private func prepareContentView() {
        contentView.translatesAutoresizingMaskIntoConstraints = false
        addSubview(contentView)

        contentView.leadingAnchor.constraint(equalTo: leadingAnchor).isActive = true
        contentView.topAnchor.constraint(equalTo: topAnchor).isActive = true
        contentView.trailingAnchor.constraint(equalTo: trailingAnchor).isActive = true
        contentView.bottomAnchor.constraint(equalTo: bottomAnchor).isActive = true
    }
    
    override func prepareForInterfaceBuilder() {
        super.prepareForInterfaceBuilder()
        contentView.prepareForInterfaceBuilder()
    }
}

extension UIView{
    static func loadFromNib() -> Self {
        let bundle = Bundle(for: self)
        let nib = UINib(nibName: String(describing: self), bundle: bundle)
        return nib.instantiate(withOwner: nil, options: nil).first as! Self
    }
}
//MessageView.swift
导入UIKit
@IBDesignable类MessageViewWrapper:NibWrapperView{}
//在这里找到的包装物
//https://medium.com/flawless-app-stories/how-to-reuse-complex-xib-designed-views-in-storyboards-using-modern-swift-generics-property-e0b7c06b07a6
类MessageView:UIView{
@IBVAR弱消息标签:UILabel!
var消息:String=“”{
didSet{messageLabel.text=message}
}
}
//MessageViewController.swift
导入UIKit
类MessageViewController:UIViewController{
@ibvar弱消息视图:UIView!
@IBVAR弱消息标签:UILabel!
重写func viewDidLoad(){
(messageView作为?MessageViewWrapper)?.contentView.message=“Yeepee!!!”
}
func inHere(){
messageLabel.text=“AHA”
}
}
//根视图控制器
导入快捷键
类RootViewController:UIViewController{
var vcTop:MessageViewController!
覆盖功能准备(对于segue:UIStoryboardSegue,发送方:有吗?){
如果(segue.identifier==“topViewSegue”){
设vc=segue.destination
guard let vtop=vc as?MessageViewController else{return}
vtop.inHere()//失败
}
}
}
//NibWrapperView.swift
导入UIKit
///类,用于将自动加载的视图包装为nib文件
类NibWrapperView:UIView{
///从nib加载的视图
var contentView:T
必需初始化?(编码器:NSCoder){
contentView=T.loadFromNib()
super.init(编码器:编码器)
prepareContentView()
}
重写初始化(帧:CGRect){
contentView=T.loadFromNib()
super.init(frame:frame)
prepareContentView()
}
私有函数prepareContentView(){
contentView.translatesAutoResizezingMaskintoConstraints=false
addSubview(contentView)
contentView.leadingAnchor.constraint(equalTo:leadingAnchor.isActive=true)
contentView.topAnchor.constraint(equalTo:topAnchor).isActive=true
contentView.trailingAnchor.constraint(equalTo:trailingAnchor).isActive=true
contentView.bottomAnchor.constraint(equalTo:bottomAnchor).isActive=true
}
重写func prepareForInterfaceBuilder(){
super.prepareforPrinterFaceBuilder()
contentView.prepareForInterfaceBuilder()文件
}
}
扩展UIView{
静态函数loadFromNib()->Self{
let bundle=bundle(用于:self)
让nib=UINib(nibName:String(description:self),bundle:bundle)
返回nib.instantiate(拥有者:nil,opti