Passing data from static table inside second controller to first view controller - ios

I working on alarm clock app and Im trying to pass data from B controller (the one in the middle of picture) to the previous one (which is A) . As you can see B view controller contains UIView which is “filled” with static table view controller (C).
I can pass data back from the B to A with delegate , it works fine, but I don’t know how pass data from the C to A (using segue and delegates?). C controller is inside B controller.
I just tried simply with segue (As you can see I created segue between C and A) and delegate, but It didn’t work and I really don’t know if it’s the good idea or practice.
To call protocol method I use this code in C controller (function parameter is just for testing purposes):
override func viewWillDisappear(_ animated: Bool) {
self.delegate?.passAlarmSettings(test: 1)
}
Or maybe I should pass from C to B and then from B to A? Or is any better way to do it?
Thanks for any suggestions

Related

How do I return to my primary display (A) if I go from screen A to B to C back to B using unwindSegue

I currently am learning how to program in Swift and have made 3 different pages; Pages A, B, and C. From page A, I am able to navigate to page B, and from page B, I am able to go to either page C or page A. When I go to page C I can go back to page B or page A.
The issue that I am running into however is that if I go from Page A to Page B to Page C back to Page B, when I try to close Page B, it would display Page C briefly before closing back to page A.
All of these are on separate viewcontrollers and I've just been presenting all of them modally each time
I've tried using Unwind Segues Step-by-Step and Create Unwind Segues in Swift 3
to understand what I've been doing wrong, however from what I've read on them (and from my limited knowledge of Swift), none of them discuss going back a single page and then trying to close after. They all go from 1 -> 2 -> 3 back to 1 without the intermediate step of going back to page 2.
#IBAction func close (_ unwindSegue: UIStoryboardSegue){} is what I've been using as my unwindSegues linking these up to my Exit placeholder. This was done on both Pages B and C
Currently there is no error message, it appears to work but it does show that intermediate screen which is not what I am looking for.
Thanks!
You said:
when I tap on the back button on page C -> B it shows that I trigger an Action that presents Modally (if that helps)
That is precisely the problem. Having gone from A to B to C, C should not then modally present B again. You’re creating a new, second instance of B. You’d have a view controller hierarchy that looks like:
A » B1 » C » B2
If, though, you successfully dismissed/unwound from C to B, you would have ended up with only A and B in the view controller hierarchy:
A » B
And then, when B went to dismiss/unwind to A, C would be long gone and there’s no way you’d see it in your animation.
If you’re using unwind segues, I’d suggest that view controller A had an unwind action like so:
#IBAction func unwindToA(_ segue: UIStoryboardSegue) { }
And view controller B could have an unwind action like so:
#IBAction func unwindToB(_ segue: UIStoryboardSegue) { }
Now, when C wants to unwind back to B, if you could use the latter unwind action. If you want to unwind to A (either from B or C), you could use the former one.
Just make sure that you never present/show when you want to go backwards in the view controller hierarchy. Either use unwind segues, or dismiss/pop as appropriate.
I don't really understand your question. But I guess your problem is you used present instead of dismiss when you back to B from C.
Sorry, your question is not fully clear to me . So far I understand if you wanna back from C to B View Controller , then you can do it Simply use
self.dismiss(animated: false, completion: nil)
in Your Exit Button action . Hopefully it will help .
Seems quite confusing question description.
Not sure but maybe you have mistakenly added segue from Page B -> C on the same Back button. Please check that also.
I've created SimpleUnwindExample project on GitHub. Hope It will help in to fix your issue.
Repository Link: https://github.com/harshal-wani/SimpleUnwindExample
Cheers!

Detect navigation pop in destination view controller

Using a UINavigationController in Xamarin.iOS (targetting iOS 11/12) I'd like to detect, in the destination View Controller when I'm being navigated back to - i.e. a pop. I specifically want to exclude/detect when the destination VC is being pushed for the first time.
To be explicit, given that we've navigated from A to C, and back to B:
[A] -(push)-> [B] -(push)-> [C] -(pop)-> [B]
I'd like to detect/discriminate - in B - between the initial push from A -> B and a subsequent pop from C -> B.
Conceptually this is identical to the questions posed here and here and I should - apparently - be able to use a combination of isMovingToParentViewController / IsBeingPresented / View.Window in ViewWillAppear() but, having tried the approaches in both the linked questions (and a few other things), I'm not seeing the expected values for these properties; they're always False, and View.Window is always null.
Is this a Xamarin.iOS-specific quirk, or am I missing something? If it is Xamarin-related is there a workaround? And if not does anyone have a bare-bones C# example of this detection working?
I'd prefer not to have to maintain state in the navigation controller (or delegate, or individual VCs) since the app structure could change in the future. However, a solution that made use of the nav controller or delegate to indicate the direction of navigation (pop vs push) to the destination VC - 'B', above - would be acceptable.
If you want to manipulate navigation operation, isMovingToParentViewController should work. Place it in your B controller's view will appear lifecycle event:
public override void ViewWillAppear(bool animated)
{
base.ViewWillAppear(animated);
if (IsMovingToParentViewController)
{
// Come from A
}
else
{
// Pop from C
}
}
Here is the effect, I tested it on iOS 12:
Another way to detect it is:
When you want to push B from A, you have to initialize a new B for pushing so B's ViewDidLoad event will be called. When popping from C, B has existed in your navigation stack so that the ViewDidLoad won't be fired.

Cycles in NavigationController - how to avoid memory leaks?

