Try and Catch with NSUrl(fileURLWithPath) - ios

I've been trying to implement try and catch in the following code
if let s = songId {
let track: NSURL!
track = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(s, ofType: "mp3")!)
.............
}
I came up with the following code:
do {
track = try NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(s, ofType: "mp3")!)
}
catch let error as NSError {
print("NSURL Error: \(error.localizedDescription)")
}
But I get the following warnings:
No calls to throwing functions occur within 'try' expression
and
'catch' block is unreachable because no errors are thrown in 'do' block
And this is strange to me, because this construction usually works.
Only with NSURL this construction isn't working. And I can't figure out why this is happening. Maybe it has something to do with it being an optional, but im not sure.
I can't figure out how to solve this. I need to use a try/catch or something similar, but I can't figure it out how to make it work.
I saw some similar problems on Google, but it didnt gave me an answer.
So my question is: How can I implement a try/catch construction or something similar with NSURL?
Thanks in advance.

There are no methods used that marked with throws keyword at the definition. So it really does not make much sense to wrap your code with try-catch. I would recommend to consider this:
let s = "song"
guard let trackURL = NSBundle.mainBundle().URLForResource(s, withExtension: "mp3") else {
print("File not found in the app bundle: \(s).mp3")
return false
}
Does it help?

That initializer doesn't fail and doesn't throw or fail so a try/catch block is unnecessary. The declaration is:
public init(fileURLWithPath path: String)
If it could throw an error is would be declared as:
public init(fileURLWithPath path: String) throws
Or if it might fail without throwing an error it would be declared as:
public init?(fileURLWithPath path: String)
If you're certain that the bundle will always contain the track you're looking for then you can just use
let track = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource(s, ofType: "mp3")!)

Related

how to add background music

