它的作用
- 当我的选项卡控制器中第一个页面加载时,我从一个JSON文件中获取数据
- 我将其存储在数组中(在第一个视图控制器中)
- 获取到的数据将显示在第二个视图控制器中。这些数据已经被加载并存储在第一个视图控制器的数组中。
问题:
我无法找到一种方法来在两个视图控制器之间传递数据,因为不能基于Segue标识符来传递数据,因为这是一个选项卡控制器
请帮忙解决!
它的作用
问题:
我无法找到一种方法来在两个视图控制器之间传递数据,因为不能基于Segue标识符来传递数据,因为这是一个选项卡控制器
请帮忙解决!
如果您需要在视图控制器之间传递数据,则:
var secondTab = self.tabBarController?.viewControllers[1] as SecondViewController
secondTab.array = firstArray
如Woodster在上面的回答中建议的那样,我最终使用了单例模式。
在Swift 3中
创建一个新的Swift文件并创建一个类:
class Items {
static let sharedInstance = Items()
var array = [String]()
}
在任何一个你的视图控制器中,你都可以像这样访问你的数组:
Items.sharedInstance.array.append("New String")
print(Items.sharedInstance.array)
H. Serdar的代码示例是正确的,这是访问另一个选项卡的视图控制器并向其提供数据的方法。
请记住,在Swift中传递数组时,您是按值传递它的 ,而不像Objective-C一样按引用传递。这意味着您的第二个视图控制器所做的更改不会反映在第一个视图控制器中,因为第二个视图控制器正在使用数组的副本,而不是相同的数组。如果您想让两个视图控制器修改同一个数组,请将数组放在类中,并传递该类的单个实例。
还有其他一些注意事项: 您可以对TabBarController进行子类化,以给它一个存储数据的属性,并且该属性可供所有选项卡使用:
if let tbc = tabBarController as? YourCustomTabBarSubclass {
println("here's my data \(tbc.array)")
}
在这种情况下,您将从多个标签页访问同一数组,因此一个标签页中的更改会反映在其他地方。
我建议不要使用您的应用程序委托作为存储数据的集中位置。这不是应用程序委托的目的。它的目的是处理应用程序对象的委托调用。
视图控制器应该拥有所有需要完成其工作的封装在其中的数据。它们与其模型数据(例如您的数组、数据库引用或托管对象上下文引用)保持连接,而不是通过遍历视图控制器图或进入委托甚至使用全局变量来访问另一个对象。这种模块化、自包含的视图控制器结构使您可以重新组织您的应用程序以适应不同设备的相似但唯一的设计,例如在一个设备上(如iPad)中以弹出视图控制器的形式呈现,在另一个设备上(如iPhone)则以全屏形式呈现。
SWIFT 3
在您的第一个视图控制器中,像平常一样声明变量(在您的情况下是一个数组)。
在您的第二个视图控制器中,请执行以下操作:
var yourVariable: YourVariableClass {
get {
return (self.tabBarController!.viewControllers![0] as! FirstViewControllerClass).yourVariable
}
set {
(self.tabBarController!.viewControllers![0] as! FirstViewControllerClass).yourVariable = newValue
}
}
Xcode 11 & Swift 5 + Storyboard + 依赖注入方法
假设您正在使用Storyboard,这是我设计的一种方法。
步骤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 }
}
var window: UIWindow?
。在xCode 11和Swift 5中,这个变量从appDelegate中移动了出来,所以很多类似的答案和教程都已经过时了。storyboard.instantiateViewController(withIdentifier:
您需要添加您用的名称作为参数。在我的截图中,您会看到我将其称为tabBarController。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()
}
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
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]
}
}