I've just implemented a commenting feature in my app. Ideally when someone leaves a comment, I'd like all notified people be able to swipe the push notification and open the app on that post.
I assume you want to open the concerned page directly. There are many ways to go about this, and it depends on how your app is laid out.
If you want to open an inner page upon app launch, you can programmatically trigger the segues that the user would otherwise need to make manually. (this ensures the back/home buttons work as opposed to loading the desired page directly).
Here's an excerpt from one of my own code, your use case may not be the same, but this is all i can do unless you give us more details.
- (BOOL) navigateToRespectiveSectionforPushNot:(NSDictionary*)pushNot
{
id rootVC = self.window.rootViewController;
NSLog(#"ROOT CLASS : %#", [rootVC class]);
if ([rootVC isKindOfClass:[SWRevealViewController class]])
{
NSLog(#"Root Class looking good... mission Navigate!!");
SWRevealViewController *homeVC = (SWRevealViewController*) rootVC;
NSString *category = [[pushNot objectForKey:pushPayloadKeyaps] objectForKey:pushPayloadKeyCategory];
NSString *subCat = [[pushNot objectForKey:pushPayloadKeyaps] objectForKey:pushPayloadKeySubCategory];
NSLog(#"category : %# , subcat : %#",category,subCat);
//The code for the page to which i'm supposed to navigate to is contained in the push notification payload
if ([category isEqualToString:pushCategoryItemChat])
{
[homeVC.rearViewController performSegueWithIdentifier:#"chatPush" sender:nil];
UINavigationController *nc = (UINavigationController*)homeVC.frontViewController;
NSLog(#"FrontView Class : %#",[nc.viewControllers[0] class]);
UITableViewController *tvc = (UITableViewController*)nc.viewControllers[0];
NSDictionary *send = #{chatPushTargetUserId:subCat,chatPushTargetUserName:#"",chatPushTargetUserImage:#""};
[tvc performSegueWithIdentifier:#"seguePushDemoVC" sender:send];
return YES;
}
//communityPush historyPush
else if ([category isEqualToString:pushCategoryItemCommunity])
{
if ([subCat isEqualToString:pushSubCatItemNewRequest])
{
[homeVC.rearViewController performSegueWithIdentifier:#"communityPush" sender:nil];
return YES;
}
else if ([subCat isEqualToString:pushSubCatItemAccepted])
{
[homeVC.rearViewController performSegueWithIdentifier:#"communityPush" sender:nil];
return YES;
}
}
else if ([category isEqualToString:pushCategoryItemHistory])
{
[homeVC.rearViewController performSegueWithIdentifier:#"historyPush" sender:nil];
return YES;
}
}
else
{
UIAlertView *whoa = [[UIAlertView alloc] initWithTitle:#"WHOA!!" message:#" That wasn't supposed to happen. You are not even logged in. Call 911..." delegate:nil cancelButtonTitle:#"mmKay.." otherButtonTitles:nil, nil];
[whoa show];
}
return NO;
}
I hope the code is self explanatory. cheers
Related
I'm preparing to launch my first app and want to have multiple leaderboards inside my game. Currently in sandbox mode I can track and log scores into Game Center successfully. Game Center saves my scores (only if it is higher) and seems to be fully functional.
I know through Itunes Connect we have the ability to set up multiple leaderboards and it seems pretty straight forward. I still want to be able to test multiple leaderboards before publishing my game though. Is there a way to do this in sandbox mode? Currently it seems like my scores are only automatically logged into a default leaderboard. Below is the relevant code I'm using to save/access scores. Thanks!
ABGameKitHelper.m
#pragma mark - Leaderboard
-(void) reportScore:(long long)aScore forLeaderboard:(NSString*)leaderboardId
{
GKScore *score = [[GKScore alloc] initWithCategory:leaderboardId];
score.value = aScore;
[score reportScoreWithCompletionHandler:^(NSError *error) {
if (!error)
{
if(![self hasConnectivity])
{
[self cacheScore:score];
}
if (ABGAMEKITHELPER_LOGGING) NSLog(#"ABGameKitHelper: Reported score (%lli) to %# successfully.", score.value, leaderboardId);
}
else
{
[self cacheScore:score];
if (ABGAMEKITHELPER_LOGGING) NSLog(#"ABGameKitHelper: ERROR -> Reporting score (%lli) to %# failed, caching...", score.value, leaderboardId);
}
}];
}
-(void) showLeaderboard:(NSString*)leaderboardId
{
GKLeaderboardViewController *viewController = [GKLeaderboardViewController new];
viewController.leaderboardDelegate = self;
if (leaderboardId)
{
viewController.category = leaderboardId;
CCLOG(#"Going to category already created");
}
[[self topViewController] presentViewController:viewController animated:YES completion:nil];
}
MainScene.m
- (void)gameCenter {
[[ABGameKitHelper sharedHelper] reportScore:1400 forLeaderboard:#"Score"];
[[ABGameKitHelper sharedHelper] showLeaderboard:#"Score"];
}
I'm not sure if I understand your question properly, but I'll try to answer! Game Center does support multiple leaderboards:
-If you want to send a score to specific leaderboard, you just have to call the function [[ABGameKitHelper sharedHelper] reportScore:X forLeaderboard:LEADERBOARD_ID];, where X represents the score you'd like to send, and LEADERBOARD_ID is the ID of the leaderboard you want to send the score to, as specified in iTunes Connect.
-When you have multiple leaderboards, if you don't want to show just one leaderboard, but a list of them all, you should use the GKGameCenterViewController class instead. However, be careful; this ViewController has been added in iOS 6 only, so you must check which version the device is running. I am also using the ABGameKitHelper, so I've made a function to show this kind of view. Here it goes :
ABGameKitHelper.m
- (void) showGameCenter{
if (![[ABGameKitHelper sharedHelper] hasConnectivity]) return;
//Check if device runs on iOS 5
if([[[UIDevice currentDevice]systemVersion]intValue]==5)
{
//If so, we must use the GKLeaderboardViewController
GKLeaderboardViewController *leaderboard = [[GKLeaderboardViewController alloc] init];
if (leaderboard != nil)
{
leaderboard.leaderboardDelegate = self;
[[self topViewController] presentViewController:leaderboard animated:YES completion:nil];
}
}else if ([[[UIDevice currentDevice]systemVersion]intValue]>=6)
{
//if it runs on iOS 6 or higher, we use GKGameCenterViewController
GKGameCenterViewController *gameCenterController = [[GKGameCenterViewController alloc] init];
if (gameCenterController != nil)
{
gameCenterController.gameCenterDelegate = self;
gameCenterController.viewState = GKGameCenterViewControllerStateDefault;
[[self topViewController] presentViewController:gameCenterController animated:YES completion:nil];
}
}
}
And don't forget to add :
- (void) gameCenterViewControllerDidFinish:(GKGameCenterViewController *)gameCenterViewController{
[gameCenterViewController dismissViewControllerAnimated:YES completion:nil];
}
Using this function will allow you to show a nice view containing all your leaderboards and achievements.
Hope this helps!
I've got two labels in a custom UITableViewCell. Their purpose is to indicate the status of a timing operation on the object represented by the cell.
One label displays a countup timer. The other simply blinks "Timer Sleeping." Their visibility is mutually exclusive (if one is visible, the other is not, and vice versa) according to a switch statement to determine which label is currently visible. Each is driven by a dedicated NSTimer.
Everything works fine--until I do a modal segue to another View Controller (for the purpose of adding another entity or other task) and then return to the original VC via Cancel or Savethrough delegation. Then, regardless of which label had been visible (and updating via its timer) prior to the segue, no label is to be seen. The cell appears blank.
The weird thing is that when I segue to yet another VC via a push segue, then return via the "Home" button, the labels appear, blinking or counting up, just as though nothing had happened. The only obvious difference I can see between the two return methods is that the modal is handled via delegation whereas the push is unwound through a nav controller.
Any ideas? I can supply any relevant code, but didn't know where to start and didn't want to paste all of it.
Thanks!
EDIT for clarification in response to question below:
I'm returning via delegation. Here's the code in the modal:
- (IBAction)saveButton:(UIBarButtonItem *)sender
{
if (self.activityField.text.length > 0)
{
if (self.categoryLabel.text.length < 1)
{
// self.thisActivity.category = #"Uncategorized";
// self.thisActivity.name =self.activityField.text;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No category selected"
message:#"Please select a category or Cancel"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
else
{
self.thisCategory.name = self.categoryLabel.text;
self.thisActivity.name = self.activityField.text;
self.thisActivity.category = self.thisCategory.name;
NSLog(#"Category name is %#", self.thisCategory.name);
NSLog(#"Activity name is %#", self.thisActivity.name);
[self.delegate addActivityViewControllerDidSave];
}
}
else
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"No activity entered"
message:#"Please enter a new activity or Cancel"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alert show];
}
}
- (IBAction)cancelButton:(UIBarButtonItem *)sender
{
[self.delegate addActivityViewControllerDidCancel:self.thisActivity];
NSLog(#"delegate is %#",self.delegate);
}
And here's the delegate method implementation code from the original VC:
#pragma mark - AddViewControllerDelegate stuff
-(void) addActivityViewControllerDidSave
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
[localContext MR_saveToPersistentStoreAndWait];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
[self refreshData];
}
-(void) addActivityViewControllerDidCancel:(WMDGActivity *) activityToDelete
{
[activityToDelete MR_deleteEntity];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
[self refreshData];
}
2nd edit:
Here's the refreshData code:
-(void) refreshData
{
actFRC = [WMDGActivity MR_fetchAllSortedBy:#"category,name"
ascending:YES withPredicate:nil
groupBy:#"category"
delegate:nil];
[self.myTableView reloadData];
}
I've tried calling this method in viewDidLoad, and NOT calling it there. Same results.
UPDATE, 3/26/2014:
OK, I've discovered that if I remove the call to refreshData from my addActivityViewControllerDidCancel method, the labels work fine. They likewise work fine if I remove the same line from addActivityViewControllerDidSave. Unfortunately, this prevents newly added items from appearing in the HomeViewController table view until the app is relaunched.
Here is my current code for the cancel and save methods:
-(void) addActivityViewControllerDidSave
{
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
[localContext MR_saveToPersistentStoreAndWait];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
[self refreshData];
}
-(void) addActivityViewControllerDidCancel:(WMDGActivity *) activityToDelete
{
[activityToDelete MR_deleteEntity];
NSManagedObjectContext *localContext = [NSManagedObjectContext MR_contextForCurrentThread];
[localContext MR_saveToPersistentStoreAndWait];
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
// [self refreshData];
}
I view this as a temporary, or interim, fix. Sure would be grateful for a real cure.
Thanks!
I am new to IOS. I am making a login view controller in IOS with one button which is sign in. I have two possible view-controllers that might be shown when the user click on the sign-in button. I am using Storyboard but I can only assign one segue to one button. I don't know how to perform the condition since I seem not to have 100% control over the segue.
Here is my code:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
NSString *stringreponse=[[NSString alloc] initWithData:_responseData encoding:NSUTF8StringEncoding];
// NSLog(#"Split response %#", [splitresponse objectAtIndex:0]);
if([stringreponse isEqualToString:#"0"])
{
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:#"Wrong username or password" message:#"Wrong username or password" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
}
else
{
NSArray *splitresponse=[stringreponse componentsSeparatedByString:#"#"];
if([[splitresponse objectAtIndex:0] isEqualToString:#"Parent"])
{
if([[splitresponse objectAtIndex:2] isEqualToString:#"yes"])
{
//seguechoice=#"showParentRegistration";
//[self performSegueWithIdentifier:#"showParentRegistration" sender:self ];
}else{
//seguechoice=#"showSohoDashboard";
}
}
}
}
you can assign one segue to one UI control but you can assign many to a viewContoller. Simply add all of them to the viewController, give each a different id and then call those id's
if([[splitresponse objectAtIndex:2] isEqualToString:#"yes"])
{
[self performSegueWithIdentifier:#"showParentRegistration" sender:self ];
}
else
{
[self performSegueWithIdentifier:#"showSohoDashboard" sender:self ];
}
Create 2 connection in storyboard from your source view controller to destination view controller (not button). Insert two different identifiers and when the button is pressed do condition and run a segue depends on the condition:
if(CONDITION TO RUN SEGUE !)
{
[self performSegueWithIdentifier:#"SEGUEIDENTIFIER1" sender:self ];
}else {
[self performSegueWithIdentifier:#"SEGUEIDENTIFIER2" sender:self ];
}
I have a framework that creates some views, the app that uses the framework calls a method from it and pass in the current view controller, the framework then calls presentModalViewController to display a view.
It was working just fine with iOS 6.1 SDK but when I updated to Xcode 5 and iOS 7 SDK I don't see the modal view anymore, instead all I get is a blank screen.
EDIT
Heres some code:
The Framework is called "testityi"
testityi.m
#import "TestViewController.h"
#implementation testitiy
- (NSString*) sayHi : (NSString*) name {
return [NSString stringWithFormat:#"Hello %#", name];
}
- (void) displayView:(UIViewController *)parentController {
TestViewController* controller = [[TestViewController alloc] init];
[parentController presentViewController:controller animated:YES completion:nil];
}
TestViewController is simply a view with a label that says "View from framework"
The framework itself works fine, calling sayHi method works just fine.
The third party app has a view with a label and a button which calls sayHi method and then displayView method, heres the view controller code:
MainViewController.m
- (IBAction)buttonPressed:(id)sender {
testitiy* framework = [[testitiy alloc] init];
NSString* msg = [NSString stringWithFormat:#"Calling sayHi method on framework...\n result: %#", [framework sayHi:#"John"]];
UIAlertView* alert = [[UIAlertView alloc] initWithTitle:#"sayHi method call" message:msg delegate:self cancelButtonTitle:#"Ok, show me the view" otherButtonTitles:nil, nil];
[alert show];
}
-(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if(buttonIndex == [alertView cancelButtonIndex]) {
testitiy* framework = [[testitiy alloc] init];
[framework displayView:self];
}
}
The alert button action is also working correctly, I added a NSLog before and its working.
After clicking the alert button a view is presented but instead of containing the label "View from framework" I get a blank screen.
You can see the code on Github
EDIT 2
I got it... I wasn't calling initWithBundle on the ViewController from the framework, I added the a custom init method that calls:
framework: TestViewController.m
+ (NSBundle *)frameworkBundle {
static NSBundle* frameworkBundle = nil;
static dispatch_once_t predicate;
dispatch_once(&predicate, ^{
NSString* mainBundlePath = [[NSBundle mainBundle] resourcePath];
NSString* frameworkBundlePath = [mainBundlePath stringByAppendingPathComponent:#"testity.bundle"];
frameworkBundle = [NSBundle bundleWithPath:frameworkBundlePath];
});
return frameworkBundle;
}
- (id) initWithFramework {
NSBundle* bundle = [[self class] frameworkBundle];
self = [super initWithNibName:#"TestViewController" bundle: bundle];
return self;
}
And changed testitiy.m
- (void) displayView:(UIViewController *)parentController {
TestViewController* controller = [[TestViewController alloc] initWithFramework];
[parentController presentViewController:controller animated:YES completion:nil];
//[parentController.navigationController pushViewController:controller animated:YES];
}
And now its working...
I hope this helps someone else but I'm guessing it was a stupid mistake of mine.
Sorry for all the trouble and thanks for your time!
So after a while I finally understand the issue:
When using a custom framework, all resources like images and NIB files have to be manually included in the third-party app so that it has access to those files.
My problem was that I was including the resources (stored in a bundle) into the third-party app but the framework was trying to display the View based on its own resources, which the app couldn't access, for that reason I was getting a blank screen.
I just needed to tell the framework to use the included bundle into the third-party app to display that View (using the initWithNibName: Bundle method).
See EDIT 2 in the question to see the code that solved my problem.
Hope this helps someone. :-)
I am trying to create an alertView from the appDelegate but I cant get it to work. The alertView will act as a disclaimer when the app launches for the first time. I cant get it to work..the introViewcontroller does not appear. what am I doing wrong? ps. i use storyboards except for the intoViewController which is a nib file.my root view controller is a "fisrtViewController" here is my code: Thank you..
int a;
and in didFinishLaunchingWithOptions
if ( a == 0) {
UIAlertView *disclaimer = [[UIAlertView alloc] initWithTitle:#"Read Before use" message:#"By using this app you agree to its terms and conditions.\n\n\n\n\n\n\n\n\n\n\ntext heren\n\n\n\n\n\n\n\n\n\n\n\n\n" delegate:self cancelButtonTitle:#"No!" otherButtonTitles:#"Yes Let me In", nil];
[disclaimer show];
}
// Override point for customization after application launch.
return YES;
}
-(void) alertView:(UIAlertView *) alertView clickedButtonAtIndex:(NSInteger)buttonIndex{
if (buttonIndex == 1) {
// FirstViewController *firstView = [[FirstViewController alloc] init];
a+=1;
// [self.viewController presentModalViewController:firstView animated:YES];
}
else if (buttonIndex == 2) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Sorry!" message:#"You are not allowed to use this app due to the fact that you did not agree to the terms and Conditions. Please exit this app!" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
if (buttonIndex ==1) {
introViewController *intro = [[introViewController alloc] initWithNibName:#"introViewController" bundle:nil];
[self.viewController presentModalViewController:intro animated:YES];
introViewController *intro = [[introViewController alloc] initWithNibName:#"introViewController" bundle:nil];
[self.viewController presentModalViewController:intro animated:YES];
}
}
ahh... Now I Understand what you are trying to do.
You problem is that self.viewController is not set before you try to present a new modal ViewController. Also, I think your buttonIndex is of by one.
Try instead:
if (buttonIndex == 1)
{
_window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
introViewController *intro = [[introViewController alloc] initWithNibName:#"introViewController" bundle:nil];
_window.rootViewController = _intro;
[_window makeKeyAndVisible];
}
Since your problem has nothing to to do with the UIAlertView, You might want to change the title and description of your question to make it more clear, for others struggling with a similar problem.
Happy coding! :)
The best way to handle this use a some NSString value write to NSUserDefaults file. when the app first time launch with the accepting the disclaimer (eg:#"accept") if user not accepting also update that NSString value accordingly.(#"notAccept").
In didFinishLaunchingWithOptions
if (![[[NSUserDefaults standardUserDefaults]valueForKey:#"key_disclaimer"] isEqualToString:#"accepted"]) {
UIAlertView *disclaimer = [[UIAlertView alloc] initWithTitle:#"Read Before use" message:#"By using this app you agree to its terms and conditions.\n\n\n\n\n\n\n\n\n\n\ntext heren\n\n\n\n\n\n\n\n\n\n\n\n\n" delegate:self cancelButtonTitle:#"No!" otherButtonTitles:#"Yes Let me In", nil];
[disclaimer show];
[disclaimer release];
// make sure to release it.
}
//if user accept the disclaimer.
[[NSUserDefaults standardUserDefaults]setValue:#"accepted" forKey:#"key_disclaimer"];
//if user not accept the disclaimer,
[[NSUserDefaults standardUserDefaults]setValue:#"notAccepted" forKey:#"key_disclaimer"];
update "key_disclaimer" accordingly. thats the best way. in your example the value of a using in the temporally. if you close and restart the app it will ask again the disclaimer.
in your code
int a;
replace it by using
int a = 0;
it will be ok.
thanx.
If your code is exactly like you wrote above, a won't be 0.
If you don't explicitly set it to 0 at startup, it might have any value.
If you want to check if the app was opened the first time after installing, use NSUserDefaults
e.g. (in didFinishWithOptions):
int startCount=[[NSUserDefaults standardUserDefaults] intForKey:#"startCount"];
if (startCount==0]){
//Is the first start, show your agreement
//Then increase startCount so that this will not be called at next start
[[NSUserDefaults standardUserDefaults] setInteger:startCount++ forKey:#"startCount"];
}
You could also store your version number in the NSUserDefaults. This way, you could check if the user first starts a new version.