XCode newbie here and i have been trying to figure out why the following is happening...
With the way the code is currently written, i keep getting 'NSInvalidArgumentException'.
reason: 'data parameter is nil' in xcode. The url works fine on the browser.
When I remove the "filters=%7B%22region%22%3A%22CA%22%7D" part of the url, it works fine in Xcode, but when this section of the url is included, that's when I get the error message. I have tried using \" in replacement of the %22 but still nothing. Any suggestions are greatly appreciated.
NSURL *url = [NSURL URLWithString:[#"http://api.v3.factual.com/t/restaurants-us?q=peets+coffee&filters=%7B%22region%22%3A%22CA%22%7D&KEY=p7kwKMFUSyVi64FxnqWmeSDEI41kzE3vNWmwY9Zi"stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
NSData *data = [NSData dataWithContentsOfURL: url];
I also had the same problem:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'data parameter is nil'
But I had solved it. The reason is my API URL is incorrect. Please check out your API URL. Good luck for you!
The code you have posted works without crashing, but the data object ends up being nil
At some point later in the code you access data. Since data == nil, the app crashes.
I suggest entering
http://api.v3.factual.com/t/restaurants-us?q=peets+coffee&filters=%7B%22region%22%3A%22CA%22%7D&KEY=p7kwKMFUSyVi64FxnqWmeSDEI41kzE3vNWmwY9Zi
and
http://api.v3.factual.com/t/restaurants-us?q=peets+coffee&KEY=p7kwKMFUSyVi64FxnqWmeSDEI41kzE3vNWmwY9Zi
into a browser to shed some light on the situation
UPDATE
The problem was encoding already encoded strings. (The %'s are being encoded to %25)
NSString *urlBase = #"http://api.v3.factual.com/t/restaurants-us?";
NSString *urlData = [#"q=peets+coffee&filters={\"region\":\"CA\"}&KEY=p7kwKMFUSyVi64FxnqWmeSDEI41kzE3vNWmwY9Zi"stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"%#%#",urlBase,urlData]];
NSData* data = [NSData dataWithContentsOfURL: url];
Works, because you are encoding a non-encoded string.
OR
NSURL *url=[NSURL URLWithString:[NSString stringWithFormat:#"http://api.v3.factual.com/t/restaurants-us?q=peets+coffee&filters=%7B%22region%22%3A%22CA%22%7D&KEY=p7kwKMFUSyVi64FxnqWmeSDEI41kzE3vNWmwY9Zi"]];
NSData* data = [NSData dataWithContentsOfURL: url];
Will work because as your post is, your string was already encoded properly
I had the same issue and I found one word in service name in upper case while actually it was in lower on server. I did fixed the name in URL and issue got resolved. Thanks.
I think the app crash at offline mode and you tried to NSJSONSerialization the data. Thanks
In my case, I forgot to add App Transport Security Settings in the .plist.
So just go to the .plist and add App Transport Security Settings, and then Allow Arbitrary Loads to yes.
I had the same problem. I found out that error was produced because the URL I was using to download some stuff using NSURLSession had become invalid. Removing the operation solved the problem for me.
Related
I´m testing Apple Watch OS 2 and I´m trying to send a image from the application to the watch. According to Apple, I shall use WCSession transferFile to do this.
Use the transferFile:metadata: method to transfer files in the background. Use this method in cases where you want to send more than a simple dictionary of values. For example, use this method to send images or file-based documents.
for example:
NSString *string = [[NSBundle mainBundle] pathForResource:#"my_image" ofType:#"png"];
NSURL *path = [NSURL URLWithString:string];
[[WCSession defaultSession] transferFile:path metadata:#{#"meta1":#"meta2"}];
It all looks ok in the debugger, the path is correct and the file is accessible (checked with NSFileManager) and readable.
However, everytime I try I get a callback to the didFinishFileTransfer function, including an error:
Error Domain=WCErrorDomain Code=7013 "The operation couldn’t be completed. (WCErrorDomain error 7013.)"
Looking up the error:
WCErrorCodeFileAccessDenied
An error indicating that a file could not be transferred because it was inaccessible.
Available in watchOS 2.0 and later.
It seems the file is not accessible by the send function? I have tried things like resaving the file to another directory etc, but nothing seems to work.
Anyone got an idea?
The URL you are creating is not a fileURL. Try:
NSURL *path = [NSURL fileURLWithPath:string];
I managed to solve the issue!
It was because my path did not start with file://
The following code worked just fine:
NSString *string = [[NSBundle mainBundle] pathForResource:#"my_image" ofType:#"png"];
string = [NSString stringWithFormat:#"file://%#", string];
NSURL *path = [NSURL URLWithString:string];
[[WCSession defaultSession] transferFile:path metadata:#{#"meta1":#"meta2"}];
So it´s quite picky regarding the path.
I have tried this:
NSURL *url = [NSURL URLWithString:ftpURL];
NSData *data = [NSData dataWithContentsOfURL:url];
if (data){
[data writeToFile:dataPath atomically:(YES)];
}
But it doesn't seem to work... I have initialised dataPath, and ftpURL elsewhere..I know they aren't null. And data just returns null for some odd reason.
Does the above method support FTP download?
I have also searched on Google and StackOverflow regarding this and I couldn't find a solution that would help me.
I saw SimpleFTPSample and I thought the above method was easier.
Ok, I found out my problem, NSURL was returning null because I needed to stringByAddingPercentEscapesUsingEncoding my ftpURL string.
Thanks guys for the help anyway =]
I just tried AFNetworking on ios7 and i get this error:
/Classes/AFHTTPClient.m:227
2013-09-16 18:25:57.557 App[13531:a0b] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid parameter not satisfying: url
I don't know what's going on, is there an issue with the lib an ios7 ?
thanks.
As Leon says in his comment, commenting out NSParameterAssert is not an ideal solution. An assertion has been put there for a reason by the author of AFNetworking. The code not passing the assertion is likely to be caused by an invalid URL.
Remember that the NSURL factory methods (that is, + URLWithString: and its siblings) will return nil when they're passed an invalid URL string. In this context, an invalid string is a string containing an invalid URL.
What you should do instead of commenting our the assertion, is making sure that you are not passing any invalid URL's to your AFHTTPClient instance. This Stackoverflow answers gives an example of how you could validate a URL. Here's a sample from the answer:
- (BOOL)validateUrl:(NSString *)candidate {
NSString *urlRegEx = #"(http|https)://((\\w)*|([0-9]*)|([-|_])*)+([\\.|/]((\\w)*|([0-9]*)|([-|_])*))+";
NSPredicate *urlTest = [NSPredicate predicateWithFormat:#"SELF MATCHES %#", urlRegEx];
return [urlTest evaluateWithObject:candidate];
}
Alternatively, you could add percentage escapes using NSString's stringByAddingPercentEscapesUsingEncoding method. Like this:
NSString *encoded = [notEncoded stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
I just had this error, the cause was a space at the start of the url:
http://host.com/etc
^
as Kasper says --> "You could add percentage escapes using NSString's stringByAddingPercentEscapesUsingEncoding method"
or better use the following since it deprecated in ios 9
path = [path stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
I had a weird case today with this assert. My problem was that I have copied url from other text editor (Sublime) and that's why url was invalid.
I was not believing until I have tested it few times.
Hope its Working.. In AFnetworing class name AFURLRequestSerialization.m
commented the line 227 : // NSParameterAssert(url);
I am making an iOS client for the Stack Exchange API. After a long, drawn out fight I finally managed to implement authentication - which gives me a token I stick into a URL. When the token is valid, the URL looks like this:
https://api.stackexchange.com/2.1/me/associated?key=_____MY_SECRET_KEY______&access_token=_____ACCESS_TOKEN_:)_____
which, when valid, brings me to this JSON in a webpage:
{"items":[{"site_name":"Stack Overflow","site_url":"http://stackoverflow.com","user_id":1849664,"reputation":4220,"account_id":1703573,"creation_date":1353769269,"badge_counts":{"gold":8,"silver":12,"bronze":36},"last_access_date":1375455434,"answer_count":242,"question_count":26},{"site_name":"Server Fault","site_url":"http://serverfault.com","user_id":162327,"reputation":117,"account_id":1703573,"creation_date":1362072291,"badge_counts":{"gold":0,"silver":0,"bronze":9},"last_access_date":1374722580,"answer_count":0,"question_count":4},...
And I get the correct JSON with this code:
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"https://api.stackexchange.com/2.1/me/associated?key=__SECRET_KEY_:)__&access_token=%#", [[NSUserDefaults standardUserDefaults] objectForKey:#"token"]]];
NSData *jsonData = [NSData dataWithContentsOfURL:url];
if (jsonData)
{
NSDictionary *JSON = [NSJSONSerialization JSONObjectWithData:jsonData options:kNilOptions error:nil];
}
When I manually invalidate the token, however, the URL still looks the same, and the page in a browser displays this:
{"error_id":403,"error_name":"access_denied","error_message":"`key` is not valid for passed `access_token`, token not found."}
However, dataWithContentsOfURL: is always nil. Why? What am I doing wrong?
I do get an NSError returned:
Error Domain=NSCocoaErrorDomain Code=256 "The operation couldn’t be completed. (Cocoa error 256.)" UserInfo=0x1dd1e9f0 {NSURL=https://api.stackexchange.com/2.1/me/associated?key=key((&access_token=token))}
NSCocoaErrorDomain Code=256 actually means a "file system or file I/O related error whose reason is unknown".
Why you get this error is likely because using dataWithContentsOfURL: will not work with that remote URL - or maybe because of the query params which contain the authentication and the token. Thus, you get the "weird" error.
In general, NSData's dataWithContentsOfURL: should only be use to access local file resources.
In order to solve your problem, you should improve your code in two steps:
1) Use NSURLConnection's convenient class method
+ (void)sendAsynchronousRequest:(NSURLRequest *)request queue:(NSOperationQueue *)queue completionHandler:(void (^)(NSURLResponse*, NSData*, NSError*))handler
The block defines what to do with the response data when the request finished. Generally, first check the error parameter, then status code of the response and Content-type - in this order.
2) Replace the former with your own instance method (or one from a third party) with a similar signature but which is much more sophisticated.
Approach #2 enables you to implement and use the following important features
Cancellation
customize authentication in every aspects
load body data to files
process received chunks simultaneous
perform multiple requests in a queue which controls the number of simultaneous connections
and a couple more.
Approach #2 is oftentimes implemented as a subclass of NSOperation and encapsulates a NSURLConnection object (which you need to cancel the connection).
You'll find answers of how to use NSURLConnection in asynchronous mode implementing the delegates. Also, there are third party solutions.
You might find the official documentation invaluable, too:
Using NSURLConnection
For a quick start, you may take a look at my "Simple GET request" class on Gist:
SimpleGetHTTPRequest
This class is NOT based on NSOperation, but it can be modified easily. Consult the official documentation of NSOperation how to make a subclass. This is basically easy, but has a few important things (KVO) which you should get correct.
In my case, adding AppTransportSecuritySettings dictionary into info.plist and setting key AllowArbitraryLoads to true.
Fixed my problem...
Hope it helps new developers.
Your URL might be having a space that's why it returns nil.Just replace the space in URL with a '+' :
stringByReplacingOccurrencesOfString:#" " withString:#"+"
I had this problem when I changed my folder structure. It gave me other NSError codes such as 512 and 4 for any file operations (local and web). The solution was to delete my IOS Simulator folders (Library\Developer\CoreSimulator).
If you are trying to access a remote url via HTTP and using XCode 7 or later you may get a NSCocoaErrorDomain returned from [NSData dataWithContentsOfURL:].
The root cause of this may actually be your "App Transport Security Settings". By default iOS doesn't allow arbitrary loading of URLS.
I have a webview which i want to load using the loadHtmlString method. The problem is that I want to be able to change the img src's with images that i have previously downloaded. I also use google analitics in the html so I need to set the baseUrl to the actual url so it will work. Here comes the problem. If I put the baseUrl in, the images will not load. If I don't set the baseUrl, it works. How can I get around this, so I will be able to both use google analitycs and have the images store locally in my application? I would prefer not having to implement the google analitics sdk in my project.
A strange thing is that if I run it in simulator, and not put the "http://" prefix in front of my baseUrl, it works fine. However, when I run it on a device, I receive the following error and it doesn't work:
Domain=WebKitErrorDomain Code=101 "The URL can’t be shown"
Thanks
EDIT
If I do this, it works:
[appsWebView loadHTMLString:htmlString baseURL:nil];
However, I must provide a baseURL in order to have Google Analitics working, I have two further cases:
This one gives the above mentioned error: (it works ok in simulator but gives error when running on device)
[appsWebView loadHTMLString:htmlString baseURL:[NSURL urlWithString:#"test.com"]];
This one simply doesn't show anything: (neither loads the html string or the url)
[appsWebView loadHTMLString:htmlString baseURL:[NSURL urlWithString:#"http://test.com"]];
I incorrectly assumed that the problem was that the local image was not fully specifying the full path, but that does not appear to be the problem here. But, you are quite right that it appears (somewhat surprisingly) that you cannot specify some web-based baseURL and also reference a local image in your HTML string. No simple solutions are leaping out at me, but at the very least, it appears that you might have a couple of (not very good) options:
First, you could base64 encode the local image using some base64 library like Mike Gallagher's NSData+Base64 category, e.g.:
NSData *imageData = [NSData dataWithContentsOfFile:imagePath];
NSString *imageDataBase64 = [imageData base64EncodedString];
NSString *imageHtml = [NSString stringWithFormat:#"<img src='data:image/png;base64,%#'>", imageDataBase64];
This slows the initial rendering, but maybe it's better than nothing.
Second, you could always try leaving the baseURL as nil, removing the JavaScript that does the Google Analytics from the HTML string, and then try injecting that JavaScript via stringByEvaluatingJavaScriptFromString. This approach may or may not work depending upon the complexity of the Google Analytics JavaScript (e.g. what further web-based references it might have), but there's a outside chance you might be able to do something that way.
My apologies for assuming the problem was a trivial img URL. Clearly you had identified a more fundamental issue.
Original answer:
Create your image URLs in your HTML string to be fully qualified file URLs within your local file system:
The image is either in Documents:
NSString *documentsPath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
NSString *imagePath = [documentsPath stringByAppendingPathComponent:imageName];
Or in the bundle:
NSString *imagePath = [[NSBundle mainBundle] pathForResource:imageName
ofType:nil];
But, once you have fully qualified path, you should be able to use that:
NSURL *imageUrl = [NSURL fileURLWithPath:imagePath];
NSString *imageHtml = [NSString stringWithFormat:#"<img src='%#'>", imageUrl];
I would bet it's a casing issue. Take into account that the Device is case sensitive whereas the Simulator is not. Check the URL and make sure it contains the right characters.