Change the page after an action is done - objective-c

I have 2 pages with xib files. One is a login page and the other is a welcome page.
Here is the login function:
-(IBAction)login{
NSLog(#"login begin");
NSString *loginResponse = [self tryLogin];
NSLog(#"%#", loginResponse);
loginError.text = loginResponse;
NSUserDefaults *session = [NSUserDefaults standardUserDefaults];
[session setInteger:1 forKey:#"islogged"];
}
After the user is logged in successfully I need to redirect them to another xib file which is called Notifications. Now how exactly should I do this?
Also for some reason when I put an if statement inside the function, it doesnt go into the statements.
-(IBAction)login{
NSLog(#"login begin");
NSString *loginResponse = [self tryLogin];
NSLog(#"%#", loginResponse);
if(responseInt == #"2"){
NSLog(#"login error 2");
UIAlertView *alertURL = [[UIAlertView alloc] initWithTitle:#"Error!"
message:#"Username or password is wrong!"
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alertURL show];
[alertURL release];
///////////////////////////////////////////////////
}else if(responseInt == #"0"){
NSUserDefaults *session = [NSUserDefaults standardUserDefaults];
[session setInteger:1 forKey:#"islogged"];
}
}
As you can see I try to nslog something as soon as one of the conditions are met but it does not go into any of the statements (the loginResponse is sent back as 2).

How to change views
If you app is navigation-based then you can add new fullscreen views using method [self.navigationController pushViewController:controller animated:YES];.
Everywhere you can add new fullscreen view using next method : [self presentModalViewController:controller animated:YES];.
Issue with 'if-statement'.
When you want to compare to objects you should use one of following methods:
compare:, this method return one of following values: NSOrderedSame, NSOrderedDescending, NSOrderedAscending. For example, if ([responseInt compare:#"2"] == NSOrderedSame) {// equal}
'isEqual:', for example, if ([responseInt isEqual:#"2"]) {// equal}
or some specific comparators for concrete class
Don't forget that when you are comparing using == or > and etc you are comparing addresses of objects in memory.

Have you tried doing isEqualToString: instead of the equal sign? That is a more reliable string comparator. Also it seems strange that your login method is returning a string and not an integer. Is there a reason for that?

Related

How to Check the string is same or changed in Objective C

I check the frame of any subclass, if it is change or not with the following code.
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if(imageFrameSize == CGRectZero) {
imageFrameSize = self.recycleBin.frame;
NSLog(#"Frame: %#", NSStringFromCGRect(imageFrameSize));
}
}
Now I want to check the string is same or changed. Basically I am storing history in history.plist. And I run the function in below delegate to save document url in history.plist file.
- (void)webViewDidFinishLoad:(UIWebView *)webView {
//when push to reload is done it will disappear pulltorefresh
[(PullToRefreshView *)[self.view viewWithTag:998] finishedLoading];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[self actualizeButtons];
urlPage =[webView stringByEvaluatingJavaScriptFromString:#"document.title"]; //[[[webView request] URL]absoluteString];
[self addHistoryFunction];
NSLog(#"WebView Finish Load %#",[[[webView request] URL]absoluteString] );
}
This function works good. But the problem is that webViewDidiFinishLoad run almost two times for google and three or many times for other websites. So addHistoryFuncation save the history two or more times with same page url.
I want to check the urlPage string before adding to history, if it is updated new string then run the addhistory function, if it is same then skip addhistory function. Just like above CGRectZero code.
Thats my idea to save history in history.plist.
If there is a better then mine please help me or solve my issue.
Thanks in advance.
- (void)webViewDidFinishLoad:(UIWebView *)webView called when ever awebview finish loading an object with in the web page so the best approch to prevent this method to be called more than once to add this line :
if ([webView isLoading]){return;)
this line will make sure that your webview will do the commands when its only finishedl loading.
here is your function after edit try it .
- (void)webViewDidFinishLoad:(UIWebView *)webView {
if ([webView isLoading]){return;)
//when push to reload is done it will disappear pulltorefresh
[(PullToRefreshView *)[self.view viewWithTag:998] finishedLoading];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
[self actualizeButtons];
urlPage =[webView stringByEvaluatingJavaScriptFromString:#"document.title"]; //[[[webView request] URL]absoluteString];
[self addHistoryFunction];
NSLog(#"WebView Finish Load %#",[[[webView request] URL]absoluteString] );
}
if you want to compare to string this is how
BOOL isTheSameStrings=[mystring isEqualToString:string2];
if (isTheSameStrings){
NSLog(#"the are the same);
}else{
NSLog(#"the are NOT the same);
}
or you want to check if the string found in an array
BOOL myArrayDoesContainMyString=[myArray containsObject:myString];
if (myArrayDoesContainMyString){
NSLog(#"myArray contain myString);
}else{
NSLog(#"myArray does not contain myString);
}

NSInvalidArgumentException, nil argument

I've looked over the site for a while and I saw a few things but nothing worked for me. Extreme newbie here though.
I'm trying to make a 2 component picker, populated from arrays, populated from a dictionary, populated from a plist. The components populate, and I have a button that spins one component. The second button is meant to check answers (the first component has states which they try to match with capitals in the second component), but this is where it always crashes.
The error I get is as follows:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[NSPlaceholderString initWithFormat:locale:arguments:]: nil argument'
* First throw call stack:
(0x14b3022 0xeb3cd6 0x145ba48 0x145b9b9 0x916169 0x916ab4 0x3036 0x14b4e99 0x1914e 0x190e6 0xbfade 0xbffa7 0xbf266 0x3e3c0 0x3e5e6 0x24dc4 0x18634 0x139def5 0x1487195 0x13ebff2 0x13ea8da 0x13e9d84 0x13e9c9b 0x139c7d8 0x139c88a 0x16626 0x27ad 0x2715)
terminate called throwing an exception(lldb)
I'm not sure where I'm going wrong. I've done this with hard coded arrays, and it works fine. The code for the button is like so (please ignore the switch code, I haven't quite figured out how to make that work yet, I want the screen to turn green for correct answers and red for incorrect, but I'm more concerned with the app crashing!):
-(IBAction)checkAnswer;
{
NSInteger StateRow = [pickerCapital selectedRowInComponent:karrayStateComponent];
NSInteger CapitalRow =[pickerCapital selectedRowInComponent:karrayCapitalComponent];
NSString *state = [arrayState objectAtIndex:StateRow];
NSString *capital = [arrayCapital objectAtIndex:CapitalRow];
NSLog (#"%i",[pickerCapital selectedRowInComponent:karrayCapitalComponent]);
NSLog(#"%i", [pickerCapital selectedRowInComponent:karrayStateComponent]);
NSString *Title = [[NSString alloc]initWithFormat:#"You have selected %# as the capital of %#.", capital, state];
NSString *Message =[[NSString alloc]initWithFormat:lblMsg];
UIAlertView *alert =[[UIAlertView alloc]initWithTitle:Title message:Message delegate:#"" cancelButtonTitle:#"OK" otherButtonTitles:nil];
[alert show];
if (StateRow == CapitalRow) {
lblMsg = #"You are correct!";
UIColor *myColor;
switch ([not sure what to use here]) {
case 0:
myColor = [UIColor greenColor];
break;
default:
break;
}
}
else {
lblMsg = #"Incorrect";
UIColor *myColor;
switch ([not sure what to use here]) {
case 0:
myColor = [UIColor redColor];
break;
default:
break;
}
}
}
If anyone can offer any sort of help on this, I would appreciate it greatly! Thank you!
Two things to check:
Where is lblMsg declared or assigned a value?
Are you sure capital and state are not nil from the calls to [arrayCapital objectAtIndex]?
Specifically: the NSString documentation states "Important: Raises an NSInvalidArgumentException if format is nil." for initWithFormat.

Sharekit not showing Twitter, Email, TextMessage Options

I'm using ShareKit 2 on an iOS app for version 5 or later. I've got the app configured to use Facebook correctly, and when the action sheet is activated, that's the only option that appears. I want to use the built-in Twitter sharing system, but the option doesn't come up in the action sheet. Here's my code:
SURL *url = [NSURL URLWithString:launchUrl];
SHKItem *item = [SHKItem URL:url title:#"Title" contentType:SHKShareTypeURL];
SHKActionSheet *actionSheet = [SHKActionSheet actionSheetForItem:item];
[SHK setRootViewController:self.view.window.rootViewController];
[actionSheet showInView:self.view.window.rootViewController.view];
As per the instructions. I've got a custom DefaultSHKConfigurator class, in which I suppose these are the relevant methods:
- (NSString*)sharersPlistName {
return #"MySHKSharers.plist";
}
- (NSArray*)defaultFavoriteURLSharers {
return [NSArray arrayWithObjects:#"SHKTwitter",#"SHKFacebook", #"SHKMail", #"SHKTextMessage", nil];
}
Again, only Facebook comes up as an option. For completeness, here's my "MySHKSharers.plist" file (the relevant part):
<dict>
<key>actions</key>
<array>
<string>SHKMail</string>
<string>SHKTextMessage</string>
</array>
<key>services</key>
<array>
<string>SHKTwitter</string>
<string>SHKFacebook</string>
</array>
</dict>
So any ideas why I can't get Twitter, Mail and TextMessage to show up in the action sheet?
If you want to configure the sharers shown in the actionsheet I found this post helpful:https://gist.github.com/1181552
I ran into trouble getting actions (email, text message, etc) to show in the default actionsheet. My solution was to create a custom actionsheet and then to call Sharekit like this:
- (IBAction) getSharingSheet:(id)sender{
UIActionSheet *sheet = [[UIActionSheet alloc] initWithTitle:#"Share"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Facebook", #"Twitter", #"Save to Photo Library", #"Email", nil];
[sheet showInView:self.view];
}
and then my didDismissWithButtonIndex:
- (void)actionSheet:(UIActionSheet *)actionSheet didDismissWithButtonIndex:(NSInteger)buttonIndex
{
switch(buttonIndex)
{
case 0:
SHKItem *item = //some item
[SHKFacebook shareItem:item];
break;
case 1:
SHKItem *item = //some item
[SHKTwitter shareItem:item];
break;
case 2:
SHKItem *item = //some item
[SHKPhotoAlbum shareItem:item];
break;
case 3:
SHKItem *item = //some item
[SHKMail shareItem:item];
break;
default:
break;
}
}
Hope this helps!
I had this same issue and just solved it. This may or may not be the same issue that you are facing.
After poking around a bit to see how the action sheet was being built, I found that in SHK.m it was pulling stored favourites out of NSUserDefaults.
+ (NSArray *)favoriteSharersForType:(SHKShareType)type
{
NSArray *favoriteSharers = [[NSUserDefaults standardUserDefaults] objectForKey:[NSString stringWithFormat:#"%#%i", SHKCONFIG(favsPrefixKey), type]];
....
}
These stored results are preferred even over what you've defined as the "default" favourite sharing services. Clearing out these favourites solves the issue.

NSTable loses focus after present:error

I have an NSTableView that lists tags that are stored using Core Data. The default value for a tag is 'untitled' and I need each tag to be unique, so I have a validation routine that traps empty and non-unique values and that works fine. I don't want the user to be able to store the 'untitled' value for a tag, so I am observing the NSControlTextDidEndEditingNotification, which calls the following code:
- (void)textEndedEditing:(NSNotification *)note {
NSString *enteredName = [[[note userInfo] valueForKey:#"NSFieldEditor"] string];
if ([enteredName isEqualToString:defaultTagName]) {
NSString *dString = [NSString stringWithFormat:#"Rejected - Name cannot be default value of '%#'", defaultTagName];
NSString *errDescription = NSLocalizedStringFromTable( dString, #"Tag", #"validation: default name error");
NSString *errRecoverySuggestion = NSLocalizedStringFromTable(#"Make sure you enter a unique value for the new tag.", #"Tag", #"validation: default name error suggestion");
int errCode = TAG_NAME_DEFAULT_VALUE_ERROR_CODE;
NSArray *objArray = [NSArray arrayWithObjects:errDescription, errRecoverySuggestion, nil];
NSArray *keyArray = [NSArray arrayWithObjects:NSLocalizedDescriptionKey, NSLocalizedRecoverySuggestionErrorKey, nil];
NSDictionary *eDict = [NSDictionary dictionaryWithObjects:objArray forKeys:keyArray];
NSError *error = [[NSError alloc] initWithDomain:TAG_ERROR_DOMAIN code:errCode userInfo:eDict];
NSBeep();
[preferencesWindowsController presentError:error];
unsigned long index = [self rowWithDefaultTag];
[self selectRowIndexes:[NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO];
// [self editColumn:0 row:index withEvent:nil select:YES];
}
}
- (unsigned long)rowWithDefaultTag {
__block unsigned long returnInt;
[managedTags enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
if ([[obj valueForKey:#"name"] isEqualToString:defaultTagName]) {
returnInt = idx;
*stop = YES;
}
}];
return returnInt;
}
With the 'editColumn' line commented out, the code works, so if the user accepts the default tag name without editing it, the error is built, displayed and the process finishes by leaving the appropriate row in the table highlighted.
However, I would like to take it that step further and place the user in edit mode. When I uncomment the 'editColumn' line, the behaviour is not at all what I expected - the tableView loses its blue focus box and the row that respresents the new tag is blank. If I click on the tableView, the row becomes visible. I've spent a lot of time on this and have got nowhere, so some help with this would be very much appreciated.
(Note: I tried using textDidEndEditing, which also didn't behave as I expected, but that is a separate issue!)
Answering my own question. Doh!
I already had a method which I used to put the user in edit mode when they clicked the button to add a new tag:
- (void)objectAdded:(NSNotification *)note {
if ([[note object] isEqual:self]) {
[self editColumn:0 row:[self rowWithDefaultTag] withEvent:nil select:YES];
}
}
Creating a notification to call this solves the problem and places the user in edit mode correctly. The important thing is not to try to do this on the existing runloop; so sending the notification as follows postpones delivery until a later runloop:
// OBJECTADDED is a previously defined constant.
NSNotification * note = [NSNotification notificationWithName:OBJECTADDED object:self];
[[NSNotificationQueue defaultQueue] enqueueNotification: note postingStyle: NSPostWhenIdle];
Problem solved. I wasted a lot of time trying to solve this - a classic example of getting too involved in the code and not looking at what I'm trying to do.
I've forgotten where I first saw this posted - whoever you are, thank you!

How to: Implement server forcing disconnect of client in GKSession

I am implementing the GKSession server/client mode operation in my application on iOS. I found one question related to mine but with no answer. I am trying to allow the server to disconnect any client that is currently connected to the session. I thought that calling disconnectPeerFromAllPeers:(NSString *)peerID would allow me to do this, but is seems to have no effect.
Any suggestions?
Thanks
Actually answered via question update ion 01/03/2012, but moved this text to the answer section
I wanted to share how I implemented a disconnect request sent from server to client. All of the code presented below is contained within a class I created to completely encapsulate all the interfacing with a GKSession instance (also implements the GKSessionDelegate methods).
First I have the server send a disconnect request to the client that shall be disconneted. Any data that is sent from client to server or vice versa is contained within a dictionary that also has a key-value pair to specify the type of data that is sent (in this case the data is a disconnect request).
- (void)sendDisconnectRequestToPeer:(NSString *)peer {
//create the data dictionary that includes the disconnect value for the data type key
NSMutableDictionary *dictPrvw = [[NSMutableDictionary alloc] initWithObjectsAndKeys:[NSNumber numberWithInt:GKSessionDataTypeDisconnect], kDictKeyDataType, nil];
NSData *dataChunk = [[NSKeyedArchiver archivedDataWithRootObject:dictPrvw] retain];
//[self printDict:dictPrvw];
NSArray *peers = [[NSArray alloc] initWithObjects:peer, nil];
[self sendData:dataChunk toPeers:peers];
[dataChunk release];
[dictPrvw release];
}
The client receives the data, casts it into a dictionary and examines the key-value pair that specifies what type of data was sent. If it's a disconnect request, my "GKSessionManager" class then implements a disconnect.
- (void)recievedAllDataChunksInSession:(GKSession *)session fromPeer:(NSString *)peer context:(void *)context {
//The chunk was packaged by the other user using an NSKeyedArchiver,
//so unpackage it here with our NSKeyedUnArchiver
NSMutableDictionary *responseDictionary = (NSMutableDictionary *)[[NSKeyedUnarchiver unarchiveObjectWithData:self.recievedPackets] mutableCopyWithZone:NULL];
//[self printDict:responseDictionary];
//get the enumerator value for the data type
NSNumber *gkSessDataType = [responseDictionary objectForKey:kDictKeyDataType];
int intDataType = [gkSessDataType intValue];
UIAlertView *anAlrtVw;
switch (intDataType) {
case GKSessionDataTypeMessageData:
[self sessionManager:self recievedDataDictionary:responseDictionary];
break;
case GKSessionDataTypePreviewRequest:
if (sess.sessionMode == GKSessionModeServer) {
[self sendMsgPreviewToPeer:peer];
}
break;
case GKSessionDataTypePreviewSend:
//[self sessionManager:self recievedDataDictionary:responseDictionary];
[self sessionManager:self connectedWithPrelimData:responseDictionary];
break;
case GKSessionDataTypeDisconnect:
anAlrtVw = [[UIAlertView alloc]
initWithTitle:nil
message:#"The server has disconnect you."
delegate:self cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[anAlrtVw show];
[anAlrtVw release];
[self closeSession];
[self disconnectedByServer];
default:
break;
}
}
- (void)closeSession {
[sess disconnectFromAllPeers];
[sess setDataReceiveHandler: nil withContext: NULL];
sess.available = NO;
sess.delegate = nil;
self.sess = nil;
self.serverId = nil;
self.rqstPeerId = nil;
serverIsConnecting = NO;
}
The user never sees the disconnect request and so has no control over whether or not to deny it.
Hope this information helps. I realize what I wrote my not be entirely clear and I have left a lot of other code out (on purpose) so feel free to comment or ask questions.