Why do I unwrap nil in my Swift file? - json

I have an app (the same one from my previous post about unwrapping nil. I really hate nil now.) that searches the iTunes store and returns data in JSON. I have it working, it gets the song name, artist name, everything! I created an #IBAction button for playing the song's preview. The JSON has a property that is the url to the song preview. When I click the button, it does the following:
let alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(url, ofType: "m4a")!)
AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback, error: nil)
AVAudioSession.sharedInstance().setActive(true, error: nil)
var error:NSError?
audioPlayer = AVAudioPlayer(contentsOfURL: alertSound, error: &error)
audioPlayer.prepareToPlay()
audioPlayer.play()
The url is this: http://a1993.phobos.apple.com/us/r1000/101/Music/b7/b3/e0/mzm.ooahqslp.aac.p.m4a. I know my setup for playing an audio file works; I have another app I am building that uses the exact same setup. Why does it tell me that I unwrap nil here: http://a1993.phobos.apple.com/us/r1000/101/Music/b7/b3/e0/mzm.ooahqslp.aac.p.m4a? The url is valid and the file plays.

Examine this line of code.
let alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(url, ofType: "m4a")!)
fileUrlWithPath is asking for a local path, that is one on your device.
NSBundle.mainBundle().pathForResource(url.....
This method returns the local path for the resource you send to it. You are sending it a web url, which is not in the mainBundle unless you've explicitly put it there. So the path that it returns is nil, because there is no local path that satisfies the arguments you are passing to it.

If you have a local resource you should use a method called URLForResource
This line makes no sense. You should always prefer working with urls and extract the path from it if needed.
Replace this line:
let alertSound = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("fileName", ofType: "m4a")!) // this would crash if not found (nil)
with this block of code
if let alertSoundUrl = NSBundle.mainBundle().URLForResource("fileName", withExtension: "m4a") {
println(true)
} else {
println(false)
}
If it is a web link you need to use NSURL(string:). fileUrlWithPath it is only for local resources.
if let checkedUrl = NSURL(string: "http://a1993.phobos.apple.com/us/r1000/101/Music/b7/b3/e0/mzm.ooahqslp.aac.p.m4‌​") {
println(true)
} else {
println(false)
}

Related

Saving a file with a variable of datatype 'Data" in Swift

I'm new to programming and I'm trying to write a function in Swift to download a JSON and parse it.
However, the JSON is very complicated and I have a daily limit on number of requests of data from the server.
Is there a way to download the data and save it to a file as 'data' so I can run all tests on this data in the file and not have to get it from the server everytime? Once I'm ready, I can start getting data from the server again.
Basically I could initialize a data variable with the contents of the file so I can use it on my tests.
Thank you
Determine where you want to store it and what it should be named. For example, for files that can be re-retrieved from the network, we’d use the cachesDirectory:
let folder = try! FileManager.default
.url(for: .cachesDirectory, in: .userDomainMask, appropriateFor: nil, create: true)
.appendingPathComponent("downloads")
Or, you can use the applicationSupportDirectory (if re-retrieving it is impractical) or .documentsDirectory (if you want to potentially expose the file to the end user). But the idea is the same.
Create that folder if you haven’t already:
try? FileManager.default.createDirectory(at: folder, withIntermediateDirectories: true)
Create URL for the file within that folder:
let fileURL = folder.appendingPathComponent("sample.json")
Save that Data to that fileURL:
do {
try data.write(to: fileURL)
} catch {
print(error)
}

SwiftyJSON Parse JSON error for array object

