How to handle the exceptions - objective-c

NSString *stringURL=[[NSString alloc] init];
stringURL=[stringURL stringByAppendingFormat:kSearchBarURL,text.text];
NSString *url = [NSString stringWithString:stringURL];
NSData *data1 = [NSData dataWithContentsOfURL:[NSURL URLWithString:url]];
NSString *responseids = [[NSString alloc] initWithData:data1 encoding:nil];
responseids = [responseids stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:#"\n\r\t"]];
SBJsonParser *parser=[SBJsonParser new];
NSData *data = [parser objectWithString:responseids error:nil];
NSMutableDictionary *searchURL = (NSMutableDictionary*)data;
I coded this i did not handle the exception for my code.
doing json and calling the service url and loading the data.
the application get crashes when my service is too low or no service found.
How to handle the exception for my code here..
Do I use #try #catch.
or
NSURLConnection for error handling.
Please help me out .
Thanks in advance.

Whenever an API makes use of NSError, you should use this rather than wrapping things up in a try…catch block as NSError is designed exactly for this. I usually reserve #try for things where I am really not able to anticipate what might go wrong. If NSError is in the mix, then you know that there is a potential for a problem that you should be handling gracefully.
More generally, your code has some strange stuff in it. You alloc init an empty NSString and then create a new string by appending a format. Not sure why you don't just use [NSString stringWithFormat]. Once you have the string, you can create the URL without the NSString *url bit.
You're also using a synchronous call to what I assume is a remote server. This has the potential to bog down your application if/when the server is not available. You're also not telling NSString what kind of encoding you expect your string to be in when it reads it from NSData. A better method depending on your server side would be to use NSString's stringWithContentsOfURL:usedEncoding:error: method. I would recommend that you use the various NSURLConnection callbacks. Have a look at the URL Loading System Programming Guide on Using NSURLConnection The NSURLConnection delegate methods are the ones you want to implement to provide this asynchronous processing.
For your trimming, you might be interested in the +whitespaceAndNewlineCharacterSet method on NSCharacterSet.
Finally, for your JSON parsing, you might be interested in the category that the SBJSON code adds to NSString, particularly -JSONValue which will give you the dictionary or array representation (as appropriate) of the NSString when parsed as JSON by SBJSON.
HTH

Related

data parameter is nil when i trying to fetch the data from web service using json

- (NSDictionary*)PostWebService:(NSString*)completeURL param:(NSString*)value
{
#try
{
NSString *urlStr =[completeURL stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url = [NSURL URLWithString:urlStr];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:#"POST"];
//NSString *urlPart=#"req=value";
//NSString *urlPart;
NSString *urlPart=[NSString stringWithFormat:#"req=%#", value];
NSLog(#"String %#",urlPart);
NSData *requestBody = [urlPart dataUsingEncoding:NSUTF8StringEncoding];
//NSLog(#"String %#",requestBody);
[request setHTTPBody:requestBody];
NSURLResponse *response = NULL;
NSError *requestError = NULL;
NSData *responseData = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&requestError];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding] ;
NSLog(#"String %#",responseString);
NSError* error;
NSDictionary* json = [NSJSONSerialization JSONObjectWithData:responseData
options:kNilOptions
error:&error];
return json;
}
#catch(NSException *e)
{
NSLog(#"reason is%#",e.reason);
}
}
and i call this method here..
-(NSDictionary*)gotvall:(NSString*)req
{
#try
{
NSString *vurl=#"some url/";
// vurl=[vurl stringByAppendingString:#"req="];
// vurl=[vurl stringByAppendingString:req];
// NSLog(#"%#",vurl);
NSDictionary *json=[self PostWebService:vurl param:req];
NSLog(#"json is%#",json);
return json;
}
#catch(NSException *e)
{
NSLog(#"%#",e.reason);
}
}
After debugging this method I got result as data parameter is nil.
Can anyone tell that what I am doing wrong here.
I got the complete url and when I run that url on browser I got the perfect data but when I printing the value of json it returns null.
You reported that your error was:
Error Domain=NSURLErrorDomain Code=-1002 "unsupported URL" UserInfo=0x8d84960 {NSErrorFailingURLStringKey=%20http://www.hugosys.in/www.nett-torg.no/api/vehicl‌​e/, NSErrorFailingURLKey=%20http://www.hugosys.in/www.nett-torg.no/api/vehicle/, NSLocalizedDescription=unsupported URL, NSUnderlyingError=0x8d8bfe0 "unsupported URL"}
That %20 in your error message is a space at the start of your URL that your stringByAddingPercentEscapesUsingEncoding call converted to %20. If you remove that extra space, you should be in good shape.
A couple of other observations:
Just to warn you, your use of stringByAddingPercentEscapesUsingEncoding will correctly handle the presence of a space in the req value. But it will not properly handle the presence of certain other characters (notably & or +). If it's possible that those sorts characters might appear in the req value, you might want to remove the call to stringByAddingPercentEscapesUsingEncoding for the whole URL, and instead just use CFURLCreateStringByAddingPercentEscapes (which gives you a little more control over the percent escaping process) on just the req value. See the percentEscapeString method in this answer: Append data to a POST NSURLRequest.
In both your network request as well as your JSON parsing process, you are returning an NSError object. I might suggest that you log those values if they're ever non-nil, which will help you diagnose problems in the future.
I notice that you are using exception handling. That's not common in Objective-C. As the Programming in Objective-C guide says:
Dealing with Errors
Almost every app encounters errors. Some of these errors will be outside of your control, such as running out of disk space or losing network connectivity. Some of these errors will be recoverable, such as invalid user input. And, while all developers strive for perfection, the occasional programmer error may also occur.
If you’re coming from other platforms and languages, you may be used to working with exceptions for the majority of error handling. When you’re writing code with Objective-C, exceptions are used solely for programmer errors, like out-of-bounds array access or invalid method arguments. These are the problems that you should find and fix during testing before you ship your app.
All other errors are represented by instances of the NSError class. This chapter gives a brief introduction to using NSError objects, including how to work with framework methods that may fail and return errors. For further information, see Error Handling Programming Guide.
Bottom line, As I mentioned in the second point, you should be checking NSError return values yourself rather than relying on exceptions in Objective-C.

NSstream write encoding issues

Im trying to send a string using NSoutputstream , however i cant seem to get the encoding right , using dataWithContentsOfURL works
im using a nodejs TCP server with actionHero library.
it works using netcat and telnet.
- (IBAction)sendText:(id)sender {
NSString *response = [NSString stringWithFormat:#"%#", [_sendTextField.text stringByAddingPercentEscapesUsingEncoding: NSUTF8StringEncoding]];
NSLog(#"writing %#",response);
///////////////////////////// this line works/////////////////////////////////////////////////////
// NSData *data = [[NSData alloc] initWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:#"http://www.google.com"]]];
///////////////////////////// this line doesnt work/////////////////////////////////////////////////////
NSData *data = [[NSData alloc] initWithData:[response dataUsingEncoding:NSUTF8StringEncoding]];
//%u returns a non zero value
NSLog(#"%u",[outputStream write:[data bytes] maxLength:[data length]]);
}
i get a null streamError from handle stream Event method
Not knowing the content of response, I can't give you a specific answer as to why NSUTF8StringEncoding doesn't work with it. Generally speaking, however, if there is a byte sequence in your content that is incompatible with UTF-8, you're going to get nil when you call -dataUsingEncoding:.
There's a strategy that I learned from reading Mike Ash's blog (look under the section "Fallbacks"), and it's served me pretty well in situations such as yours.
To briefly sum it up, first try using NSUTF8StringEncoding. If that doesn't work, try using NSISOLatin1StringEncoding. And if that doesn't work, try using NSMacOSRomanStringEncoding. Mike's blog has the rationale for this.
Found the answer to my own question. turns out the problem is in actionHero's on data method where it looks for a /n which is not provided by the ios application. appended a \n and its fine now

Unknown error creating file in objective c

I'm creating a mac app that needs to create a file with the contents of another file, i'm creating it as follows:
NSString *p = #"/AfilethatEXISTS.plist";
NSString *user1 = #"~/Library/MyApp/myFile";
NSString *pT1 = [user1 stringByExpandingTildeInPath];
[[NSFileManager alloc] createFileAtPath:[NSURL URLWithString:pT1] contents:[NSData dataWithContentsOfFile:p] attributes:nil];
However returning no error, its not creating the file?
There are several things wrong with this code, but not enough context to tell you what is going wrong.
First, there should never be a file in / directly. That directory should be sacrosanct and many users will not be able to write to that directory without admin access.
Secondly, paths should be managed via the path manipulation APIs on NSString and NSURL.
Next, pT1 isn't really an URL and that is URLWithString: may be returning nil. Use fileURLWithPath: instead.
Finally, there isn't any error checking in that code and, thus, there is no way to tell how you might have discovered no error. What have you checked?
First off, you're creating the file manager instance incorrectly. To create a new instance, you need to both allocate and initialize it.
You're trying to pass an NSURL object, which won't be created correctly since the string you're using to create it with isn't a URL. But that doesn't matter anyway, because even if the NSURL was created, -createFileAtPath:contents:attributes: expects an NSString - just pass pT1 directly.
Better still, since you're basically just copying p to pT1, use the NSFileManager method for doing that. Not only is it conceptually a better fit, it also gives you a chance to examine a returned NSError object to see what (if anything) went wrong.
NSError *error;
NSFileManager *fm = [[[NSFileManager alloc] init] autorelease];
if (![fm copyFileAtPath:p toPath:pT1 error:&error]) {
// If copyFileAtPath:toPath:error: returned FALSE, an error occurred, and
// error will point to an NSError instance with more information
}

How to make QTMovie play file from URL with forced (MP3) type?

I'm using QTKit to progressively download and play an MP3 from a URL. According to this documentation, this is the code I should use to accomplish that:
NSURL *mp3URL = [NSURL URLWithString:#"http://foo.com/bar.mp3"];
NSError *error = nil;
QTMovie *sound = [[QTMovie alloc] initWithURL:mp3URL error:&error];
[sound play];
This works, and does exactly what I want — the MP3 URL is lazily downloaded and starts playing immediately. However, if the URL does not have the ".mp3" path extension, it fails:
NSURL *mp3URL = [NSURL URLWithString:#"http://foo.com/bar"];
NSError *error = nil;
QTMovie *sound = [[QTMovie alloc] initWithURL:mp3URL error:&error];
[sound play];
No error is given, no exception is raised; the duration of the sound is just set to zero, and nothing plays.
The only way I have found to work around this is to force a type by loading the data manually and using a QTDataReference:
NSURL *mp3URL = [NSURL URLWithString:#"http://foo.com/bar"];
NSData *mp3Data = [NSData dataWithContentsOfURL:mp3URL];
QTDataReference *dataReference =
[QTDataReference dataReferenceWithReferenceToData:mp3Data
name:#"bar.mp3"
MIMEType:nil];
NSError *error = nil;
QTMovie *sound = [[QTMovie alloc] initWithDataReference:dataReference error:&error];
[sound play];
However, this forces me to completely download ALL of the MP3 synchronously before I can start playing it, which is obviously undesirable. Is there any way around this?
Thanks.
Edit
Actually, it seems that the path extension has nothing to do with it; the Content-Type is simply not being set in the HTTP header. Even so, the latter code works and the former does not. Anyone know of a way to fix this, without having access to the server?
Edit 2
Anyone? I can't find information about this anywhere, and Google frustratingly now shows this page as the top result for most of my queries...
Two ideas. (The first one being a bit hacky):
To work around the missing content type, you could embed a small Cocoa webserver that supplements the missing header field and route your NSURL over that "proxy".
Some Cocoa http server implementations:
http://code.google.com/p/cocoahttpserver/
http://cocoawithlove.com/2009/07/simple-extensible-http-server-in-cocoa.html
http://culturedcode.com/cocoa/
The second one would be, to switch to a lower level framework (From QTKit to AudioToolbox).
You'd need more code, but there are some very good resources out there on how to stream mp3 using AudioToolbox.
e.g.:
http://cocoawithlove.com/2008/09/streaming-and-playing-live-mp3-stream.html
Personally I'd go with the second option. AudioToolbox isn't as straightforward as QTKit but it offers a clean solution to your problem. It's also available on both - iOS and Mac OS - so you will find plenty of information.
Update:
Did you try to use another initializer? e.g.
+ (id)movieWithAttributes:(NSDictionary *)attributes error:(NSError **)errorPtr
You can insert your URL for the key QTMovieURLAttribute and maybe you can compensate the missing content type by providing other attributes in that dictionary.
This open source project has a QTMovie category that contains methods to accomplish similar things:
http://vidnik.googlecode.com/svn-history/r63/trunk/Source/Categories/QTMovie+Async.m
If you thought weichsel's first solution was hacky, you're going to love this one:
The culprit is the Content-Type header, as you have determined. Had QTKit.framework used Objective-C internally, this would be a trivial matter of overriding -[NSHTTPURLResponse allHeaderFields] with a category of your choosing. However, QTKit.framework (for better or worse) uses Core Foundation (and Core Services) internally. These are both C-based frameworks and there is no elegant way of overriding functions in C.
That said, there is a method, just not a pretty one. Function interposition is even documented by Apple, but seems to be a bit behind the times, compared to the remainder of their documentation.
In essence, you want something along the following lines:
typedef struct interpose_s {
void *new_func;
void *orig_func;
} interpose_t;
CFStringRef myCFHTTPMessageCopyHeaderFieldValue (
CFHTTPMessageRef message,
CFStringRef headerField
);
static const interpose_t interposers[] __attribute__ ((section("__DATA, __interpose"))) = {
{ (void *)myCFHTTPMessageCopyHeaderFieldValue, (void *)CFHTTPMessageCopyHeaderFieldValue }
};
CFStringRef myCFHTTPMessageCopyHeaderFieldValue (
CFHTTPMessageRef message,
CFStringRef headerField
) {
if (CFStringCompare(headerField, CFSTR("Content-Type"), 0) == kCFCompareEqualTo) {
return CFSTR("audio/x-mpeg");
} else {
return CFHTTPMessageCopyHeaderFieldValue(message, headerField);
}
}
You might want to add logic specific to your application in terms of handling the Content-Type field lest your application break in weird and wonderful ways when every HTTP request is determined to be an audio file.
Try replacing http:// with icy://.
Just create an instance like this...
QTMovie *aPlayer = [QTMovie movieWithAttributes:[NSDictionary dictionaryWithObjectsAndKeys:
fileUrl, QTMovieURLAttribute,
[NSNumber numberWithBool:YES], QTMovieOpenForPlaybackAttribute,
/*[NSNumber numberWithBool:YES], QTMovieOpenAsyncOKAttribute,*/
nil] error:error];

parsing JSON using objective C?

I have spent 1 week studying objective C. Now I am quite confused at the dealing with data part.
My friend gave me a link
http://nrj.playsoft.fr/v3/getQuiz.php?udid=23423455&app=2
and ask me write a class to parse this JSON. I had no clue what parsing JSON means. but I have gone online and looked up. I could understand a basics of it and then I impletemented a punch of code to parse this JSON. Which is:
-
(void)parseURL
{
//create new SBJSON object
SBJSON *parser = [[SBJSON alloc] init];
NSError *error = nil;
//perform request from URL
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:#"http://nrj.playsoft.fr/v3/getQuiz.php?udid=23423455&app=2"]];
// Perform request and get JSON back as a NSData object
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:&error];
// Get JSON as a NSString from NSData response
NSString *json_string = [[NSString alloc] initWithData:response encoding:NSUTF8StringEncoding];
// parse the JSON response into an object
NSDictionary *results = [parser objectWithString:json_string error:&error];
// array just for the "answer" results
NSArray *quizes = [results objectForKey:#"quiz"];
NSDictionary *firstQuiz = [quizes objectAtIndex:0];
// finally, the name key
NSString *extract = [firstQuiz objectForKey:#"extract"];
NSLog(#"this is: %#", [extract valueForKey:#"extract"]);
}
This is at the implementation file, but in the header file I could not declare any variables, it will print out some errors. I tried to run this, there is no errors, but I am not sure this code is correct or not. And my friend asked me to write a class into an existing project. I don't know what needs to be modified and what not. I am so blur right now. Could anyone pro in this give me a hand. ?
My sincere thanks.
Thanks for reply. I have downloading and added the JSON framework ealier too. I am just not sure where to begin and where to end, meaning the step I should do when I add JSON framework into it. I could understand the syntax but I am not sure about the steps I should do. I am a newbie in this.
If you support iOS 5.0+, you should use built-in NSJSONSerialization.
It is faster than TouchJSON.
You could just use TouchJSON: http://code.google.com/p/touchcode/wiki/TouchJSON
Or you could use this one: http://code.google.com/p/json-framework/
I'm sure there are others. I use TouchJSON... it's fast and has a good API.
I recommend working through Ray Wenderlich's MapKit tutorial, especially if you are a newbie. It covers several common iOS development issues, including parsing JSON data.
http://www.raywenderlich.com/2847/introduction-to-mapkit-on-ios-tutorial
"The Implementation" section is where his JSON feed is retrieved and then in "Plotting the Data" he uses the SBJson library to parse it.