I have created an app group group.com.example.FoodTracker-qg, In the main view controller of the app I am downloading an image and storing inside the shared container but I am unable to use the same image in image view. I am getting the following error
fatal error: 'try!' expression unexpectedly raised an error: Error Domain=NSCocoaErrorDomain Code=256 "The file “EC700C58-E9C9-480D-8EE2-B88A570A5728image.jpg” couldn’t be opened." UserInfo={NSURL=/private/var/mobile/Containers/Shared/AppGroup/EC700C58-E9C9-480D-8EE2-B88A570A5728image.jpg}: file /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-800.0.63/src/swift/stdlib/public/core/ErrorType.swift, line 178
Below is my code for writing and reading from shared container
// ViewController.swift
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var mealName: UILabel!
#IBOutlet weak var imageView: UIImageView!
override func viewDidLoad() {
super.viewDidLoad()
let urlString = "https://static.pexels.com/photos/3247/nature-forest-industry-rails.jpg"
try? Data(contentsOf: URL(string: urlString)!).write(to: getSharedFileUrl("image.jpg"))
imageView.image = UIImage(data: try! Data(contentsOf: getSharedFileUrl("image.jpg")))
}
func getSharedFileUrl(_ fileName: String) -> URL {
let fileManager = FileManager.default
let url = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.com.example.FoodTracker-qg")
return URL(string: url!.path.appending(fileName))!
}
}
Code seems to be correct, your problem might be due to file name itself....
check url in error
/private/var/mobile/Containers/Shared/AppGroup/EC700C58-E9C9-480D-8EE2-B88A570A5728image.jpg
there's no "/"...it should look like 728/image.jpg
In getSharedFileUrl(_ fileName: String) -> URL why deconstruct the newly retrieved url from containerURL(.. just to create a new one?
You could do something like this instead:
return url!.appending(fileName)
This should fix your problem with the missing /.
I'm not sure I agree with those force wraps, or even with possibly blocking the Main Thread with Data(contentsOf: ..) though!
You append the filename. As a result, you are missing the slash / in between the path components, as JJAAXX44 correctly pinpointed.
Use appendingPathComponentinstead:
func getSharedFileUrl(_ fileName: String) -> URL {
let fileManager = FileManager.default
guard let url = fileManager.containerURL(forSecurityApplicationGroupIdentifier: "group.com.example.FoodTracker-qg")
else {
fatalError() // handle error appropriate to your needs instead
}
return url.appendingPathComponent(fileName)
}
Your write action is not correct.So you can not be read you image form your shared container.
let appGroupIdentifier = "group.mark3"
extension Data {
func writeToGroupContainer(filePath: String, completeHandle: #escaping (Bool, String) -> Void) {
let url = Data.appGroupContainerURL(filePath: filePath)
let result = FileManager.default.createFile(atPath: url.path, contents: self, attributes: nil)
completeHandle(result, url.path)
}
static func appGroupContainerURL(filePath: String) -> URL {
let fileManager = FileManager.default
let groupURL = fileManager.containerURL(forSecurityApplicationGroupIdentifier: appGroupIdentifier)
let url = groupURL!.appendingPathComponent(filePath)
try? FileManager.default.createDirectory(atPath: url.deletingLastPathComponent().path, withIntermediateDirectories: true, attributes: nil)
return url
}
}
us this extension to write a data to your disk correct.
override func viewDidLoad() {
super.viewDidLoad()
let filePath = "images/group/mark3/avatar.png"
let data: Data = UIImagePNGRepresentation(UIImage(named: "image.png")!)!
data.writeToGroupContainer(filePath: filePath) { (done, file) in
print(filePath, done)
}
}
Related
so this might be a trivial question, but I can't get it to work.
I want to save a pdf file to CoreData after I dropped it onto a view (using IOS' Drag&Drop feature)
func dropInteraction(_ interaction: UIDropInteraction, performDrop session: UIDropSession) {
session.loadObjects(ofClass: ComicBookPDFDocument.self) { (pdfItems) in
let items = pdfItems as! [ComicBookPDFDocument]
// "Cannot assign value of type 'ComicBookPDFDocument' to type 'NSData?'"
self.file.data = items[0]
}
}
ComicBookPDFDocument just subclasses PDFDocument to make it conforming to NSItemProviderReading:
final class ComicBookPDFDocument: PDFDocument, NSItemProviderReading {
public static var readableTypeIdentifiersForItemProvider: [String] {
return [kUTTypePDF as String]
}
public static func object(withItemProviderData data: Data, typeIdentifier: String) throws -> ComicBookPDFDocument {
return ComicBookPDFDocument(data: data)!
}
}
However, I get this compiler error from XCode:
Cannot assign value of type 'ComicBookPDFDocument' to type 'NSData?'
How can I save the pdf data from a PDFDocument? I couldn't find anything on the internet or the documentation.
Thanks for any help
Okay, I don't know how I missed that, but here it is:
items[0].dataRepresentation()
You do one thing,
Try to save PDF into the Document Directory and save its path in the Core-Data.
Here is the code to save to Document directory and fetch from document direcory
class PDCache: NSObject {
static let sharedInstance = PDCache()
func saveData(obj: Data, fileName: String){
let filename = getDocumentsDirectory().appendingPathComponent("\(fileName).pdf")
do{
try obj.write(to: filename, options: .atomic)
} catch{
print(error.localizedDescription)
}
}
func getData(fileName: String) -> URL?{
let fileManager = FileManager.default
let filename = getDocumentsDirectory().appendingPathComponent("\(fileName).pdf")
if fileManager.fileExists(atPath: filename.path){
return URL(fileURLWithPath: filename.path)
}
return nil
}
private func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
}
To save the data use this
let data = Data()
self.saveData(obj: data, fileName: "myPdfFile")
and to get the file url use this
let pdfUrl = self.getData(fileName: "myPdfFile")
Try this and let me know if it works for you.
I'm trying to open a .pdf file after download which is downloaded with Alamofire. But I've seen only using a "webview". Thus the application consumes lots of memory and is not viable.
What I want is to open it with the native device application. Any suggestions? Thank you.
Edit: This is my code for download file:
var localPath: NSURL?
Alamofire.download(.GET, url, destination: { (temporaryURL, response) in
let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let pathComponent = response.suggestedFilename
localPath = directoryURL.URLByAppendingPathComponent(pathComponent!)
return localPath!
})
.response { (request, response, _, error) in
if error != nil
{
// got an error in getting the data, need to handle it
print("Error: \(error!)")
}
//print(response)
print("Download file en:\(localPath!)")
self.view.hideToastActivity()
//self.actioncall()
}
}
I need open file from localpath...
You should use UIDocumentInteractionController. You can read about it on this Apple documentation page.
By doing some Googling you should see even some example implementations. For example here you can see some code about this done by "mattneub".
I let you one more code that you can use:
var documentInteractionController: UIDocumentInteractionController!
#IBAction func openDocument(sender: UIButton) {
let URL: NSURL = NSBundle.mainBundle().URLForResource("yourPDF", withExtension: "pdf")!
if (URL != "") {
// Initialize Document Interaction Controller
self.documentInteractionController = UIDocumentInteractionController(URL: URL)
// Configure Document Interaction Controller
self.documentInteractionController.delegate = self
// Present Open In Menu
self.documentInteractionController.presentOptionsMenuFromRect(sender.frame, inView: self.view, animated: true)
//presentOpenInMenuFromRect
}
}
// UIDocumentInteractionControllerDelegate
func documentInteractionControllerViewControllerForPreview(controller: UIDocumentInteractionController) -> UIViewController {
return self
}
I'm trying to open a .pdf file after download which is downloaded with Alamofire. But I've seen only using a "webview". Thus the application consumes lots of memory and is not viable.
What I want is to open it with the native device application. Any suggestions? Thank you.
Edit: This is my code for download file:
var localPath: NSURL?
Alamofire.download(.GET, url, destination: { (temporaryURL, response) in
let directoryURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let pathComponent = response.suggestedFilename
localPath = directoryURL.URLByAppendingPathComponent(pathComponent!)
return localPath!
})
.response { (request, response, _, error) in
if error != nil
{
// got an error in getting the data, need to handle it
print("Error: \(error!)")
}
//print(response)
print("Download file en:\(localPath!)")
self.view.hideToastActivity()
//self.actioncall()
}
}
I need open file from localpath...
You should use UIDocumentInteractionController. You can read about it on this Apple documentation page.
By doing some Googling you should see even some example implementations. For example here you can see some code about this done by "mattneub".
I let you one more code that you can use:
var documentInteractionController: UIDocumentInteractionController!
#IBAction func openDocument(sender: UIButton) {
let URL: NSURL = NSBundle.mainBundle().URLForResource("yourPDF", withExtension: "pdf")!
if (URL != "") {
// Initialize Document Interaction Controller
self.documentInteractionController = UIDocumentInteractionController(URL: URL)
// Configure Document Interaction Controller
self.documentInteractionController.delegate = self
// Present Open In Menu
self.documentInteractionController.presentOptionsMenuFromRect(sender.frame, inView: self.view, animated: true)
//presentOpenInMenuFromRect
}
}
// UIDocumentInteractionControllerDelegate
func documentInteractionControllerViewControllerForPreview(controller: UIDocumentInteractionController) -> UIViewController {
return self
}
I am getting an error when writing an image file to a directory in Xcode. The function data.writeToFile is returning an error. Here is what I am trying to do:
Get The File Path:
func getPath(fileName: String) -> String {
let documentURL = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)[0]
let folder = "sampleDirectory"
return documentURL.URLByAppendingPathComponent(folder).URLByAppendingPathComponent(fileName).path!
}
Save the Image
func saveImage(image: UIImage, path: String) -> Bool {
let pngImageData = UIImagePNGRepresentation(image)
do {
let success = try pngImageData?.writeToFile(path, options: NSDataWritingOptions.init(rawValue: 0))
} catch {
print(error)
}
return false
}
However, there is an error saying:
NSPOSIXErrorDomain - code : 2
Does anyone know what the problem could be?
EDIT
Where I call the code:
let fileName = "first_image"
let imagePath = self.getPath(fileName)
let result = self.saveImage(processedImage, path: imagePath)
processedImage is of type UIImage!
Try creating the directory "sampleDirectory" if it does not exists or don't use a subdirectory.
You can check if the directory exists with:
if !NSFileManager.defaultManager().fileExistsAtPath(path) {
// create missing directories
try! NSFileManager.defaultManager().createDirectoryAtPath(foo, withIntermediateDirectories: true, attributes: nil)
}
You also might want to use the option NSDataWritingOptions.DataWritingAtomic which first write to an auxiliary file first and then exchange the files if there were no errors
Trying to create a simple example code block in Swift 2.0 on iOS 9.1 using Xcode 7.1. Tried this article in techotopia; which I suspect is based on swift 1.2.
Made a few tiny changes so that it would compile & run, but although it appears to work, it doesn't seem to save my string into the file. Is there capability or something subtle I have missed here.
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var textBox: UITextField!
var fileMgr: NSFileManager = NSFileManager.defaultManager()
var docsDir: String?
var dataFile: String?
var string: String = ""
override func viewDidLoad() {
super.viewDidLoad()
let dirPaths = NSSearchPathForDirectoriesInDomains(
.DocumentDirectory, .UserDomainMask, true)
docsDir = dirPaths[0] as String
let dataFile = NSURL(fileURLWithPath: docsDir!).URLByAppendingPathComponent("datafile.dat")
string = "\(dataFile)"
print(string)
if fileMgr.fileExistsAtPath(string) {
let databuffer = fileMgr.contentsAtPath(string)
let datastring = NSString(data: databuffer!,
encoding: NSUTF8StringEncoding)
textBox.text = datastring as? String
}
}
#IBAction func saveText(sender: AnyObject) {
let databuffer = (textBox.text)
let data = databuffer?.dataUsingEncoding(NSUTF8StringEncoding)
fileMgr.createFileAtPath(string, contents: data,
attributes: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
More testing; noticed I get this error when I try and create the file... error in __connection_block_invoke_2: Connection interrupted; which explains why it isn't working, if only I could workout what it is talking about?
Continued to try to debug; added UIFileSharingEnabled but cannot see Documents directory; added more code to test its presence, and create it if missing; fails telling me it is already there... even if it is evidently invisible...
When you do this, string ends up being a string representation of the file URL, e.g. file://.... That file:// prefix is a URL "scheme" (like http:// or ftp://). But including the scheme at the start of the string means that this is not a valid path. You have to remove the scheme.
The easiest way to do this is to use the path method to get the path from a NSURL without that scheme. I'd also use URLForDirectory to get the URL for the documents folder nowadays.
class ViewController: UIViewController {
#IBOutlet weak var textBox: UITextField!
lazy var fileMgr = NSFileManager.defaultManager()
var path: String!
override func viewDidLoad() {
super.viewDidLoad()
let documents = try! fileMgr.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
path = documents.URLByAppendingPathComponent("datafile.dat").path
if fileMgr.fileExistsAtPath(path) {
if let data = fileMgr.contentsAtPath(path) {
textBox.text = String(data: data, encoding: NSUTF8StringEncoding)
}
}
}
#IBAction func saveText(sender: AnyObject) {
let data = textBox.text?.dataUsingEncoding(NSUTF8StringEncoding)
fileMgr.createFileAtPath(path, contents: data, attributes: nil)
}
}
Or I might stay entirely in the world of URLs, retiring paths altogether, also using methods that throw meaningful error messages:
class ViewController: UIViewController {
#IBOutlet weak var textBox: UITextField!
lazy var fileMgr = NSFileManager.defaultManager()
var fileURL: NSURL!
override func viewDidLoad() {
super.viewDidLoad()
do {
let documents = try fileMgr.URLForDirectory(.DocumentDirectory, inDomain: .UserDomainMask, appropriateForURL: nil, create: false)
fileURL = documents.URLByAppendingPathComponent("datafile.dat")
var reachableError: NSError?
if fileURL.checkResourceIsReachableAndReturnError(&reachableError) {
textBox.text = try String(contentsOfURL: fileURL)
}
} catch {
print(error)
}
}
#IBAction func saveText(sender: AnyObject) {
do {
try textBox.text?.writeToURL(fileURL, atomically: true, encoding: NSUTF8StringEncoding)
} catch {
print(error)
}
}
}