I am retrieving data from URL like this:
let url = NSURL(string: baseURL)
let request = NSURLRequest(URL: url!)
let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in
if error == nil {
let swiftyJSON = JSON(data: data!)
let results = swiftyJSON[0]["name"]
print(results)
} else {
print("error")
}
}
For the above, I get data like this:
[
{
"_id":"123",
"_rev":"345",
"name":"hey"
},
{
"_id":"133",
"_rev":"33345",
"name":"hello"
}
]
I always end up in error block and I am not sure why?
I pasted the JSON in chrome console and able to do swiftyJSON[0].name. I would like to print all elements from the above json OBJECT.
Error:
error Optional(Error Domain=NSURLErrorDomain Code=-1003 "A server with the specified hostname could not be found." UserInfo={NSUnderlyingError=0x7f87514ab570 {Error Domain=kCFErrorDomainCFNetwork Code=-1003 "(null)" UserInfo={_kCFStreamErrorCodeKey=8, _kCFStreamErrorDomainKey=12}}, NSErrorFailingURLStringKey=http://localhost:3000/idea, NSErrorFailingURLKey=http://localhost:3000/idea, _kCFStreamErrorDomainKey=12, _kCFStreamErrorCodeKey=8, NSLocalizedDescription=A server with the specified hostname could not be found.})
Please note, localhost:3000 is on.
The error you pasted may be the request's hostname not found.
"A server with the specified hostname could not be found." The JSON parse seems right totally.
The error is not in the JSON data. The data cannot be retrieved in the first place since the URL http://localhost:3000/idea is not working.
Most likey, the URL is valid on your Mac but not on your iPhone. The URL would only be valid if your server side was running on the iPhone or simulator itself, which is rather unlikely.
localhost isn't a global address. On your Mac, it refers to your Mac. On an iPhone, it refers to the iPhone itself.
Open the Network Utility app on your Mac, look up the IP address and replace localhost with your IP address, e.g. http://192.168.1.37:3000/idea. Then your iOS app will be able to retrieve the data.

integrate UISearchController with Async result update in swift

I want to implement UISearchContoller that search from webservice JSON with swifty json, exactly like apple's appStore when you search for an app, it loads without load them into tableView
here is what I have done in updateSearchResultsForSearchController method:
func updateSearchResultsForSearchController(searchController: UISearchController) {
filterContentForSearchText(searchController.searchBar.text!)
}
func filterContentForSearchText(searchText: String) {
filteredContents = myStruct.filter{$0.name.rangeOfString(searchText) != nil
}
Posting more of your code would be nice, like what you are using to get the results from the web service, However, I will try to step you through it anyway.
I have done with before just using a UISearchBar and it's delegate method, one the user pressed the search button or enter, I would use NSURLSession to pass the user's search terms to the API, and parsed the response.
func searchBarSearchButtonClicked(_ searchBar: UISearchBar) {
let searchText : String = searchBar.text
webService.getRecipe(ingredient: searchText, completionHandler: { (recipeArray) in
self.highProteinArray = recipeArray
dispatch_async(dispatch_get_main_queue(), {
self.collectionView.reloadData()
})
})
}
As you can see I used a callback to handle setting the newly parsed data to a variable for later use, and then reloaded the collectionView. This way your tableView/collectionView will load and set itself up while you are waiting for the response from the web service and then parsing it, once that is complete you just reload to show the new data.
To add a little extra you could even add a fading in animation in your cellForItemAtIndexPath or cellForRowAtIndexPath, whichever you are using.

Parsing JSON file from folder - NSTemporaryDirectory

I have got a file downloaded from AWS S3 to my NSTemporaryDirectory using this code:
let downloadFilePath = (NSTemporaryDirectory() as NSString).stringByAppendingPathComponent("FILENAME")
let downloadingFileURL = NSURL(fileURLWithPath:downloadFilePath)
let downloadRequest: AWSS3TransferManagerDownloadRequest = AWSS3TransferManagerDownloadRequest();
downloadRequest.bucket = "Bucketname";
downloadRequest.key = "FileName";
downloadRequest.downloadingFileURL = downloadingFileURL;
The file = .json file
the apps content is all saved on the JSON file, therefore i need to redirect the file from the NSTemporaryDirectory in order for the content to appear on the application.
Does anyone know the parse function in order to load the data from my JSON file into the application?
Thank you
You cannot modify the main bundle, so this isn't going to work.
There are a few directories under your control, for example the home directory, the application support directory, cache directories, or possibly the document directory.
As gnasher729 notes, you can't modify the main bundle itself, but there's no reason to here. You don't need to move the file in order to display it. You can read from your temporary directory. It's inside your application sandbox, and there's nothing special about it (it doesn't even get cleaned up for you either, so that's your responsibility if you need that).
The temp directory isn't backed up, so if you want that, you should move this to your documents directory. See NSFileManager moveItemAtPath:toPath:error: if you want to do that (or just download to your documents directory in the first place).
I figured it out.
So after downloading the File:
let downloadFilePath = (NSTemporaryDirectory() as NSString).stringByAppendingPathComponent("FILENAME")
let downloadingFileURL = NSURL(fileURLWithPath:downloadFilePath)
let downloadRequest: AWSS3TransferManagerDownloadRequest = AWSS3TransferManagerDownloadRequest();
downloadRequest.bucket = "Bucketname";
downloadRequest.key = "FileName";
downloadRequest.downloadingFileURL = downloadingFileURL;
i have to submit the download request - as seen below:
// submit download request
let transferManager: AWSS3TransferManager = AWSS3TransferManager.defaultS3TransferManager();
print("Downloading started, please wait...");
transferManager.download(downloadRequest).continueWithExecutor(AWSExecutor.defaultExecutor(), block: { (task) -> AnyObject? in
print("TASK:::::: \(task)");
if (task.error != nil){
print("Error Downloading");
}else{
self.readFile()
print("Download complete");
}
return nil;
}, cancellationToken: nil)
}
create a function that will parse your JSON file through the temp directory, using AlamoFire and SwiftyJSON:
func readFile() {
// JSON parsing step (from temporary directory)
let path = (NSTemporaryDirectory() as NSString).stringByAppendingPathComponent("FILENAME")
do {
let readFile:NSString? = try NSString(contentsOfFile: path, encoding: NSUTF8StringEncoding)
let json = JSON.parse(readFile as String!)
for (_, subJson) in json["FILECONTENT"] {
let version = subJson["FILECONTENT"].string
let newsletter = Edition(Version: version!)
self.editions.append(ARRAYNAME!)
}
dispatch_async(dispatch_get_main_queue()) {
self.tableView.reloadData()
}
//print(readFile)
} catch {
}
}
this will showcase the text on your application when ran.
I am trying to get the images to do the something now.

parsing json from url to swift 2.0

I've been trying to retreive my json data for my iOS App. I tried many different sollutions but none of these worked properly for me. So this was the code I was using to read the json from the url and convert it.
let url = NSURL(string: "http://www.blind3d.byethost7.com/service.php")!
func load() {
do {
let request = NSURLRequest(URL: url)
let data = try NSURLConnection.sendSynchronousRequest(request, returningResponse: nil)
self.handleData(data)
}
catch let error as NSError {
print("wieso dont you do siss : \(NSURLRequest(URL: url))")
self.handleError(error)
}
}
func handleError(error : NSError?) {
print("wieso dont you do siss : \(NSURLRequest(URL: url))")
NSLog("%#", "Error with loading from \(url): \(error)")
}
func handleData(data : NSData) {
do {
let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.AllowFragments)
handleJSON(json)
}
catch let error as NSError {
handleError(error)
}
}
but somehow this isn't running properly. I am always getting this error when I am executing this method: NSJSONSerialization
Error with loading from http://www.blind3d.byethost7.com/service.php: Optional(Error Domain=NSCocoaErrorDomain Code=3840 "Invalid value around character 0." UserInfo={NSDebugDescription=Invalid value around character 0.})
The json data I wanted to use for my app is here
Thank you for your help guys
The problem occurs because there it no actual JSON in the data variable. I tried your web service, and this is what you get returned in the data, along with all the other error html tags:
"This site requires Javascript to work, please enable Javascript in your
browser or use a browser with Javascript support"
The full response:
<html><body><script type="text/javascript" src="/aes.js" ></script><script>function toNumbers(d){var e=[];d.replace(/(..)/g,function(d){e.push(parseInt(d,16))});return e}function toHex(){for(var d=[],d=1==arguments.length&&arguments[0].constructor==Array?arguments[0]:arguments,e="",f=0;f<d.length;f++)e+=(16>d[f]?"0":"")+d[f].toString(16);return e.toLowerCase()}var a=toNumbers("f655ba9d09a112d4968c63579db590b4"),b=toNumbers("98344c2eee86c3994890592585b49f80"),c=toNumbers("26049265c821fd7227c09955cbb61ebc");document.cookie="__test="+toHex(slowAES.decrypt(c,2,a,b))+"; expires=Thu, 31-Dec-37 23:55:55 GMT; path=/";location.href="http://www.blind3d.byethost7.com/service.php?ckattempt=1";</script><noscript>This site requires Javascript to work, please enable Javascript in your browser or use a browser with Javascript support</noscript></body></html>
This seems to happen, because there is some Javascript injected in the webpage you are trying to parse from, probably for statistics, or some other unknown reasons.
For checking by yourself, print your data - print(data), before calling self.handleData(data)
Try removing \r\n or escape them with '\' like
\\r\\n
and you are good to go. BTW, using json is painful in swift like this, SwiftyJSON is a necessary library if you deal with json frequently.
This is the result of installed "testCookie-nginx-module"
It's supposed to prevent DDOS attacks on your hosting
When you visit your site for the first time, it sends you this JS code, which your browser is supposed to process and set a special cookie (its name it _test)
Only with this cookie attached to your IP your browser can see the original content (your content: html php json etc.)
Seems the only way for you - is to process this JS (with AES, HEX and other JS functions, get the right _test cookie and send another request with this cookie)