Getting EXC_BAD_ACCESS when using UIImage(contentsOfFile: ) - swift

I am currently using UIImage(contentsOfFile: path) if a function to return image of a file path but it is getting me EXC_BAD_ACCESS.
I have searched a lot and found some things about auto releasing and solutions in Objective-C but I couldn't find anything for Swift. What should I do in Swift?

Check for nil:
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
if let dirPath = paths.first {
let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent("Image2.png")
let image = UIImage(contentsOfFile: imageURL.path)
// Do whatever you want with the image
}

Related

load glb model in SCNScene swift

I have a .glb file in document folder, how do I get the image and load into scnScene? like how I load a uiimage from document folder
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
if let dirPath = paths.first
{
let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent("Image2.png")
let image = UIImage(contentsOfFile: imageURL.path
is it possible to load .glb in SCNScene?
let scene = SCNScene(named: "latest.glb")
answering my own question, I used GLTFSceneKit
let path = FileManager.default.urls(for: .documentDirectory,
in: .userDomainMask)[0]
.appendingPathComponent("test.glb")
var scene: SCNScene
do {
let sceneSource = try GLTFSceneSource(url: path)
scene = try sceneSource.scene()
} catch {
print("\(error.localizedDescription)")
return
}

loadImageFromDisk - function modyfication swift

im using the below code to load a downloaded image from disk, when the file exists I can load it as image. If it doesn't image returns as nil.
How could I modify the code to replace return nil with loading a placeholder image from my asset folder called default.png. So instead of returning nil, there is always an image return, either downloaded one that's trying to load or if it doesn't exist, my own asset image.
func loadImageFromDiskWith(fileName: String) -> UIImage? {
let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
if let dirPath = paths.first {
let imageUrl = URL(fileURLWithPath: dirPath).appendingPathComponent(fileName)
let image = UIImage(contentsOfFile: imageUrl.path)
return image
}
return nil
}
You can do as below -
func loadImageFromDiskWith(fileName: String) -> UIImage {
let documentDirectory = FileManager.SearchPathDirectory.documentDirectory
let userDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(documentDirectory, userDomainMask, true)
var image = UIImage(named: "default") // Make sure there must be "default.png" in your main bundle.
if let dirPath = paths.first {
let imageUrl = URL(fileURLWithPath: dirPath).appendingPathComponent(fileName)
if FileManager.default.fileExists(atPath: imageUrl.path) { //Check here for file existence. It won't crash.
image = UIImage(contentsOfFile: imageUrl.path)
}
}
return image
}

How to download a file from URL using Alamofire to a custom folder

I'm using Alamofire to a download file from url, I'm getting filepath, but I'm not able to track down that filepath
let mjString = "https://wallpaperstock.net/wallpapers/thumbs1/42535.jpg"
let destination: DownloadRequest.DownloadFileDestination = { _, _ in
let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
print("destinationURLForFile *********** \(documentsURL)")
let fileURL = documentsURL.appendingPathComponent("42535.jpg")
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
Alamofire.download(mjString, to: destination).response { response in
// print(response)
if response.error == nil, let imagePath = response.destinationURL?.path {
let image = UIImage(contentsOfFile: imagePath)
self.mjImage.image = image
print("imagePath = \(imagePath)")
}
}
file:///var/mobile/Containers/Data/Application/4CE55219-8244-4021-B113-1BB00B8F5B10/Documents/42535.jpg
I want that file to a custom folder, if it is possible. Any help would be appreciated.
The Output what i get is,
file:///var/mobile/Containers/Data/Application/4CE55219-8244-4021-B113-1BB00B8F5B10/Documents/42535.jpg
Append Path Component
just simply change
let fileURL = documentsURL.appendingPathComponent("42535.jpg")
to
let fileURL = documentsURL.appendingPathComponent("/yourFolder/42535.jpg")
EDIT
You can load this image with this function:
func loadImageFromDocumentDirectory(nameOfImage : String, folder: String) -> UIImage {
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
if let dirPath = paths.first{
let imageURL = URL(fileURLWithPath: dirPath).appendingPathComponent("\(folder)/\(nameOfImage)")
if FileManager.default.fileExists(atPath: (imageURL.path)) {
if let image = UIImage(contentsOfFile: imageURL.path) {
return image
}
}
}
//Load default image if img doesnt exist.
return UIImage.init(named: "something.jpg")!
}
Just simply use it like:
imageView.image = loadImageFromDocumentDirectory(nameOfImage : "42535.jpg", folder: "yourFolder")

Save UIImage array to disk

I have a UIImage array that I'm trying to save to disk (documents directory). I've converted it to Data so it can be saved but I can't figure out the correct/best way to save that [Data] to disk.
(arrayData as NSArray).write(to: filename, atomically: false) doesn't seem right or there seems like there is some better way.
Code so far:
// Get the new UIImage
let image4 = chartView.snapShot()
// Make UIImage into Data to save
let data = UIImagePNGRepresentation(image4!)
// Add Data image to Data Array
arrayData.append(data!)
// Get Disk/Folder
let filename = getDocumentsDirectory().appendingPathComponent("images")
// This is how I'd Write Data image to Disk
// try? data?.write(to: filename)
// TODO: Write array Data images to Disk
(arrayData as NSArray).write(to: filename, atomically: false)
To save your images to the document directory, you could start by creating a function to save your image as follows. The function handles creating the image name for you and returns it.
func saveImage(image: UIImage) -> String {
let imageData = NSData(data: UIImagePNGRepresentation(image)!)
let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let docs = paths[0] as NSString
let uuid = NSUUID().uuidString + ".png"
let fullPath = docs.appendingPathComponent(uuid)
_ = imageData.write(toFile: fullPath, atomically: true)
return uuid
}
Now since you want to save an array of images, you can simply loop and call the saveImage function:
for image in images {
saveImage(image: image)
}
If you prefer to name those images yourself, you can amend the first function to the following:
func saveImage(image: UIImage, withName name: String) {
let imageData = NSData(data: UIImagePNGRepresentation(image)!)
let paths = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
let docs = paths[0] as NSString
let name = name
let fullPath = docs.appendingPathComponent(name)
_ = imageData.write(toFile: fullPath, atomically: true)
}
When you save an image as a UIImagePNGRepresentation as you are trying to do, please note that is does not save orientation for you. This means that when you attempt to retrieve the image, it might be titled to the left. You will need to redraw your image to make sure it has the right orientation as this post will explain how to save png correctly. However, if you save your image with UIImageJPEGRepresentation you will not have to worry about all that and you can simply save your image without any extra effort.
EDITED TO GIVE ARRAY OF IMAGES
To retrieve the images you have saved, you can use the following function where you pass an array of the image names and you get an array back:
func getImage(imageNames: [String]) -> [UIImage] {
var savedImages: [UIImage] = [UIImage]()
for imageName in imageNames {
if let imagePath = getFilePath(fileName: imageName) {
savedImage.append(UIImage(contentsOfFile: imagePath))
}
}
return savedImages
}
Which relies on this function to work:
func getFilePath(fileName: String) -> String? {
let nsDocumentDirectory = FileManager.SearchPathDirectory.documentDirectory
let nsUserDomainMask = FileManager.SearchPathDomainMask.userDomainMask
var filePath: String?
let paths = NSSearchPathForDirectoriesInDomains(nsDocumentDirectory, nsUserDomainMask, true)
if paths.count > 0 {
let dirPath = paths[0] as NSString
filePath = dirPath.appendingPathComponent(fileName)
}
else {
filePath = nil
}
return filePath
}
You can below code to stored image into local.
let fileManager = NSFileManager.defaultManager()
let paths = (NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0] as NSString).stringByAppendingPathComponent("ImageName.png")
let image = YOUR_IMAGE_TO_STORE.
let imageData = UIImageJPEGRepresentation(image!, 0.5)
fileManager.createFileAtPath(paths as String, contents: imageData, attributes: nil)

reading from .plist always returns nil

All of my attempts to read from a plist have resulted in a nil value returned, I've tried this in several ways on both Xcode 6 & Xcode beta 7. Also, there are quite a few similar questions on stack, I've tried many of them, but none of them resolve this issue.
I've added my words.plist by clicking on:
{my project} > targets > build phases > copy Bundle Resources
Then I tried several variations of the following code in my ViewController:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
let documentsDirectory = paths[0] as! String
let path = documentsDirectory.stringByAppendingPathComponent("words.plist")
let fileManager = NSFileManager.defaultManager()
//check if file exists
if(!fileManager.fileExistsAtPath(path)) {
// If it doesn't, copy it from the default file in the Bundle
if let bundlePath = NSBundle.mainBundle().pathForResource("words", ofType: "plist") {
let resultDictionary = NSMutableDictionary(contentsOfFile: bundlePath)
println("Bundle words file is --> \(resultDictionary?.description)") // this is nil!!!
fileManager.copyItemAtPath(bundlePath, toPath: path, error: nil)
} else {
println("words not found. Please, make sure it is part of the bundle.")
}
} else {
println("words already exits at path.")
// use this to delete file from documents directory
//fileManager.removeItemAtPath(path, error: nil)
}
print("entering if-let")
if let pfr = NSBundle.mainBundle().pathForResource("words", ofType: "plist") {
print("\nin let\n")
print(pfr)
print("\nentering dict if-let\n")
if let dict = NSDictionary(contentsOfFile: path) as? Dictionary<String, AnyObject> {
// use swift dictionary as normal
print("\nin let\n")
print(dict)
}
}
}
Question
Why am I getting a nil value and whats the proper way to add a plist file and read from it?
update:
inside my if statement the following is nil:
let resultDictionary = NSMutableDictionary(contentsOfFile: bundlePath)
println("Bundle words file is --> \(resultDictionary?.description)") // this is nil!!!
To me, this would indicate that either Xcode doesn't know about my words.plist file, or that I'm pointing my bundlePath to the wrong location.
the issue:
As #Steven Fisher stated, in the comments. My .plist file was an Array and not an NSDictionary. So I just had to switch two lines from my code:
let resultDictionary = NSMutableDictionary(contentsOfFile: bundlePath)
to
let resultDictionary = NSMutableArray(contentsOfFile: bundlePath)
and also
if let dict = NSDictionary(contentsOfFile: path) { //...
to
if let dict = NSArray(contentsOfFile: path) { //..
final working code:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let paths = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true) as NSArray
let documentsDirectory = paths[0] as! String
let path = documentsDirectory.stringByAppendingPathComponent("words.plist")
let fileManager = NSFileManager.defaultManager()
//check if file exists
if(!fileManager.fileExistsAtPath(path)) {
// If it doesn't, copy it from the default file in the Bundle
if let bundlePath = NSBundle.mainBundle().pathForResource("words", ofType: "plist") {
let resultDictionary = NSMutableArray(contentsOfFile: bundlePath)
println("Bundle words file is --> \(resultDictionary?.description)")
fileManager.copyItemAtPath(bundlePath, toPath: path, error: nil)
} else {
println("words not found. Please, make sure it is part of the bundle.")
}
} else {
println("words already exits at path.")
// use this to delete file from documents directory
//fileManager.removeItemAtPath(path, error: nil)
}
print("entering if-let")
if let pfr = NSBundle.mainBundle().pathForResource("words", ofType: "plist") {
print("\nin let\n")
print(pfr)
print("\nentering dict if-let\n")
if let dict = NSArray(contentsOfFile: pfr) {
// use swift dictionary as normal
print("\nin let\n")
print(dict)
}
}
}