Swift - 通过导航控制器委托
Posted
技术标签:
【中文标题】Swift - 通过导航控制器委托【英文标题】:Swift - Delegate through Nav Controller 【发布时间】:2017-05-01 03:09:57 【问题描述】:我将在其中包含我的完整代码,但我会尝试指出相关位的位置。基本上,我从 Unwind Segue 返回到带有一些新数据的视图控制器。我在“NBARotoHome”VC 中成功使用了该数据,但我还需要通过嵌入式导航控制器将其中一些数据传递给“NBARotoTabPager”vc。
我正在尝试使用“UpdateChildView”委托(在第一个代码块的顶部)并在“loadViewData()”中调用它的方法(在靠近第一个块底部的“if 语句”中)来执行此操作.
protocol UpdateChildView : class
func updateView()
func test()
var playerSelected: Player? get set
class RotoViewRoundCell: UITableViewCell
@IBOutlet weak var categoryLabel: UILabel!
class RotoViewRoundHeader: UITableViewCell
class NBARotoHome: UIViewController
@IBOutlet weak var posPaidLabel: UILabel!
@IBOutlet weak var progressIndicator: UIProgressView!
@IBOutlet weak var vsLabel: UILabel!
@IBOutlet weak var fantasyFundsAmountLabel: UILabel!
@IBOutlet weak var fantasyFundsLabel: UILabel!
@IBOutlet weak var playerName: UILabel!
@IBOutlet weak var roundIndicator: UILabel!
var selectedPlayer: Player!
var firstNavController: UINavigationController!
weak var updateChildView : UpdateChildView?
override func viewDidLoad()
super.viewDidLoad()
loadViewData()
firstNavController = self.navigationController
let rightBarButton = UIBarButtonItem(title: "Select", style: UIBarButtonItemStyle.plain, target: self, action: #selector(myRightSideBarButtonItemTapped(_:)))
self.navigationItem.rightBarButtonItem = rightBarButton
self.title = "NBA Roto"
func myRightSideBarButtonItemTapped(_ sender:UIBarButtonItem!)
performSegue(withIdentifier: "ShowDraft", sender: nil)
override func prepare(for segue: UIStoryboardSegue, sender: Any?)
if segue.identifier == "ShowDraft"
let navVC = segue.destination as? UINavigationController
let nbaDraftList = navVC?.viewControllers.first as! NBADraftList
nbaDraftList.mainNavController = firstNavController
if (segue.identifier == "buyNavControllerChild")
// let navVC = segue.destination as? UINavigationController
// let buyVC = navVC?.viewControllers.first as! NBARotoTabPager
// buyVC.delegate = self
override func viewWillAppear(_ animated: Bool)
super.viewWillAppear(animated)
@IBAction func prepareForUnwind(segue: UIStoryboardSegue)
func loadViewData()
if((selectedPlayer) != nil)
roundIndicator.text = "Upcoming: " + selectedPlayer.game_time
playerName.text = selectedPlayer.Name
vsLabel.text = selectedPlayer.visiting + " @ " + selectedPlayer.home
fantasyFundsLabel.text = ""
fantasyFundsAmountLabel.text = ""
updateChildView?.test()
// updateChildView?.playerSelected = selectedPlayer
// updateChildView?.updateView()
else
roundIndicator.text = "Select a Player"
playerName.text = "No Player Selected"
vsLabel.text = "--"
fantasyFundsLabel.text = "Fantasy Funds"
fantasyFundsAmountLabel.text = "$10,000"
因为我无法让代理工作,所以我一直在尝试在上面的“准备”方法中设置其代理属性 -'buyVC.delegate = self' - 但我得到的是 'buyVC没有成员代表”,所以这是一条死胡同。
下一段代码是嵌入在导航控制器中的 NBARotoTabPager vc。由于我不再确定的原因,我决定将其设为 NBARotoHome 的子类,但它基本上是一个自定义选项卡寻呼机,它使用分段控件在两个额外的 vcs 之间切换。
此时最重要的一步是让“test”函数工作(它只是打印“test”。它在下面的代码块中实现,从底部倒数第二个 updateView)。
class NBARotoTabPager: NBARotoHome, UpdateChildView
@IBOutlet weak var segmentedControl: UISegmentedControl!
@IBOutlet weak var scoreKey: UIBarButtonItem!
@IBOutlet weak var standings: UIBarButtonItem!
var playerSelected: Player?
override func viewDidLoad()
navigationController?.navigationBar.barTintColor = UIColor(red: 27/255, green: 27/255, blue: 27/255, alpha: 1)
scoreKey.setTitleTextAttributes([NSFontAttributeName: UIFont(name: "Helvetica", size: 13.0)!], for: UIControlState.normal)
scoreKey.tintColor = UIColor.blue
standings.setTitleTextAttributes([NSFontAttributeName: UIFont(name: "Helvetica", size: 13.0)!], for: UIControlState.normal)
standings.tintColor = UIColor.blue
setupView()
private func setupView()
setupSegmentedControl()
updateView()
private func setupSegmentedControl()
// Configure Segmented Control
segmentedControl.removeAllSegments()
segmentedControl.insertSegment(withTitle: "Live", at: 0, animated: false)
segmentedControl.insertSegment(withTitle: "Avg / +", at: 1, animated: false)
segmentedControl.addTarget(self, action: #selector(selectionDidChange(_:)), for: .valueChanged)
segmentedControl.selectedSegmentIndex = 0
func selectionDidChange(_ sender: UISegmentedControl)
updateView()
private lazy var viewLiveTab: NBARotoLive =
// Load Storyboard
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
// Instantiate View Controller
var viewController = storyboard.instantiateViewController(withIdentifier: "NBARotoLive") as! NBARotoLive
if((self.playerSelected) != nil)
viewController.selectedPlayer = self.playerSelected
// Add View Controller as Child View Controller
self.add(asChildViewController: viewController)
return viewController
()
private lazy var viewAvgsTab: NBARotoAvgs =
// Load Storyboard
let storyboard = UIStoryboard(name: "Main", bundle: Bundle.main)
// Instantiate View Controller
var viewController = storyboard.instantiateViewController(withIdentifier: "NBARotoAvgs") as! NBARotoAvgs
if((self.playerSelected) != nil)
viewController.selectedPlayer = self.playerSelected
// Add View Controller as Child View Controller
self.add(asChildViewController: viewController)
return viewController
()
private func add(asChildViewController viewController: UIViewController)
// Add Child View Controller
addChildViewController(viewController)
// Add Child View as Subview
view.addSubview(viewController.view)
// Configure Child View
viewController.view.frame = view.bounds
viewController.view.autoresizingMask = [.flexibleWidth, .flexibleHeight]
// Notify Child View Controller
viewController.didMove(toParentViewController: self)
private func remove(asChildViewController viewController: UIViewController)
// Notify Child View Controller
viewController.willMove(toParentViewController: nil)
// Remove Child View From Superview
viewController.view.removeFromSuperview()
// Notify Child View Controller
viewController.removeFromParentViewController()
internal func test()
print("test")
internal func updateView()
if segmentedControl.selectedSegmentIndex == 0
let position = viewAvgsTab.tableView.contentOffset.y;
viewLiveTab.tableView.contentOffset = CGPoint(x:0, y:position);
remove(asChildViewController: viewAvgsTab)
add(asChildViewController: viewLiveTab)
else
let position = viewLiveTab.tableView.contentOffset.y;
viewAvgsTab.tableView.contentOffset = CGPoint(x:0, y:position);
remove(asChildViewController: viewLiveTab)
add(asChildViewController: viewAvgsTab)
我查看了很多示例,但我不理解整个“设置委托”的内容,即 theSecondViewController.delegate = self.有时我会看到您不需要这样做的示例。而其他时候,我的 VC 似乎甚至没有委托财产。所以我不确定这是否是我的具体问题,但任何方向都将不胜感激。谢谢
【问题讨论】:
【参考方案1】:实现委托分为三个步骤。
-
创建协议..(您已经通过创建 updateChildView 协议完成了此操作)
您需要在您希望接收和处理此数据的类中实现此协议。(您尚未完成此步骤,这就是您无法设置 buyVC.delegate = self 的原因)
您需要在 ViewController2 中添加一个名为“delegate”的属性,并在步骤 1 中将其作为您的协议类型(您尚未完成此步骤,并且 vc2 中没有名为“delegate”的属性..这就是为什么你得到这个错误'buyVC没有成员代表')
这是一个简单的例子:
协议:
protocol UpdateChildView //removed :class
func updateView()
func test()
var playerSelected: Player? get set
视图控制器 A:
class NBARotoHome: UIViewController, UpdateChildView //added conformance to the protocol
//add the methods for conforming to protocol and add your implementation
func updateView()
//add your implementation
func test()
//add your implementation
var playerSelected: Player?
//add your implementation
prepare(for: Segue)
/** code for passing data **/
let navVC = segue.destination as? UINavigationController
let buyVC = navVC?.viewControllers.first as! NBARotoTabPager
buyVC.delegate = self
//sets the delegate in the new viewcontroller
//remember.. delegate is a property in the next vc
// and the property only accepts any viewcontroller that is implements updatechildview protocol
present(vc2)
viewcontroller2:
class viewControllerB: UIViewController
var delegate: UpdateChildView? //add this
viewdidload
delegate?.test() //call the func in the previous vc
【讨论】:
谢谢,这绝对给了我一个清晰而有用的例子。我不确定这是否能满足我的特殊需求,因为我认为我需要在 viewControllerB 中实现方法的一致性和实现。这是完全奇怪和不可能的吗? 协议只是给出一个类必须实现的所需方法和属性的列表。所以只要继承协议,实现需要的方法,应该没问题... 您的代码的问题是您在 NBARtoHome 视图控制器中有一个 updateChildView 属性,并且未设置,因此为 nil。 尝试将 NBArtolive viewcontroller 设置为 NBARtoHome.updatechildview 属性中的一个属性,您应该可以调用测试函数 所以我让协议按照您在示例中显示的方式工作。我真正的问题是我想从 LoadViewData()(NBARotoHome 中的最后一个方法)调用 updateView()(NBATabPager 中的最后一个方法)。您的意思是将 NBARotoTabPager 设置为 NBARotoHome.loadViewData() 中的属性吗?还是我都倒退了?以上是关于Swift - 通过导航控制器委托的主要内容,如果未能解决你的问题,请参考以下文章