In my app I have a navigation controller with four controllers. The user navigate from A -> B -> C -> D -> A_1 -> B_2 -> ... etc. It's one way and every ViewController is always a new ViewController.
This cycle is intended. But in ViewController A and C I initialize GoogleMaps which is using a lot of memory. So after 15 loops (and 30 inits of GoogleMaps) my app crashes because of a memory leak.
Now I see different possibilities to solve this problem.
1) I do not init a new ViewController rather I reuse my VCs. So Google Maps just initialize two times.
I dislike this, because my VCs could have different states. A clean init would be more comfortable and a smaller source of errors
2) I remove the stack at the right time, because the navigation is just one way. When the transition from A -> B is done I could throw A away. Same thing for C -> D.
3) I deinit Google Maps after transitions. I don't know how to do this yet but I'm quite sure that I will figure it out.
I read about setViewControllers by which I can replace view controllers.
What is the best practice? What recomments Apple?
Start with the 3rd and the easiest option:
Use override func viewWillDisappear(){} to deinit google maps. You could use this method for 2nd option as well.
But I think, you should use delegates when you go back to A from D. What do you change on A, when you reach it again?
You mentioned that navigation is just one way. If so you can just replace UINavigationController's viewControllers array. In other words, you may not need navigation stack if a user does not go backward in the stack.
Alternatively, I got a similar issue in my app. When I am pushing a controller in the UINavigationController it checks the existing viewControllers and modifies it. For example, if an identical controller is already there, pop to that copy.
You can navigate view controllers from A -> B -> C -> D -> A_1 -> B_2 -> ... etc. using two method.
Method 1:
When you are going to D controller then pop to a specific controller(A controller) and again navigate cycle A to D with the push view controller.
self.navigationController?.popToViewController(A, animated: true)
Method 2:
When you are going to D controller then the present controller (A controller) and dismiss presented cycle flow when you again reached at D controller
viewController.present(A, animated:true, completion: nil)

Getting data from another view controller (not via passing the data forward or backward) in Swift 4

Say I have View Controller A, where I have an array with data.
Now I also have a couple of other View Controllers (B,C,D, etc...)where I need that array.
I know I could pass the data forward using segues to each of the other View Controllers. But It seems not the perfect solution for me as I have to pass the data each time through a lot of different View Controllers
I would rather have a method where I define in View controller B "Get the data from View Controller A"
(As I understand passing data backwards is not what I want to achieve because I don't want to change the array in View controller B and pass it back to View Controller A. I only want to read/get the data within View Controller B from View Controller A.
Can somebody point me to a solution for this? Or do I have to pass the data forward from VC A to VC B?
I guess it is a matter of taste but I would rather write my code in VC B/C/D in case I need the data from VC A than passing each time data from A to every other VC...
Create a singleton class. let's say DataManager.
class DataManager: NSObject {
// A Singleton instance
static let shared = DataManager()
// your array
var dataArray = [String]()
}
now access this array from anywhere in the app.
Print(DataManager.shared.dataArray)
Do I have to pass the data forward from VC A to VC B?
You don't have to, but you should.
The suggested singleton pattern is considered an anti-pattern nowadays, you can read more about why here: What is so bad about singletons?.
It's not just a matter of taste, your code will be more maintainable if you avoid singletons.
Even if you use CoreData instead of an array in ViewController A, you will/should pass references from A to B, be it the Managed Object Context or an array of objects that you retrieved from CoreData in ViewController A. You can see this happening in the default template provided by XCode/Apple for a MasterDetail app with CoreData (just create a new project for that).

unwinding to two different view controllers in iOS

I am new to iOS development and having a fundamental question as how i can re-use same view controller from two different view controllers to perform a specific function.
Here is my problem.
Say we have three view controllers A, B and C. And C performs a specific function and it's output i want to use in both A and B.
Say A, has two edit box A1 and A2 and a button "Call C",
A1 is edit box that user fills in and to take input for A2, we have to call C by pressing "Call C" button that i have segued in storyboard.
Similarly B, has two edit box B1 and B2 and also a button "Call C".
B1 is edit box that user fills in and to take input for B2, we have to call C by pressing "Call C" button that i have segued in storyboard.
Essentially i want to make use of C for two different view controllers where C will return some string to calling view that i can fill in B2 or C2 edit boxes.
Here are two ways to unwind:
Method - A:
Programmatically you can call performSegueWithIdentifier to caller view controller and return to it, but in this process called view controller (i.e. A or B) gets re-created, so input that may have been done by user on control A1 or C1 is lost as A and B views are re-created.
So i can programmatically unwind but state is lost of calling view controller as it gets re-created.
Method - B:
In both A and B i create unwind methods like:
-(IBAction) receiveDataFromCtoA:(UIStoryboardSegue *)segue
-(IBAction) receiveDataFromCtoB:(UIStoryboardSegue *)segue
respectively.
But in view C, i can only unwind in Exit to either of the two functions however it does allow me to retain value of calling view controller controls A1 / C1.
So unwinding from Exit works as expected, but i can only unwind to either of the two and thus i can't reuse view controller C for both.
So whole point is how you can make use of a view controller which takes some input, performs some calculation and return results and can be used by any calling view.
I did look at following post:
Unwind segues for 2 View Controllers
But it does not answer.
Any help is appreciated.
You should be using delegates in order to achieve this.
Delegates and Data Sources
I would suggest looking here for more info
How do I create delegates in Objective-C?

Resources