从另一个视图控制器更新视图控制器的内容而不打开它
Posted
技术标签:
【中文标题】从另一个视图控制器更新视图控制器的内容而不打开它【英文标题】:Updating a view controller's content from another view controller without opening it 【发布时间】:2016-06-03 12:48:15 【问题描述】:在我正在开发的应用程序中,我需要在点击按钮时更新 2 个视图控制器。我设法更新了包含按钮的视图控制器,但我无法更新另一个视图控制器的内容。
我尝试通过以下几种方式做到这一点:首先,我在按钮的视图控制器中创建了一个委托变量(使用协议)并将其值设置为另一个视图控制器:
var delegate: WeatherServiceDelegateForcast? = ViewController2()
因为 ViewController2 是我尝试使用委托更新的视图控制器。
协议:
protocol WeatherServiceDelegateForcast
func SetForcast(forcast: ForcastInfo)
viewController2 中的 SetForcast 函数
func SetForcast(forcast: ForcastInfo)
self.day1Label.text = ....
问题是在执行SetForcast函数时,day1label的IBOutlet为nil,因此无法更新。我想这是因为视图控制器尚未加载,但我无法找到加载它的方法。
其次,我尝试使用 segue(无委托)将数据传递给 viewcontroller2。这有效,但只有当我为 segue 使用 type show 并且在我的应用程序中,它不会打开是至关重要的。当我尝试在不打开 viewcontroller2(按自定义类型)的情况下使用 segue 时,它再次不起作用并且无法识别 IBOutlets。
有什么建议如何在不打开数据的情况下将数据传递给 viewcontroller2?
编辑:
这是我使用的代码:
当点击 viewcontroller1 中的按钮时,它会从文本字段中获取数据并从其属性天气服务中调用函数(有效)。
self.weatherService.GetForcast(textField.text!)
GetWeather 获取一个城市的天气,从预测类型创建一个变量,然后:
if self.delegate2 != nil
dispatch_async(dispatch_get_main_queue(),
self.delegate2?.SetForecast(forecast)
)
因为delegate2是weatherService的属性,它引用viewcontroller2,这就是它在weatherService类开头的定义:
var delegate2: WeatherServiceDelegateForecast? = ViewController2()
WeatherServiceForcast 是协议:
protocol WeatherServiceDelegateForcast
func SetForecast(forecast: ForecastInfo)
然后,根据调试器,它使用正确的预测变量执行 viewcontroller2 的 SetForecast:
func SetForcast(forcast: ForcastInfo)
self.day1 = String(round(forcast.day[0])) + "-" + String(round(forcast.night[0]))
self.day2 = String(round(forcast.day[1])) + "-" + String(round(forcast.night[1]))
self.day3 = String(round(forcast.day[2])) + "-" + String(round(forcast.night[2]))
self.day4 = String(round(forcast.day[3])) + "-" + String(round(forcast.night[3]))
self.day5 = String(round(forcast.day[4])) + "-" + String(round(forcast.night[4]))
self.day6 = String(round(forcast.day[5])) + "-" + String(round(forcast.night[5]))
self.day7 = String(round(forcast.day[6])) + "-" + String(round(forcast.night[6]))
因为 day1-7 是 viewController2 类中的变量,之后我想从中更新 viewController2 的标签,这就是这些变量的定义方式:
var day1 = String()
var day2 = String()
var day3 = String()
var day4 = String()
var day5 = String()
var day6 = String()
var day7 = String()
在 viewDidLoad 中,我将更新标签的代码放入变量 day1-7 的字符串中,但似乎它首先调用了该函数,然后才调用设置预测并更新变量。
override func viewDidLoad()
// Do any additional setup after loading the view.
self.day1Label.text = self.day1
self.day2Label.text = self.day2
self.day3Label.text = self.day3
self.day4Label.text = self.day4
self.day5Label.text = self.day5
self.day6Label.text = self.day6
self.day7Label.text = self.day7
【问题讨论】:
【参考方案1】:为什么不更新viewWillAppear
或viewDidLoad
中的viewController2
的内容?视图控制器在需要在屏幕上显示它们之前不会加载它的视图和子视图。
因此,如果您不打算展示您的viewController2
的视图,则不会加载它,这就是您得到 nil 并且无法访问它的原因。
实现你想要的一个干净的方法是:
在viewController2
中有一个单独的属性来存储数据
在viewController1
中设置属性内容
然后根据你刚才设置的属性更新viewDidLoad
或viewWillAppear
中viewController2
的视图。
编辑
尝试改变这个:
if self.delegate2 != nil
dispatch_async(dispatch_get_main_queue(),
self.delegate2?.SetForecast(forecast)
)
到
if self.delegate2 != nil
self.delegate2?.SetForecast(forecast)
异步块内的代码将异步执行,因此可以在设置这些属性之前调用viewWillAppear
或viewDidload
。
这就是为什么这些值是“”。另外,这里不需要使用异步块,您在SetForcast
中所做的只是设置属性值,它们几乎立即完成。
【讨论】:
我试过了,但由于某种原因,它首先执行 viewDidLoad 或 viewWillAppear - 它将我需要的标签更新为仍未更新的属性,然后才将我需要的数据放入属性中,但是为时已晚。也许这与这两个视图控制器都在另一个视图控制器的同一个滚动视图中有关?也许这会导致 viewDidLoad 或 viewWillAppear 启动得太早? 您可以将代码添加到您的问题中吗?那我看看能不能帮到你 我在编辑中添加了出错的代码,如果您能浏览一下,我将非常感谢@luiyzhengspan> 我现在注意到该应用程序在应用程序启动时一开始就执行了viewDidLoad和ViewWillApear的代码并且不再执行它,我认为这意味着viewcontroller2是从头开始加载的但我仍然无法更新视图控制器 2 的内容,因为当我尝试更新它们时标签为零,所以这很奇怪 我注意到的一件事是您将“setForecast”放在异步块中,为什么要这样做?如果你把东西放在异步块中,那么它应该不会阻塞线程,并且可以在设置这些属性之前调用 viewWillAppear 或 viewDidload。【参考方案2】:您根本无法做到这一点。
如果ViewController2
未加载,则它不会从不获取数据。
你首先必须初始化它,然后你可以给它数据,而不用显示它。
您只需执行“alloc-init”即可将其加载到变量中。你提供数据。
【讨论】:
以上是关于从另一个视图控制器更新视图控制器的内容而不打开它的主要内容,如果未能解决你的问题,请参考以下文章