Swift 3 FileManagerDelegate: shouldRemoveItemAt compiler error - swift3

While using Xcode 8 and Swift 3, I am trying to implement the following method for the FileManagerDelegate protocol:
private func fileManager(_ fileManager: FileManager, shouldRemoveItemAt URL: URL) -> Bool {
var shouldDelete = true
let urlString = URL.absoluteString
if urlString?.range(of: "keepfiles") != nil {
shouldDelete = false
}
return shouldDelete
}
the compiler shows the following error:
Use of undeclared type: 'URL'
but it does not offer any solution to fix it. Because of this I cannot test the selective deletion. If I change the URL type declaration to NSURL, the error goes away, but the delegate never gets called and all the files get deleted.
Does anyone know why this is happening and how I can fix it?

You were trying to get the absoluteString from the type URL instead of instance url. Change your parameter name into a more readable format and do like this, the error will go away.
private func fileManager(_ fileManager: FileManager, shouldRemoveItemAt url: URL) -> Bool {
var shouldDelete = true
let urlString = url.absoluteString
if urlString?.range(of: "keepfiles") != nil {
shouldDelete = false
}
return shouldDelete
}

Related

Getting 100x100 profile pic using Facebook API, Firebase and Swift

My project had been getting the URL string for the medium sized profile pic using this code:
let downloadMediumPicTask = session.dataTask(with: mediumProfPictureURL) { (data, response, error)
in
// The download has finished.
if let e2 = error {
print("Error downloading profile picture: \(e2)")
} else {
if let res2 = response as? HTTPURLResponse {
print("Downloaded medium profile picture with response code \(res2.statusCode)")
if let imageData2 = data {
mediumProfilePictureUIImageFile = UIImage(data: imageData2)!
print("mediumProfilePictureUIImageFile has now been defined as: \(mediumProfilePictureUIImageFile).")
} else {
print("Couldn't get image: Image is nil")
}
} else {
print("Couldn't get response code for some reason")
}
}
}
downloadMediumPicTask.resume()
It crashes here giving a 403 response code. The URL that is being referenced is an expired signature URL from Facebook. Firebase doesn't adjust to get the new appropriate URL, and it was from Firebase that I had been getting the URL. I can't figure out how to get it directly as tried below:
func getUrlOfMediumProfilePic(){
if (FBSDKAccessToken.current() != nil) {
let graphPathPart2 = "me/picture"
let paramsPart2 = ["type":"medium", "redirect":"false"]
let completionHandlerPart2 = { (connection: FBSDKGraphRequestConnection?, result: Any?, error: Error?) in
if let error = error {
print("Medium picture graph call contained an error: \(error.localizedDescription)")
return
} else {
guard connection != nil else {
print("getURLOfLargeProfilePic() function aborted bc connection failed.")
return
}
let results = result! as! NSDictionary
let dataDict = results["data"] as! NSDictionary
stringOfMediumProfilePicURLaka100x100 = dataDict["url"] as! String
print("medium picture graph call results define stringOfMediumProfilePicURLaka100x100 as: \(stringOfMediumProfilePicURLaka100x100)")
}
}
let graphRequest = FBSDKGraphRequest(graphPath: graphPathPart2, parameters: paramsPart2)!
graphRequest.start(completionHandler: completionHandlerPart2)
}else{
print("User not logged in when getURLOfMediumProfilePic() function was run.")
return
}
}
This code yields an error with code 8.
Have you tried this:
https://graph.facebook.com/{id}/picture?width=100&height=100
I don't know swift, so I can't help about syntax. I think you can make http request to url and get image.
Hope this help :)

Can't create object with existing primary key value

I'm in my first steps of using Realm Mobile Database, and I would like to know if there is a way of handling the error caused by trying to add an object with the same primaryKey as one previously inserted, causing the following Can't create object with existing primary key value.
Here are my snippets:
class CategoryRLM: Object {
dynamic var name: String = ""
dynamic var desc: String = ""
override static func primaryKey() -> String? {
return "name"
}
}
static func addCategory(category: CategoryRLM) -> Bool {
let realm = try! Realm()
do {
try realm.write {
realm.add(category)
}
return true
}
catch let error {
print(error)
return false
}
}
Using the previous function:
if !CategoryRLM.addCategory(category: newCategory) {
// There was an error while adding the object
}
The thing is that the error doesn't get handled by the do-catch.
Attempting to add an object with a primary key that already exists is classed as programmer error (that is, misuse of the API), and as such it is not possible to handle this error at runtime.
In your case you should instead check if an object exists with that primary key prior to attempting to add the category to the Realm:
static func addCategory(category: CategoryRLM) -> Bool {
let realm = try! Realm()
if let existingCategory = realm.object(ofType: CategoryRLM.self, forPrimaryKey: category.name) {
return false
}
try realm.write! {
realm.add(category)
}
return true
}

