0

In the app I am developing I need to update 2 view controllers when a button is tapped. I managed to update the view controller which contain the button, but i could not update the content of the other view controller.

I tried to do so by a couple of ways: first, I created a delegate variable (using a protocol) in the view controller of the button and set its value to the other view controller:

var delegate: WeatherServiceDelegateForcast? = ViewController2()

as ViewController2 is the view controller I am trying to update using the delegate.

the protocol:

protocol WeatherServiceDelegateForcast{
    func SetForcast(forcast: ForcastInfo)
}

The SetForcast func in viewController2

func SetForcast(forcast: ForcastInfo) {
    self.day1Label.text = ....
}

the problem is that when executing the function SetForcast, the IBOutlet of day1label is nil and as a result it cannot be updated. I suppose that is happens because the view controller has not yet been loaded, but i could not figure out a way to load it.

secondly, I tried to use segue (without delegate) to pass the data to viewcontroller2. That worked but only when I used type show for the segue and in my app it is critical that it won't open. When i tried to use segue without opening viewcontroller2 (by type custom) it once again did not work and could not identify the IBOutlets.

Any suggestions how to pass the data to viewcontroller2 without opening it?

edit:

this is the code i used:

when the button in viewcontroller1 is tapped it takes the data from textfield and call the function from its property weather service (that works).

 self.weatherService.GetForcast(textField.text!)

GetWeather gets the weather of a city, creates a variable from type forecast and then:

if self.delegate2 != nil
        {
            dispatch_async(dispatch_get_main_queue(), {
                self.delegate2?.SetForecast(forecast)
            })
        }

as delegate2 is the property of weatherService that refers to viewcontroller2 and this is how it is defined in the beginning of weatherService class:

var delegate2: WeatherServiceDelegateForecast? = ViewController2()

and WeatherServiceForcast is the protocol:

protocol WeatherServiceDelegateForcast
{
    func SetForecast(forecast: ForecastInfo)
} 

then, according to the debugger, it executes SetForecast of viewcontroller2 with the right forecast variable:

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]))
}

as day1-7 are variables in viewController2 class from which i want to update the labels of viewController2 afterwards, and this is how these variables are defined:

var day1 = String()
var day2 = String()
var day3 = String()
var day4 = String()
var day5 = String()
var day6 = String()
var day7 = String()

in viewDidLoad i put the code to update the labels into the strings of the variables day1-7 but it seems it firstly calls that function and only then it calls set forecast and updates the variables.

 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

}
0

2 Answers 2

1

Why not update the content of your viewController2 in viewWillAppear or viewDidLoad? A view controller won't load its view and subviews until it needs to display them on screen. Therefore, Views of your viewController2 is not loaded if you are not going to present it, that's why you got nil and you can't access it.

A clean way to achieve what you want is:

  1. Have a separate property in viewController2 to store the data

  2. Set content of the property in viewController1

  3. Then update the view of viewController2 in viewDidLoad or viewWillAppear according to the property you just set.

Edit

Try change this:

if self.delegate2 != nil
        {
            dispatch_async(dispatch_get_main_queue(), {
                self.delegate2?.SetForecast(forecast)
            })
        }

to

if self.delegate2 != nil
    {
        self.delegate2?.SetForecast(forecast)

    }

Code inside a async block will be executed asynchronously , so viewWillAppear or viewDidload may be called before these properties are set. That's why these values are "". Also, no need to use async block here, what you are doing in SetForcast is just set values of properties, they are finished almost immediately.

Sign up to request clarification or add additional context in comments.

11 Comments

I tried that but for some reason in it firstly executes viewDidLoad or viewWillAppear - it updates the labels i need to the properties that are still not updated and only then it puts the data i need in the properties but it is too late. Perhaps it has something to do with the fact that both of these view controllers are in the same scroll view of another view controller? maybe that causes the viewDidLoad or viewWillAppear to start too soon?
Could you add the code to your question? Then I can see if I can help you
I added the code that went wrong in the edit, i would be very thankful if you could skim through it @luiyezheng
I now noticed that the app executes the code of viewDidLoad and ViewWillApear at the very beginning when the app starts and never executes it again, I think it means that the viewcontroller2 is loaded from the beginning but i still cannot update the content of view controller2 as the labels are nil when i try to update them so it's weird
One thing I notice is that you put the 'setForecast' in a async block, why did you do this? If you put something in a async block, then it is supposed not to block the threads ,and viewWillAppear or viewDidload could be called before these properties are set.
|
0

You simply can't do this.

If the ViewController2 is not loaded it won't never take the data.

You first have to initialize it, then you can give it the data, without displaying it.

You simply have to do an "alloc-init" to load it inside a variable. The you give the data.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.