how to use GameCenterManager in multiple view controllers - ios

I would like to be able to add a score, in a different view controller then the main. So what is the best way to replace self in this call?
[self.gameCenterManager reportScore: self.currentScore forCategory:self.currentLeaderBoard];
I thought about passing it in to the view controller, but it is the third view controller, so i would need to pass it twice, feels wrong to me.
I thought about a NSManagedObjectContext, but then I saw in the sample has GameCenterManagerDelegate.
Is there a way to use that anywhere in the game?

Check out GKTapper to see this, but the VC that you call that function from should have a GameCenterManager declared.
Then your call will work, check out GKTapper.
http://developer.apple.com/library/ios/#samplecode/GKTapper/Introduction/Intro.html

Related

Calling functions from separate view controllers in swift

I think the solution to this is going to need to use delegation, but I'm unfamiliar with how to use them.
So in my project, I have my main viewcontroller/storyboard that contains a UIScrollView. That UIScrollview calls another storyboard (xib file) as a subview. The other storyboard (which is an xib file) is controlled with another swift file.
My question is, when I call an action inside of my other storyboard, how can I call a function from the main viewcontroller. Like say the viewdidload from the first viewcontroller.
I can't make the whole thing a global function, it needs to stay inside its class. So if I try to do ViewController.viewDidLoad() it needs (I think) an instance variable or something.
Thanks.
You can try:
Using weak variable (property) in the other class with type UIViewController
Assign the parent view controller to that property after the other view is initialized
Good reads about weak, strong, unowned references Here And Here
Firstly, if you want to call it with class name as you said above declare your method with "class". So its just like static in Java. It makes it generic to call it anywhere in your project. Make a separate extension.
class func myfunc(){
}
if you want to send data from B to A controller. You use what is called delegation. You give the work of B to A. Make a protocol above B for functions that you want to do or send with them. Call them in B. And then in A write code for those functions. So that you have the data from B to A
Else you demand something like common data. Create a singleton class and initialize properties methods there. You can use objects for that and call it in other controller to modify or make different instances.
You dont call viewDidLoad(). As the name says it loads once. If you want something that modify everytime you screen appears, use viewWillAppear

iOS Delegates instead of passing data through a segue

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).

Check which UIViewController my custom button class is on w/o Storyboard

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.

Best design/pattern to use for first-use tutorial in app?

The background:
I have an app with 5 tabs. The first time a user navigates to each tab, I would like to show a one-time "tutorial". I intend to do this by creating a "TutorialViewController" that will handle displaying these "tutorial" views and will have buttons for next/back etc...
The problem:
I'm not sure the best pattern to use for implementing the logic for whether or not to show these screens and instantiating the "TutorialViewController" to display them. The goal is to have a single line of code (a single method call) that would show the tutorial if necessary. I'm trying to avoid duplication of code across the 5 view controllers. The problem is where/how to implement this single method. As a class method on TutorialViewController? As a global C function?
Things I've considered:
1) Implementing a class method on TutorialViewController called "displayTutorialIfNecessary". In this case, each view controller that has a tutorial would call this class method from their "viewDidAppear" methods. This class method would check to see if the tutorial has already been shown, and if not, it would instantiate a TutorialViewController object to handle to display it. In this option, I guess I would have to pass in "self" from each calling view controller and the class method would use that to display the TutorialViewController.
2) Implementing a class method on TutorialViewController called "tutorialShouldBeDisplayedForScreen: ". In this option, each calling view controller would call this method, and if it returns true, each vc would instantiate and present the "TutorialViewController" which would handle displaying the tutorial.
I'm sure there is a "best practice" or a pattern that fits this scenario, but I'm not sure what the best implementation is. Thanks in advance for your recommendations.
To summarize: Instead of having something like this in each view controller:
if ([TutorialViewController shouldDisplayTutorialForScreen:<someEnum>])
{
TutorialViewController *myTutorialVC = [[TutorialViewController alloc] init];
[self displayModalViewController: myTutorialVC];
}
I'd like something more like this:
[FirstUseViewController displayTutorialIfNecessaryForScreen: <someEnum> forParentViewController: self];
store the tutorial has shown state into NSUserDefaults and use factory method design pattern to let each UIViewController you'll need create and return tutorial UIViewController like:
- (UIViewController *)tutorialVC {
return [[MYHomeScreenTutorialVC alloc] init];
}

Segue destination types & how to find them in code

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.

Resources