FileManager replaceItemAt() results in EXC_BAD_ACCESS

I've written an application that downloads images from a website.
If this image already exists on the device I'm trying to replace it.
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
let userId = Int.init(downloadTask.taskDescription!)! // task description is definetly set in downloadImage() and is an Int
guard let target = imageFolder?.appendingPathComponent("\(userId).jpg") else {
delegate?.imageDownloadFailed(forUser: userId, error: "Could not create target URL.")
return
}
do {
if fileManager.fileExists(atPath: target.path) {
_ = try fileManager.replaceItemAt(target, withItemAt: location)
} else {
try fileManager.moveItem(at: location, to: target)
}
delegate?.savedImage(forUser: userId, at: target)
} catch let error {
delegate?.imageDownloadFailed(forUser: userId, error: error.localizedDescription)
}
}
The problem occurs in the if-statement:
_ = try fileManager.replaceItemAt(target, withItemAt: location)
I always got EXC_BAD_ACCESS and I can't find the error.
fileManager, target, and location are non-nil.
I've already tried to dispatch the code synchronous to the main thread, but the error still persists.
Any advices?
Edit:
Since I'm not the only one who got this error I decided to create a bug report at Apple.
The report is available at Open Radar; click
I've also uploaded a playground file at pastebin.com which demonstrates the error and provides a quick solution similar to the one of naudec.
Had the same issue. Ended up writing my own version:
let fileManager = FileManager.default
func copyItem(at srcURL: URL, to dstURL: URL) {
do {
try fileManager.copyItem(at: srcURL, to: dstURL)
} catch let error as NSError {
if error.code == NSFileWriteFileExistsError {
print("File exists. Trying to replace")
replaceItem(at: dstURL, with: srcURL)
}
}
}
func replaceItem(at dstURL: URL, with srcURL: URL) {
do {
try fileManager.removeItem(at: dstURL)
copyItem(at: srcURL, to: dstURL)
} catch let error as NSError {
print(error.localizedDescription)
}
}
I call copyItem first.
The class holding this method does not exist any more at the time your download finishes and did release your filemanager. Create the FileManager within your completion closure:
...
let localFilemanager = FileManager.default
do {
...

if let nil in swift 2.0 is not working as expected

"if let nil" check is not working in Swift 2.0, but was working fine in Swift 1.2.
In the below code, "fetchNumbersFromCoreDataDB" function returns nil. In getDatabaseDate function, I have a condition "if let date = dbDate". This condition ideally should fail and go to else block. But in Swift 2.0, it is going inside the if block. In Swift 1.2, same code is going to else block. I am confused here. What is the difference here?
func getDatabaseDate() {
let dbDate : NSDate? = ((self.fetchNumbersFromCoreDataDB(“123456”) as DBNumbers!).dbDate)
if let date = dbDate {
print(“\(date)”)
}
else {
print(“No Date”)
}
}
func fetchNumbersFromCoreDataDB(Number:String) -> DBNumbers? {
var numArray = coreDataInterface.fetchAllObjectsFromEntity(info, withAttributeValues: [“No” : Number]) as! [DBNumbers]
return numArray.count>0 ? numArray[0] : nil
}
Note: "dbDate" is NSDate type in Coredata table
The let dbDate line is very oddly constructed and would raise an exception if your fetchNumbersFromCoreDataDB were returning nil. Therefore your fetchNumbersFromCoreDataDB is not returning nil.
Your line:
let dbDate : NSDate? = ((self.fetchNumbersFromCoreDataDB(“123456”) as DBNumbers!).dbDate)
as DBNumbers! says to convert from DBNumbers? to DBNumbers!. So you've got an optional that is implicitly unwrapped.
Hence .dbDate says to unwrap the return result of fetchNumbersFromCoreDataDB and get the dbDate property from it. Had fetchNumbersFromCoreDataDB returned nil, the attempt to unwrap would raise an exception.
What you probably wanted was:
let dbDate = self.fetchNumbersFromCoreDataDB(“123456”)?.dbDate
Which says "if the optional returned by fetchNumbersFromCoreDataDB is not nil then get its dbDate property; otherwise get nil".
If you really need to convince yourself empirically, open a playground and try this:
class DBNumbers {
var dbDate: NSDate?
}
func fetchNumbersFromCoreDataDB(Number:String) -> DBNumbers? {
return nil
}
let dbDate : NSDate? = (fetchNumbersFromCoreDataDB("123456") as DBNumbers!).dbDate
You'll get an EXC_BAD_INSTRUCTION on the last line.

Issue Getting NSData Request To Work In Swift 2.0

I'm hoping someone may be able to help me figure out a snafu I'm having with an app I am trying to write (or learn to write) in Swift 2.0. This previously worked in Swift 1.2, but after the necessary conversions, I am continunally facing the error;
Cannot invoke initializer of type 'NSData' with an argument list of type '(contenOfURL: NSURL, options: NSDataReadingOptions, error:nil)'
Here is my code, slightly truncated, that I am using;
...
class func fetchMinionData() -> [Minion] {
let myURL = "https://myurl/test.json"
let dataURL = NSURL(string: myURL)
let data = NSData(contentsOfURL: dataURL!, options: NSDataReadingOptions.DataReadingMappedIfSafe, error: nil)
//THIS IS THE LINE THAT THROWS THE ERROR
let minionJSON = JSON(data)
var minions = [Minion]()
for (_ , minionDictionary) in minionJSON {
minions.append(Minion(minionDetails: minionDictionary))
}
return minions
}
...
Note that I plan to use the SwiftyJSON library to further parse the data once it is downloaded. I am searching endlessly online, but I just can't seem to figure this out! Thank you!
If you are working with Swift 2, you should not pass the last argument "error". Instead put a try around the NSData initialization. If data needs to be accessed outside take the init result in a var and convert to let Modified code
var optData:NSData? = nil
do {
optData = try NSData(contentsOfURL: dataURL!, options: NSDataReadingOptions.DataReadingMappedIfSafe)
}
catch {
print("Handle \(error) here")
}
if let data = optData {
// Convert data to JSON here
}
Example code for Dictionary :) Swift 2.0
https://github.com/DaRkD0G/LoadExtension/edit/master/LoadExtensionDictionary.swift
enum EHError: ErrorType {
case Nil(String)
case NSData(String)
case JSON(String)
}
extension Dictionary {
/**
Loads a JSON file from the app bundle into a new dictionary
- parameter filename: File name
- throws: PathForResource / NSData / JSON
- returns: Dictionary<String, AnyObject>
*/
static func loadJSONFromBundle(filename: String) throws -> Dictionary<String, AnyObject> {
guard let path = NSBundle.mainBundle().pathForResource(filename, ofType: "json") else {
throw EHError.Nil("[EasyHelper][loadJSONFromBundle][->pathForResource] The file could not be located\nFile : '\(filename).json'")
}
guard let data = try? NSData(contentsOfFile: path, options:NSDataReadingOptions()) else {
throw EHError.NSData("[EasyHelper][loadJSONFromBundle][->NSData] The absolute path of the file not find\nFile : '\(filename)'")
}
guard let jsonDict = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions()) as? Dictionary<String, AnyObject> else {
throw EHError.JSON("[EasyHelper][loadJSONFromBundle][->NSJSONSerialization]Error.InvalidJSON Level file '\(filename)' is not valid JSON")
}
return jsonDict
}
}
If I do not do a mistake, for you is that
/**
Loads a JSON file from the app bundle into a new dictionary
- parameter filename: File name
- throws: EHError : PathForResource / NSData / JSON
- returns: [String : AnyObject]
*/
static func loadJSONFromBundle(filename: String, nameJson:String) throws -> [String : AnyObject] {
guard let path = NSBundle.mainBundle().pathForResource(filename, ofType: "json") else {
throw EHError.Nil("[EasyHelper][loadJSONFromBundle][->pathForResource] The file could not be located\nFile : '\(filename).json'")
}
guard let data = try? NSData(contentsOfFile: path, options:NSDataReadingOptions()) else {
throw EHError.NSData("[EasyHelper][loadJSONFromBundle][->NSData] The absolute path of the file not find\nFile : '\(filename)'")
}
guard let jsonDict = try NSJSONSerialization.JSONObjectWithData(data, options: .AllowFragments) as? [String : AnyObject] else {
throw EHError.JSON("[EasyHelper][loadJSONFromBundle][->NSJSONSerialization] Invalid JSON\n nameJson '\(nameJson)'\nFile '\(filename)'")
}
return jsonDict
}