Get variable from void function in Objective C - xcode

I'm VERY new to Objective C and iOS development (like 5 hours new :-). I've got some code that calls an API to authenticate a user and returns a simple OK or FAIL. I can get the result to write to the console but what I need to do is get that result as part of my IBAction.
Here's the IBAction code:
- (IBAction) authenticateUser
{
[txtEmail resignFirstResponder];
[txtPassword resignFirstResponder];
[self performAuthentication];
if (authResult == #"OK")
What I need is for authResult to be the JSON result (OK or FAIL). Here is the code that gets the result:
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[connection release];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
NSLog(#"%#", responseString);
[responseData release];
NSMutableDictionary *jsonResult = [responseString JSONValue];
if (jsonResult != nil)
{
NSString *jsonResponse = [jsonResult objectForKey:#"Result"];
NSLog(#"%#", jsonResponse);
}
}
Thank you so much for any help and sorry if I'm missing something obvious!

I'm a little confused as to what's going on here... it looks like your -performAuthentication method must start an asynchronous network request via NSURLConnection, and your connection's delegate's -connectionDidFinishLoading: gets to determine the result of the request. So good so far? But your -authenticateUser method expects authResult to be determined as soon as -performAuthentication returns. If the network request is asynchronous, that's not going to happen. If I'm following you, I think you need to do the following:
Fix up -connectionDidFinishLoading: so that it actually sets authResult based on the Result value in jsonResponse. I'm sure you'd get around to this at some point anyway.
Change -authenticateUser such that it doesn't expect to have an answer immediately. You've got to give the network request a chance to do its thing.
Add another method, possibly called -authenticationDidFinish or something along those lines. Everything currently in -authenticateUser from the 'if (authResult...' to the end goes in this new method.
Call the new method from -connectionDidFinishLoading:.
Fix your string comparison. If you want to compare two strings in Cocoa, you say (for example):
if ([authResult isEqualToString:#"OK") { }

Related

Mixing tokens and strings in NSTokenField

I want to have an NSTokenField that contains both plain text and tokens. That's the same problem as in this question, but the answers there haven't solved it for me. Maybe I'm missing something, or maybe Apple changed something in the 5 years since those answers were posted.
Specifically, let's say I want to type "hello%tok%" and have it turn into this:
In order to try to remove chances for confusion, I always use a custom represented object, of one of the following classes, rather than a plain string...
#interface Token : NSObject
#end
#implementation Token
#end
#interface WrappedString : NSObject
#property (retain) NSString* text;
#end
#implementation WrappedString
#end
Here are my delegate methods:
- (NSString *)tokenField:(NSTokenField *)tokenField
displayStringForRepresentedObject:(id)representedObject
{
NSString * displayString = nil;
if ([representedObject isKindOfClass: [WrappedString class]])
{
displayString = ((WrappedString*)representedObject).text;
}
else
{
displayString = #"TOKEN";
}
return displayString;
}
- (NSTokenStyle)tokenField:(NSTokenField *)tokenField
styleForRepresentedObject:(id)representedObject
{
NSTokenStyle theStyle = NSPlainTextTokenStyle;
if ([representedObject isKindOfClass: [Token class]])
{
theStyle = NSRoundedTokenStyle;
}
return theStyle;
}
- (NSString *)tokenField:(NSTokenField *)tokenField
editingStringForRepresentedObject:(id)representedObject
{
NSString * editingString = representedObject;
if ([representedObject isKindOfClass: [Token class]])
{
editingString = nil;
}
else
{
editingString = ((WrappedString*)representedObject).text;
}
return editingString;
}
- (id)tokenField:(NSTokenField *)tokenField
representedObjectForEditingString:(NSString *)editingString
{
id repOb = nil;
if ([editingString isEqualToString:#"tok"])
{
repOb = [[[Token alloc] init] autorelease];
}
else
{
WrappedString* wrapped = [[[WrappedString alloc]
init] autorelease];
wrapped.text = editingString;
repOb = wrapped;
}
return repOb;
}
As I'm typing the "hello", none of the delegate methods is called, which seems reasonable. When I type the first "%", there are 3 delegate calls:
tokenField:representedObjectForEditingString: gets the string "hello" and turns it into a WrappedString representation.
tokenField:styleForRepresentedObject: gets that WrappedString and returns NSPlainTextTokenStyle.
tokenField:editingStringForRepresentedObject: gets the WrappedString and returns "hello".
The first two calls seem reasonable. I'm not sure about number 3, because the token should be editable but it's not being edited yet. I would have thought that tokenField:displayStringForRepresentedObject: would get called, but it doesn't.
When I type "tok", no delegate methods are called. When I type the second "%", tokenField:representedObjectForEditingString: receives the string "hellotok", where I would have expected to see just "tok". So I never get a chance to create the rounded token.
If I type the text in the other order, "%tok%hello", then I do get the expected result, a round token followed by plain "hello".
By the way, the Token Field Programming Guide says
Note that there can be only one token per token field that is configured for the plain-text token style.
which seems to imply that it's not possible to freely mix plain text and tokens.
I asked myself whether I had seen mixed text and tokens anywhere in standard apps, and I had. In the Language & Text panel of System Preferences, under the Formats tab, clicking one of the "Customize..." buttons brings up a dialog containing token fields. Here's part of one.
Here, you don't create tokens by typing a tokenizing character, you drag and drop prototype tokens.
To make one of the prototype tokens, make another NSTokenField and set it to have no background or border and be selectable but not editable. When your window has loaded, you can initialize the prototype field using the objectValue property, e.g.,
self.protoToken.objectValue = #[[[[Token alloc] init] autorelease]];
You need to set up a delegate for each prototype token field as well as your editable token field. In order to be able to drag and drop tokens, your delegate must implement tokenField:writeRepresentedObjects:toPasteboard: and tokenField:readFromPasteboard:.

NSTextField with NSFormatter results in broken continuous binding

I have a textfield which has to be unique so I added my custom NSFormatter (see below)
The formatter works, as you can see on the screenshot, but the continuous binding, which I am using is broken, so for example the bound text does no longer get updated in real-time.
I found a possible cause here, but I don't know how to work around this problem and re-enable the continuous binding:
...
12. If the view has an NSFormatter attached to it, the value is
formatted by the NSFormatter instance. Proceed to Step 17.
...
17. The updated value is displayed in the user interface.
So it looks like it's intentionally skipping the steps we want. This
is very annoying. I tried NSValueTransformer, but adding that to an
editable NSTextField makes it non-editable.
My formatter
- (BOOL)getObjectValue:(out id *)obj forString:(NSString *)string errorDescription:(out NSString **)error {
if([string isNotEqualTo:#"todo-invalid-value"]){
*obj = string;
NSLog(#"YES");
return YES;
} else {
if(error){
*error = #"ERROR: not allowed";
}
return NO;
}
}
- (NSString *)stringForObjectValue:(id)obj {
return (NSString *)obj;
}
Working validation
Please note that the title of the list item should be updated with the text, that I entered in the textfield.
I ran into the same problem over the weekend, and eventually discovered a post from 2008 by Yann Disser on the cocoa-dev mailing list which shed some light on my problem.
I had an existing NSFormatter that was working fine and when I broke down the components, so I spent a little more time on it this morning and located Yann's post.
The key is that you need to return a different object than the one that is passed in. It's subtle, but the docs say: If conversion is successful, upon return contains the object created from string.
The problem I was having stemmed from the fact that the NSString that was coming in was actually an NSMutableString and was getting modified later.
Here's the code modified to return [NSString stringWithString: string], which should fix your problem:
- (BOOL)getObjectValue:(out id *)obj forString:(NSString *)string errorDescription:(out NSString **)error {
if([string isNotEqualTo:#"todo-invalid-value"]){
*obj = [NSString stringWithString: string];
NSLog(#"YES");
return YES;
} else {
if(error){
*error = #"ERROR: not allowed";
}
return NO;
}
}

How to automatically find nearby locations using my location?

I am VERY new to xcode but what i am trying to accomplish is when you open the app it shows a map and my location and the current food places that are around me. I dont have my own database for the locations i am trying to use google for this function. what i was able to do is find a tutorial but it has a search bar and when i search for something it shows me but i want it to automatically show me and not have the function of searching.
Is this possible? any help/tutorial is greatly appreciated. Thank you
You can try to use Place search api.
http://code.google.com/apis/maps/documentation/places/#PlaceSearches
They support a "restaurant" and "food" type.
http://code.google.com/apis/maps/documentation/places/supported_types.html
So you can remove the search bar and instead send a request to google places api with current location and types="restaurant" or types="restaurant|food".
You can get the results as JSON data wich you can easily use in your app.
Next step would be to make annotations and add them to a map.
__
Here are details on the first parts.
Once you get this working you can move on to getting an API-key for google places, get current position and then start adding json results to a map using map annotations. :)
The async url connection is the biggest part here. So once you get this working, you are well on your way to finding nearby locations.
To setup the JSON part..
Download a json library.. https://github.com/johnezang/JSONKit
Add JSONKit.h and JSONKit.m to your project. (add files.. or drag them over)
Add #import "JSONKit.h" (in your .m file)
Look in the final method below to see how to setup the variables and get data from json.
For the url connection part...
Based on: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/URLLoadingSystem/Tasks/UsingNSURLConnection.html
PS: You would make a change later to use google places json api-url, api-key, current location and the "restaurant" type (to get the needed response in json from google).
Create a request:
- (void)viewDidLoad
{
// Create the request.
NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:#"http://www.google.com/calendar/feeds/developer-calendar#google.com/public/full?alt=json"]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:60.0];
// create the connection with the request
// and start loading the data
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
// Create the NSMutableData to hold the received data.
receivedData = [[NSMutableData data] retain];
} else {
// Inform the user that the connection failed.
}
}
Then you need to implement the delegate methods.. (copy this into .m file)
This one is invoked when you get response (not the actual data, hence they reset it).
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
// This method is called when the server has determined that it
// has enough information to create the NSURLResponse.
// It can be called multiple times, for example in the case of a
// redirect, so each time we reset the data.
[receivedData setLength:0];
}
This one is invoked when data is received - can happen several times, so they append data each time.
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// Append the new data to receivedData.
[receivedData appendData:data];
}
Sometimes the connection would fail, then this delegate method is invoked - and you can present a message to the user (apple says to always inform users of what is happening)..
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
// release the connection, and the data object
[connection release];
[receivedData release];
// inform the user
NSLog(#"Connection failed! Error - %# %#",
[error localizedDescription],
[[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
Finally, this method is invoked when the connection finished successfully. Now you have your complete data, and you save it to a variable. Here we also place the data into jsonDict.
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// do something with the data ...
// Your data is now stored in "receivedData",
// set up this mutable variable in the header file, then synthesize.
// in the .h file, inside the #interface block.:
//
// NSMutableData *receivedData;
// NSDictionary *jsonDict;
// }
//
// #protocol (nonatomic, retain) NSMutableData *receivedData;
// #protocol (nonatomic, retain) NSDictionary *jsonDict;
// And in the .m file, under the #implementation line.
// #synthesize receivedData, jsonDict;
// Log to test your connection
NSLog(#"Succeeded! Received %d bytes of data",[receivedData length]);
// Place the received data into a json dictionary
jsonDict = [receivedData objectFromJSONData];
// Get sections from your data
NSString *feed = [jsonDict objectForKey:#"feed"]; // asumes there is only one title in your json data, otherwise you would use an array (with dictionary items) ..look in your feed to find what to use.
// Log your data
NSLog(#"My feed: %#", feed);
// release the connection, and the data object
[connection release];
[receivedData release];
}
Try to get this going, then we can get back to using places search and adding results to a map.
Refer the following link
http://www.raywenderlich.com/13160/using-the-google-places-api-with-mapkit
The link shows the from the scratch development of map API project

How to objects from a fetchedResultsController to a Plist?

Can someone help me. I have a coredata application but I need to save the objects from a fetchedResultsController into an NSDictionary to be used for sending UILocalNotifications.
Should I use an NSMutableSet, or a NSDictionary, or an array. I'm not used to using collections and I can't figure out the best way to do that.
Could you please give me clues on how to do that please ?
Thanks,
Mike
If I'm reading your question correctly, you're asking how you should pack objects into the userInfo dictionary of a UILocalNotification. Really, it's however works best for you; userInfo dictionaries are created by you and only consumed by you.
I'm not sure why you would be using an NSFetchedResultsController - that class is for managing the marshaling of managed objects between UI classes (like UITableView) efficiently, whereas here it sounds like you would be better off just getting an NSArray of results from your managedObjectContext and the corresponding request, like this:
NSError *error = nil;
NSArray *fetchedObjects = [myManagedObjectContext executeFetchRequest: myRequest error: &error];
if (array == nil)
{
// Deal with error...
}
where you have a pre-existing managed object context and request. You don't need to use an NSFetchedResultsController here.
From there, the simplest suggestion would be to build your userInfo dictionary like this:
NSDictionary* myUserInfo = [NSDictionary dictionaryWithObject: fetchedObjects forKey: #"AnythingYouWant"];
UILocalNotification *localNotif = [[UILocalNotification alloc] init];
// ... do other setup tasks ...
localNotif.userInfo = myUserInfo;
[[UIApplication sharedApplication] scheduleLocalNotification:localNotif];
[localNotif release];
Then when it comes time to receive that notification, you can read that dictionary like this:
- (void)application:(UIApplication *)app didReceiveLocalNotification:(UILocalNotification *)notif
{
NSArray* myFetchedObjects = [notif.userInfo objectForKey: #"AnythingYouWant"];
for(id object in myFetchedObjects)
{
// ... do other stuff ...
}
}
Now, hopefully that's clarified how the userInfo dictionary works. I don't know the details of your app, so it's hard to say, but I'm suspicious that actually passing fetched objects is NOT what you want to do here, mainly because I'm not sure that you have any guarantee that the receiving delegate method will be working with the same object context as the sending method. I would suggest perhaps putting the entity name and predicate in the dictionary and then refetching the objects at receive time with whatever the current MOC is at that moment.
Good luck!

Simple NSSpeechRecognizer code, not working!

I noticed NSSpeechRecognizer in ADC library and I found it to be very interesting, so to play with it I prepared a simple application which will just listen the command and if recognized it displays it in log.
The code used is:
- (id)init {
if (self = [super init]) {
// Insert code here to initialize your application
NSArray *cmds = [NSArray arrayWithObjects:#"A",#"B", #"C",#"alpha",#"beta",#"vodka",#"wine",nil];
recog = [[NSSpeechRecognizer alloc] init]; // recog is an ivar
[recog setCommands:cmds];
[recog setDelegate:self];
}
return self;
}
- (IBAction)listen:(id)sender
{ NSLog(#"listen:");
if ([sender state] == NSOnState) { // listen
[recog startListening];
} else {
[recog stopListening];
}
}
- (void)speechRecognizer:(NSSpeechRecognizer *)sender didRecognizeCommand:(id)aCmd {
NSLog(#"speechRecognizer: %#",(NSString *)aCmd);
}
I tried it many times for the commands registered but I was unable to get none of the messages in log, in delegate :(
There was always some noise in the background.. could this be the reason for it or I have done something wrong in the code??
Can anyone suggest me some solution for it??
Thanks,
Miraaj
Code looks fine so far.
The NSSpeechRecognizer is a bit tricky sometimes and refuses to listen to the right words. Did you try different words?
Did you try setting startListening as default?
I wrote a little tutorial some time ago. Its in german language but maybe it will help you anyway or you use some translation tool.
http://cocoa-coding.de/spracherkennung/nsspeechrecognizer1.html

Resources