The duplicate answer does not works at all
import Cocoa
import AVFoundation
var error: NSError?
println("Hello, Audio!")
var url = NSURL(fileURLWithPath: "/Users/somebody/myfile.mid") // Change to a local midi file
var midi = AVMIDIPlayer(contentsOfURL: url, soundBankURL: nil, error: &error)
if midi == nil {
if let e = error {
println("AVMIDIPlayer failed: " + e.localizedDescription)
}
}
midi.play(nil)
while midi.playing {
// Spin (yeah, that's bad!)
}
I've made a couple of changes to your code but this seems to "work" (we'll get to that)
First off, import the MP3 file to your playground as described in this answer
Then you can use your file like so:
import UIKit
import AVFoundation
print("Hello, Audio!")
if let url = Bundle.main.url(forResource: "drum01", withExtension: "mp3") {
do {
let midi = try AVMIDIPlayer(contentsOf: url, soundBankURL: nil)
midi.play(nil)
while midi.isPlaying {
// Spin (yeah, that's bad!)
}
} catch (let error) {
print("AVMIDIPlayer failed: " + error.localizedDescription)
}
}
Notice:
printinstead of println
In Swift 3 a lot of things was renamed and some of the "old" methods that took an &error parameter was changed to use do try catch instead. Therefore the error has gone from your call and has been replaced with a try.
The above will fail! You will see error code -10870 which can be found in the AUComponent.h header file and which translates to:
kAudioUnitErr_UnknownFileType
If an audio unit uses external files as a data source, this error is returned
if a file is invalid (Apple's DLS synth returns this error)
So...this leads me to thinking you need to do one of two things, either:
find a .midi file and use that with the AVMidiPlayer
find something else to play your file, for instance AVFilePlayer or AVAudioEngine
(you can read more about error handling in Swift here).
Hope that helps you.
The mp3 file must be in the Resources folder.
You play an mp3 with code like this (not the MIDI player):
if let url = Bundle.main.url(forResource: "drum01", withExtension: "mp3") {
let player = try? AVAudioPlayer(contentsOf: url)
player?.prepareToPlay()
player?.play()
}

FileManager.createDirectory fails with NSCocoaErrorDomain Code: 518

I'm doing
let tempDirectory = URL(string: "\(NSTemporaryDirectory())video/")!
do {
try FileManager.default.createDirectory(
at: tempDirectory,
withIntermediateDirectories: true)
} catch { report(error) }
and that's often throwing an NSCocoaErrorDomain Code: 518.
Any idea of the reason? I thought that could because there's already something there, so I added
var isDir: ObjCBool = false
if FileManager.default.fileExists(
atPath: tempDirectory.absoluteString,
isDirectory: &isDir
) {
if isDir.boolValue {
print("Temp directory exists on launch")
}
else {
print("Temp directory exists on launch and is a file")
}
return
}
but that doesn't seem to catch anything
Your building of tempDirectory isn't correct. You want:
let tempDirectory = URL(fileURLWithPath: NSTemporaryDirectory()). appendingPathComponent("video")
The issue with your code is that you were not passing a value URL string to URL(string:). Since you have a file path you need to use URL(fileURLWithPath:). And build paths/URLs using the provided methods to ensure slashes and other parts are added correctly.
Print your value of tempDirectory from your original code and then print the new value from the code in my answer. Note the key difference.
Your URL will be something like:
/var/...
and it may be missing the slash before "video".
The correct file URL will be something like:
file:///var/...

Error while using .copyItemAtPath

I am trying to copy a file (.plist) to a new directory but I am getting an error saying : Extra argument "error" in call. My code is below.
I searched apple's swift documentation. I guess .copyItemAtPath code changed and I need to use throws but I cant implement throws apperantly.
var folder = NSBundle.mainBundle().pathForResource(folderName, ofType: folderType)
//this is where i get error
NSFileManager.defaultManager().copyItemAtPath(folder, toPath: folderPath, error:nil)
print("Coppied")
With Swift2 you need to do something like this:
do{
try NSFileManager.defaultManager().copyItemAtPath(folder, toPath: folderPath)
print("Coppied")
}catch let error as NSError{
print(error.localizedDescription);
}

handling error using xcode 7.0 beta in asynchronous block

I am trying to validate different errors while downloading text files from AWS S3, and with the next piece of code:
... above here function receiving String parameters ruta, archivo, archivoLocal
let directorioURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first! as NSURL
let archivoURL = directorioURL.URLByAppendingPathComponent("b\(archivoLocal)")
let downloadRequest = AWSS3TransferManagerDownloadRequest()
downloadRequest.bucket = ruta
downloadRequest.key = archivo
downloadRequest.downloadingFileURL = archivoURL
let transferManager = AWSS3TransferManager.defaultS3TransferManager()
let task = BFTask()
let executor = BFExecutor.mainThreadExecutor()
transferManager.download(downloadRequest).continueWithExecutor(executor, withBlock: { (task) -> AnyObject! in
if task.error != nil {
if task.error.domain == AWSS3TransferManagerErrorDomain {
self.processDomainErrorType(AWSS3TransferManagerErrorType(rawValue: task.error.code))
} else {
self.processError(task.error)
}
} else if task.result != nil {
do {
let mytext = try String(contentsOfURL: archivoURL, encoding: NSUTF8StringEncoding)
self.processResult(mytext)
} catch let urlerror as? NSError {
self.processError(urlerror)
}
}
...
I am getting the error:
Invalid conversion from throwing function of type '(_) throws -> AnyObject!' to non-throwing function type '#convention(block) (BFTask!) -> AnyObject!'
I obtained the "do { try } catch" syntax from https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/AdoptingCocoaDesignPatterns.html#//apple_ref/doc/uid/TP40014216-CH7-ID10
I can remove the error by replacing the catch clause with:
} catch _ {
self.processError(NSError(domain: "String-ContentsOfURL Error", code: 100, userInfo: nil))
}
Of course this way I will never know the real cause why ContentsOfURL could be failing.
All I can figure out why this error happens is because this syntax is valid only for OS X apps and for iOS the error handling guide at
https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/ErrorHandling.html#//apple_ref/doc/uid/TP40014097-CH42
allows only the second syntax unless you own the object throwing the errors from an enum structure of ErrorType type, which is not the case since I want to catch the NSError from String object, contentsOfURL function.
I hope someone could guide me through this, maybe being XCode 7 a beta, the catch syntax is still incomplete or maybe I should not matter about the reason why this function fails, but I think it is important to determine what is making this function fail and if it could be traced and fixed before reaching the do-try-catch clause.
Additionally to the above error, I am getting a warning in the task variable assignation line to BFTask() saying that "Initialization of immutable value 'task' was never used". I think this is a bug with this beta version that it doesn't include the pattern to acknowledge that the variable task is being used in the asynchronous block. I'd appreciate a lot some confirmation about this and if I just need to ignore it.
By the way, the only reason I am using XCode 7 beta is because my client wants to evaluate the app before acquiring their apple membership.
Apple replaced NSError with ErrorType in Swift 2.
Replace your own explicit usage of NSError with ErrorType and you don't get this type of compiler errors.

'Extra argument in call' when calling init! initializer on AVAssetReader swift

I see many versions of this question, but I've looked through many of them and haven't found something explaining my problem yet. I hope this isn't a repeat question.
I am simply trying to initialize an AVAssetWriter with this init! method defined in the documentation:
init!(URL outputURL: NSURL!,
fileType outputFileType: String!,
error outError: NSErrorPointer)
So I've written the following code in my playground:
var err : NSError? = nil
var outputPath = "\(NSTemporaryDirectory())mypath.mov"
var url = NSURL(fileURLWithPath: outputPath)
var fileManager = NSFileManager.defaultManager()
println("The putput path is \(outputPath)")
if(fileManager.fileExistsAtPath(outputPath))
{
fileManager.removeItemAtPath(outputPath, error: &err)
println(outputPath)
if(err != nil)
{
println("Error: \(err?.localizedDescription)")
}
}
var writeInitErr : NSError? = nil
var assetWriter = AVAssetWriter(URL: url, fileType: AVMediaTypeVideo, error: writeInitErr)
However, the last line throws the error "Extra argument 'URL' in call". None of the solutions I found in other questions about this error seem to apply here. Am I passing the wrong type to the parameter? Am I misunderstanding the use of the initializer?
Well, as is often the case, I figured out the answer minutes after asking the question.
The problem is actually with the "error: writeInitError" parameter, which should be
"error: &writeInitError"
Apparently the xcode error reporting is buggy, and was reporting a problem with the URL parameter instead. Fixing the error parameter solved the problem.
I suppose until the error reporting is improved, "Extra argument in call" translates to "Something is wrong with one of your parameters".

Resources