它的作用
问题:
我无法找到在两个视图控制器之间传递数据的方法。由于它是标签栏控制器,因此无法根据segue标识符传递数据
请帮忙!
答案 0 :(得分:20)
如果需要在视图控制器之间传递数据,那么:
var secondTab = self.tabBarController?.viewControllers[1] as SecondViewController
secondTab.array = firstArray
答案 1 :(得分:15)
我最后使用了一个单身人士,就像伍德斯特在上面的回答中所说的那样。
在Swift 3中
创建一个新的swift文件并创建一个类:
class Items {
static let sharedInstance = Items()
var array = [String]()
}
在任何视图控制器中,您都可以像这样访问数组:
Items.sharedInstance.array.append("New String")
print(Items.sharedInstance.array)
答案 2 :(得分:10)
小时。 Serdar的代码示例是正确的,这是访问另一个选项卡的视图控制器并为其提供数据的方法。
请记住,当您在Swift中传递数组you're passing it by value时,与Objective-C不同,后者通过引用传递它。这意味着第二个视图控制器所做的更改不会反映在第一个视图控制器中,因为第二个视图控制器正在使用数组的副本,而不是相同的数组。如果您希望两个视图控制器都修改同一个数组,请将该数组放入一个类中,并传递该类的单个实例。
其他一些注意事项: 您可以将TabBarController子类化,为其提供一个存储数据的属性,并且可以使用以下所有选项卡使用:
if let tbc = tabBarController as? YourCustomTabBarSubclass {
println("here's my data \(tbc.array)")
}
在这种情况下,您将从多个选项卡访问相同的阵列,因此一个选项卡中的更改将反映在其他位置。
我建议不要将App Delegate用作存储数据的集中位置。这不是应用程序代表的目的。其目的是处理应用程序对象的委托调用。
View Controllers应该拥有他们完成工作所需的所有数据。它们与模型数据(例如您的数组,或对数据库或托管对象上下文的引用)有关,而不是让视图控制器通过遍历视图控制器图形或进入代理甚至连接到另一个对象。使用全局变量。这种模块化,独立的视图控制器结构允许您在不同设备上重新构建您的应用程序以获得类似但独特的设计,例如在一个设备(如iPad)上的弹出窗口中呈现视图控制器并在另一个设备上呈现全屏幕,例如一部iPhone。
答案 3 :(得分:6)
SWIFT 3
在你的第一个viewcontroller中,像往常一样声明你的变量(在你的情况下是一个数组)。
在第二个viewcontroller中,执行以下操作:
var yourVariable: YourVariableClass {
get {
return (self.tabBarController!.viewControllers![0] as! FirstViewControllerClass).yourVariable
}
set {
(self.tabBarController!.viewControllers![0] as! FirstViewControllerClass).yourVariable = newValue
}
}
这是有效的,因为在tabbarcontroller中,标签项后面的所有viewcontrollers都被初始化。通过在第二个viewcontroller中执行此操作,您实际上是从/在第一个viewcontroller中获取/设置变量。
答案 4 :(得分:2)
对于Xcode 11和Swift 5 +故事板+依赖注入方法
假设您正在使用情节提要,这是我设计的方法。
步骤1:
像在下图中一样,在您的tabBarController上放置一个标识符。
第2步:
在 scenedelegate.swift 文件(不是appDelegate.swift)中,将以下代码添加到适当的func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
方法中。
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
self.window = self.window ?? UIWindow()//@JA- If this scene's self.window is nil then set a new UIWindow object to it.
//@Grab the storyboard and ensure that the tab bar controller is reinstantiated with the details below.
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let tabBarController = storyboard.instantiateViewController(withIdentifier: "tabBarController") as! UITabBarController
for child in tabBarController.viewControllers ?? [] {
if let top = child as? StateControllerProtocol {
print("State Controller Passed To:")
print(child.title!)
top.setState(state: stateController)
}
}
self.window!.rootViewController = tabBarController //Set the rootViewController to our modified version with the StateController instances
self.window!.makeKeyAndVisible()
print("Finished scene setting code")
guard let _ = (scene as? UIWindowScene) else { return }
}
您会注意到scenedelgate.swift文件具有一个成员变量。 var window: UIWindow?
。该曾经是appDelegate的一部分,但已在xCode 11和Swift 5中进行了更改,因此许多类似的答案和教程都将过时。
代码中写着storyboard.instantiateViewController(withIdentifier:
的部分您将要添加用于参数的名称。在我的屏幕截图中,您会看到我将其称为tabBarController。
为使此函数可在任何类型的viewController上运行而不必在索引上单独实例化每个函数,我使用了一种称为 StateControllerProtocol 的协议策略。接下来,我们将与保存全局变量的StateController一起创建它。
第3步:
在 stateController.swift 或您要命名此文件的任何名称中,添加以下代码,以删除不适用于您的项目的方面。
import Foundation
struct tdfvars{
var lateBED:Double = 0.0
var acuteBED:Double = 0.0
var rbe:Double = 1.4
var t1half:Double = 1.5
var alphaBetaLate:Double = 3.0
var alphaBetaAcute:Double = 10.0
var totalDose:Double = 6000.00
var dosePerFraction:Double = 200.0
var numOfFractions:Double = 30
var totalTime:Double = 168
var ldrDose:Double = 8500.0
}
//@JA - Protocol that view controllers should have that defines that it should have a function to setState
protocol StateControllerProtocol {
func setState(state: StateController)
}
class StateController {
var tdfvariables:tdfvars = tdfvars()
}
您希望在视图之间共享的变量我建议添加到结构中。我命名了我的tdfvariables,但您将要命名与您的项目相关的名称。还要注意此处定义的协议。这是一个协议,它将作为扩展添加到每个viewController中,该扩展定义了应该有一个函数来设置其stateController成员变量(我们尚未定义,但将在后续步骤中) 。
第4步:
在我的情况下,我有2个由tabBarController控制的视图。 StandardRegimenViewController和settingsViewController。这是您要为viewController添加的代码。
import UIKit
class SettingsViewController: UIViewController {
var stateController: StateController?
override func viewDidLoad() {
super.viewDidLoad()
}
}
//@JA - This adds the stateController variable to the viewController
extension SettingsViewController: StateControllerProtocol {
func setState(state: StateController) {
self.stateController = state
}
}
此处的扩展将协议添加到您的类,并根据我们在stateController.swift文件中先前定义的功能添加功能。这就是最终将stateController及其结构值放入viewController中的原因。
第5步:
使用stateController来访问您的变量!你完成了!
以下是我在其中一个控制器中执行此操作的示例。
stateController?.tdfvariables.lateBED = 100
您可以用相同的方式读取变量!这种方法的优势在于,您不使用Singletons ,而对ViewController以及可能需要访问变量的任何其他对象使用依赖注入。阅读有关依赖注入的更多信息,以了解单例带来的好处,以了解更多信息。
答案 5 :(得分:0)
我的应用程序中有一个选项卡式视图控制器,我使用相同的数组来查看多个选项卡视图。我通过在任何类之外声明数组(在导入UIKit和类声明之间的行中)来实现这一点,这样它本质上是每个视图都可以访问的全局变量。你试过这个吗?
答案 6 :(得分:0)
您可以覆盖 tabBar(didSelect:)
方法,然后索引 UITabViewController 上的 ViewControllers 数组,并将 ViewController 转换为所需的自定义 ViewController。无需共享可变状态以及随之而来的所有问题。
class SecondViewController: UIViewController {
var array: [Int] = []
override func viewDidLoad() {
super.viewDidLoad()
}
}
class TabViewController: UITabBarController {
override func tabBar(
_ tabBar: UITabBar,
didSelect item: UITabBarItem
) {
super.tabBar(tabBar, didSelect: item)
var secondTab = viewControllers?[1] as? SecondViewController
secondTab?.array = [1, 2, 3]
}
}