In creating an App, I want to achieve:
First Visit (if !setup):
1) SetupView [UINavigationController]
2) OverviewView [UINavigationController]
Second Visit (if setup):
1) OverviewView [UINavigationController]
I'm looking to use storyboards, but what is the best practice to use here? Should I
a) Create separate storyboards (one for setup, one for regular use) and change between those two
b) Have a single storyboard, with two separate UINavigationControllers, having SetupView as the initial and programmatically check setup? yes/no to forward to the OverviewView? If so, which transaction? I tried doing this, but the App crashes if I do a push segue to the new nav controller.
Looking forward to hearing from you guys!
go with option B, you just need to make sure in your app delegate to perform a check on which controller to show.
You can set in your Settings.plist a BOOL variable that show if the setup has already done or not. fetch that result from your settings plist and use it to call one or another view controller. ( if the BOOL hasSetup is TRUE ( you already have setted all up ) you won't even create the instance of the setup controller ).
Related
I'm trying to learn how delegates work and wrap my head around the concept. I'm finding I get some of the ideas. I understand you use it to pass data from one view controller to another, however wouldn't it work the same if I just sent data from a segue and every time the 1st view controller would appear, it would use that data?
So for example I have 2 view controllers.
1 is homeViewController and
2 is editViewController.
I have a variable titled "addressOfHome" which is a string in homeViewController(1).
In homeViewController under the method "viewDidAppear"
I also set the addressLabel = addressOfHome.
Then I just pass the data from editViewController(2) to homeViewController(1)
when the segue's destination vc is homeViewController ?
I'm terrible at explaining things so I apologize for that, but I gave it my best shot. Thanks for your time!
Delegates are mainly used to "trigger action" on an object from another one.
An object delegates a way to handle something to someone else, for example when you click on an UIAlertView button, if its delegate is set on a viewController, alertView:clickedButtonAtIndex will be executed on the VC, which can so react as it want
I'm terrible at explaining things
Haha, yes, you are !
A delegate isn't for that - a delegate is a way to over-ride the default behaviour of some feature(s) of a class, without creating your own sub-class. See this post : How does a delegate work in objective-C?
Are you trying to understand how delegates work (in which case, I don't think your example is one that requires a delegate) or are you trying to implement the functionality you describe, and think that a delegate is the way to do it? (I think you actually want a data source).
I am working on an application which allows users to work with a couple of workmodes. Main view of the app contains information common to all workmodes. I want to create a "subview" with ability to change its ViewController. This subview will be used to display information connected with specified workmode. It is important that app goes to MainViewController from WorkmodesViewController in which user chooses workmode to work with.
My question is:
Which tehnique should I use to acheave changeable WorkmodeViewController inside MainViewVontroller
I have found example git project with functionality I need:
https://github.com/mluton/EmbeddedSwapping
I have created a custom class for my UIBarButtonItem (refreshIndicator.m). This button will be on many different view controllers, all push-segued from my MainViewController/NavigationController.
Instead of dragging an outlet onto every single ViewController.m file for iPhone storyboard THEN iPad storyboard (ugh, still targeting iOS7), I want to know if there is a way to complete my task simply within my UIBarButtonItem custom class. I've looked around everywhere but I haven't quite found an answer to this,
All I need to do is check which UIViewController is present, check the last time the page was refreshed, and then based on that time, set an image for the UIBarButtonItem. (I've got this part figured out though, unless someone has a better suggestion). How can I check for the current UIViewController within a custom button class? Is this possible?
Does it need to know which view controller its on so it can tell that vc it was pressed? If that's the case, then use your button's inherited target and action properties. On every vc that contains an instance of the button, in view did load:
self.myRefreshIndicator.target = self;
self.myRefreshIndicator.action = #selector(myRefreshIndicatorTapped:);
- (void)myRefreshIndicatorTapped:(id)sender {
// do whatever
}
More generally, its better to have knowledge about the model flow to the views from the vc, and knowledge of user actions flow from the views. Under that principal, your custom button could have a method like:
- (void)timeIntervalSinceLastRefresh:(NSTimeInterval)seconds {
// change how I look based on how many seconds are passed
}
And your vcs:
NSTimeInterval interval = [[NSDate date] timeIntervalSinceDate:self.lastRefreshDate];
[self.myRefreshIndicator timeIntervalSinceLastRefresh:interval];
If you really must go from a subview to a view controller, you could follow the responder chain as suggested in a few of the answers here (but I would go to great lengths to avoid this sort of thing).
It is possible to achieve this, but the solution is everything but elegant. It is one way of getting around the basic principles of iOS and is strongly discouraged.
One of the ways is to walk through the responder chain, posted by Phil M.
Another way is to look through all subviews of view controllers until you find the button.
Both ways are considered a bad practice and should be avoided.
For your particular case, I would rethink the structure of having a separate instance of the bar button. For example, you could rework it into a single UIButton instance that gets displayed over every view controller and it can also act as a singleton.
I am building a music player app -- in this app, the music player view controller will always sit on top of any other sub-viewcontroller (navigation view, table views, etc) I need actions taken in any potential subview to be sent back up to the player view controller (for example, user selects "play" on a profile page, and I send that event back up) My question is what is the best way to do this? I apologize in advance for being a bit nebulous, but I already know of three ways I can implement it. I just want to know what the "right" way is.
These are the three ways I've thought of:
1.Delegate pattern -- pass the Music Player Controller off to it's children controllers and set itself as the delegate for whenever that event is passed (messy because the first view controller is a navigation view controller, so I think I'd have to pass it down several levels meaning several delegates (correct me if I'm wrong))
2.Notification Center -- register the player view controller for a particular notification, encapsulate the data that's sent from the other viewcontrollers so that I can perform my actions.
3.Singleton-like access of the player view controller - basically allow access to the player view controller from any view controller.
Any help is appreciate to steer me in the right direction. I can do it either of these ways, but as this is a "learning" app, would love to do it right.
IMHO there is no "right way". Frankly I was thinking of all three of them when I read the subject line only.
As you are asing for opinions... I would not recommend the singleton pattern here. This is just because view controllers could stack and by their nature be instanciated multiple times. In terms of maintainable code (readability by others) I'd say no to that approach.
The delegate pattern is fine. But as you say you would have to pass a reference to this view controller from one view controller to the next. Yes, a bit messy.
Well, you could store a reference to the delegate in some singleton. That is not the same as designing a view controller as singleton.
I'd say that the notification center is most appropriate for this type of data flow. Sender and receiver of the message are totally detatched and don't need to 'know each other'. It is a perfect pattern for all kinds of multiple senders and/or mulitple receipient type of messages.
Well, as I said, this is just an opinion.
I would not recommend broadcast notifications (via NSNotificationCenter), they are hard to debug, other developers will have problems to understand, whats going on in your application (application flow), every developer must maintain a global list with all notification names (notificationSender and observer must use the same notification name and they are usually constant string variables), observer can not send back any data after receiving a notification, etc. Broadcasting is really helpful, if all controllers should be notified of the same event (for example Login/Logout events).
If possible, i think one should allways try to use a Delegate Pattern (with clearly defined protocol). Maybe something like:
id <SubViewControllerEvents>musicPlayerVC= [MyMusicAppManager delegate];
if ( [musicPlayerVC respondsToSelector:#selector(userDidSelectPlay)] ) {
[musicPlayerVC userDidSelectPlay];
}
Can anyone tell me how I can phrase an if () statement to discover if a segue's destination view controller will appear in the Detail Split or in the Master Split?
I want to put the if() statement inside my prepareForSegue:sender: methods.
EDIT
All my detail views that are relevant to this question (at the moment) conform to a protocol and I am currently performing introspection on the destination controller using:
if ([segue.destinationViewController conformsToProtocol:#protocol(myProtocol)])...
I can see that this would not work if I wanted:
To be able to show the same class in either Master or Detail of the splitView from time to time, and at the same time...
I only want the if() statement to be true when the view is to be presented in the detail split.
Things like segue.destinationViewController.navigationController == ... don't appear to be any use either.
I was hoping that since we need to set "Master Split" or "Detail Split" when we set the segue up... there would be a way to access that information less circuitously.
SECOND EDIT:
The way I have this set up with using introspection does "work". It just doesn't seem very "Object Oriented". I don't think I should be querying the View Controller at all for this information, I can't see why the VC should know anything about which side of the splitView it will be displayed. Surely the object that should hold onto this information is the Segue and, as I say, it appears this is being "set" in the storyboard when we select "Detail" or "Master" split.
Maybe it isn't a property of anything, but I can't see how to get at it.
I suppose I could query the destinationViewController in its viewWillAppear to discover which NavigationController it is in after it appears on screen but, again, it seems a bit "hacky".
There is probably a better more abstract and reusable way to do this that I'm not aware of, but here is a suggestion that could help in your specific project that requires just a bit of special knowledge of your specific project.
If you use introspection in your prepare for segue, you can check to see if methods exist by using the responds to approach.
So for example, in typical implementations of a splitview controller (note - not all) the detail view will implement the methods to handle rotation. So if this is true in your project, you could do something like this:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.destinationViewController respondsToSelector:#selector(splitViewController:shouldHideViewController:inOrientation:)]) {
//do something
}
}
You could use this same approach based upon something that was unique but constant in your project related to either the master or detail view.
hope that helps,
be well
My experience is a little limited, but most times I've seen prepareForSegue used, the if() block checks segue.identifier to do anything that needs to be done specifically to handle building the new page. If you set the identifier for all your segues, you could just have code to handle each segue from that controller, and change what the code is depending on if that segue goes to a masterViewController or a detailViewController. Not really a well automated way, but it'll get the job done.
EDIT: oh geez, that wording is kinda confusing. If you want me to I can put a code example up, but it'll have to wait until Monday, as I don't have access to a Mac until then.
The talk of classes and protocols gave me another idea, but again, not sure if it will work - I wanted to test it before posting, but I'm not going to have the time to test anytime soon.
I think you should be able to create 2 new classes, UIMasterViewController and UIDetailViewController, that are subclasses of just UIViewController. Then, for each of your actual screens, instead of making them subclasses of UIViewController directly, make them either a UIDetailViewController or UIMasterViewController. Then, in your prepareForSegue,
if ([segue.destinationViewController isKindOfClass:UIMasterViewController])
{
//do master view specific stuff
}
else if ([segue.destinationViewController isKindOfClass:UIDetailViewController])
{
//do detail view stuff here
}
This should be a pretty dependable way to tell where your segue is sending you, as long as you can set up the custom view controller classes right. This still won't solve the first issue noted in the question
"To be able to show the same class in either Master or Detail of the
splitView from time to time, and at the same time..."
This could be overcome by making 2 copies of all of the views you want to be able to show as either or both, then make one a UIMasterViewController and the other a UIDetailViewController - copy-paste should be good for most of the rest.
Let me know if this works - I'm not exactly sure how to set up the controllers off the top of my head, but I'm pretty sure it could be done. If it can, I can see this being a very useful thing.