Caching a UIWebView - iphone

I am very new to iphone development and i am trying to get a web view to cache onto the device so that it will sty there even when the application is closed and then reload the data when the application starts again. I would also like it to reload the data in the cache every 2 weeks.
Many Thanks,
Thomas

through a lot of searching around and asking friends i managed to find the code and though that i would share it with everyone
Objective-C
- (void) cacheFile
{
//Create the file/directory pointer for the storage of the cache.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES);
self.dataPath = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"cache.html"];
//Check to see if a file exists a the location
if ([[NSFileManager defaultManager] fileExistsAtPath:dataPath]) {
//Code for customising when the cache reloads would go here.
}
else
{
//If no file exists write the html cache to it
//Download and write to file
NSURL *cacheUrl = [NSURL URLWithString:#"INSERT WEB URL HERE"];
NSData *cacheUrlData = [NSData dataWithContentsOfURL:cacheUrl];
[cacheUrlData writeToFile:dataPath atomically:YES];
}
//Run the load web view function.
[self loadWebView];
}
- (void) loadWebView
{
//Load up the web view from the cache.
[WebView loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:dataPath]]];
}
Swift 3
func cacheFile() {
//Create the file/directory pointer for the storage of the cache.
let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
guard let dataPath = paths.first?.appending("cache.html") else {
return
}
//Check to see if a file exists a the location
if FileManager.default.fileExists(atPath: dataPath) {
//Code for customising when the cache reloads would go here.
} else if let cacheUrl = URL(string: "INSERT WEB URL HERE") {
//If no file exists write the html cache to it
//Download and write to file
do {
let cacheUrlData = try Data(contentsOf: cacheUrl)
try cacheUrlData.write(to: URL(fileURLWithPath: dataPath), options: Data.WritingOptions.atomic)
} catch {
print("Problem with cacheUrlData")
}
}
//Run the load web view function.
loadWebView(dataPath: dataPath)
}
func loadWebView(dataPath: String) {
webView.loadRequest(URLRequest(url: URL(fileURLWithPath: dataPath)))
}

Related

Xcode / Swift default files at installation - iOS

I need to add some "default" file during the installation or the first launch of my app in the "Document" directory to let user access to "demo" files or presets. Is there a way to do it properly ?
It's mostly for iOS Apps.
It's very straightforward to get to the app's Documents directory:
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
let documentsDirectory = paths[0]
return documentsDirectory
}
Using the above function, you would be able to easily refer to the Documents folder to install files (or a folder containing your demo files) into the Documents directory and then read them out of there.
To copy a default file from your iOS application bundle, you could do something like:
let sourceURL = Bundle.main.url(forResource: "defaultfile", withExtension: ".png") // whatever kind of file it is
let destinationFolderURL = self.getDocumentsDirectory()
let fullDestURL = destinationFolderURL.appendingPathComponent("defaultfile.png")
let fileManager = FileManager.default
do{
try fileManager.copyItem(at: sourceURL, to: destURL)
} catch {
print(error)
}
Hopefully I didn't make any typos in the above example. :-)
Obj-C solution for anyone interested
If you want user to just read/view those files, all you need to do is to drag&drop them to your project files in Xcode, and then you can access them programmatically like this:
[[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:#"relative/path/to/your/files"]
Alternatively, if you want your users to modify/re-save those files, you'll need to copy-paste them from your NSBundle to Documents directory on the first launch.
- (void)copyDemoFilesToDocumentsFolder {
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *demoFilesPath = [DOCUMENTS_DIR stringByAppendingPathComponent:#"path/to/your/demo/files"];
if (![fileManager fileExistsAtPath:demoFilesPath]) {
NSString *sourceFolderPath = [[[NSBundle mainBundle] bundlePath]
stringByAppendingPathComponent:#"path/to/your/demo/files"];
[fileManager copyItemAtPath:sourceFolderPath
toPath:demoFilesPath
error:&error];
}
}

How to delete iCloud documents?

I'm using a UIDocument with iCloud. I'm not using CoreData. What's the best way to delete a UIDocument?
Copied from the "Deleting a Document" section of the Document-Based App Programming Guide for iOS.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(void) {
NSFileCoordinator* fileCoordinator = [[NSFileCoordinator alloc] initWithFilePresenter:nil];
[fileCoordinator coordinateWritingItemAtURL:fileURL options:NSFileCoordinatorWritingForDeleting
error:nil byAccessor:^(NSURL* writingURL) {
NSFileManager* fileManager = [[NSFileManager alloc] init];
[fileManager removeItemAtURL:writingURL error:nil];
}];
});
N.B.: "When you delete a document from storage, your code should approximate what UIDocument does for reading and writing operations. It should perform the deletion asynchronously on a background queue, and it should use file coordination."
To delete the document from iCloud, first you have to get the filename you want to delete. and then you can delete it using NSFileManager.
NSString *saveFileName = #"Report.pdf";
NSURL *ubiq = [[NSFileManager defaultManager] URLForUbiquityContainerIdentifier:nil];
NSURL *ubiquitousPackage = [[ubiq URLByAppendingPathComponent:#"Documents"] URLByAppendingPathComponent:saveFileName];
NSFileManager *filemgr = [NSFileManager defaultManager];
[filemgr removeItemAtURL:ubiquitousPackage error:nil];
This is the way, which i used to delete document, Check it out.
It is woking great for me.
Thanks
SWIFT 3 come from #AlexChaffee 's answer
func deleteZipFile(with filePath: String) {
DispatchQueue.global(qos: .default).async {
let fileCoordinator = NSFileCoordinator(filePresenter: nil)
fileCoordinator.coordinate(writingItemAt: URL(fileURLWithPath: filePath), options: NSFileCoordinator.WritingOptions.forDeleting, error: nil) {
writingURL in
do {
try FileManager.default.removeItem(at: writingURL)
} catch {
DLog("error: \(error.localizedDescription)")
}
}
}
}
I think I found a solution:
[[NSFileManager defaultManager] setUbiquitous:NO itemAtURL:url destinationURL:nil error:nil]
Source:
http://oleb.net/blog/2011/11/ios5-tech-talk-michael-jurewitz-on-icloud-storage/
See Apple documentation of "Managing the Life-Cyle of a Document" under 'Deleting a Document."

Save videos using uiimagepickercontroller without changings its created date

I am using uiimagepicker to save video to my application bundle. But after saving that, the created date of the video is changed. My requirement is just to copy that video to my folder without changing its created date.
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
[[picker parentViewController] dismissModalViewControllerAnimated:YES];
NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
NSData *imageData = [NSData dataWithContentsOfURL:url];
NSString *path = NSHomeDirectory();
NSString *img_temp_name=[[NSString stringWithFormat:#"test"] stringByAppendingString:#".mov"];
NSString *full_path=[path stringByAppendingPathComponent:img_temp_name];
if([imageData writeToFile:full_path atomically:YES]) {
}
Can you use NSFileManager to help you?
I assume that you're not going to be allowed just to move the movie but if you copy it, does it preserve some file information?
NSURL *url = [info objectForKey:UIImagePickerControllerReferenceURL];
NSString *path = NSHomeDirectory();
NSString *img_temp_name=[[NSString stringWithFormat:#"test"] stringByAppendingString:#".mov"];
NSString *full_path=[path stringByAppendingPathComponent:img_temp_name];
NSURL *dst = [NSURL fileURLWithString:full_path];
NSError *error = nil;
NSFileManager *manager = [[[NSFileManager alloc] init] autorelease];
BOOL success = [manager copyItemAtURL:url toURL:dst error:&error];
if (NO == success || error) {
NSLog(#"Could not copy : %#", error);
}
Your issue is that as part of the picking process the video is reencoded. This changes the creation date. I would also like to know if it is possible to getbthis info.
Here is a way to get videos as NSData.
It uses the Photos framework as ALAssetLibrary is deprecated as of iOS9:
IMPORTANT
The Assets Library framework is deprecated as of iOS 9.0. Instead, use the Photos framework instead, which in iOS 8.0 and later provides more features and better performance for working with a user’s photo library. For more information, see Photos Framework Reference.
import Photos
func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
self.dismissViewControllerAnimated(true, completion: nil)
if let referenceURL = info[UIImagePickerControllerReferenceURL] as? NSURL {
let fetchResult = PHAsset.fetchAssetsWithALAssetURLs([referenceURL], options: nil)
if let phAsset = fetchResult.firstObject as? PHAsset {
PHImageManager.defaultManager().requestAVAssetForVideo(phAsset, options: PHVideoRequestOptions(), resultHandler: { (asset, audioMix, info) -> Void in
if let asset = asset as? AVURLAsset {
let videoData = NSData(contentsOfURL: asset.URL)
// optionally, write the video to the temp directory
let videoPath = NSTemporaryDirectory() + "tmpMovie.MOV"
let videoURL = NSURL(fileURLWithPath: videoPath)
let writeResult = videoData?.writeToURL(videoURL, atomically: true)
if let writeResult = writeResult where writeResult {
print("success")
}
else {
print("failure")
}
}
})
}
}
}

Copy folder from iPhone Resources directory to document directory

BOOL success;
NSFileManager *fileManager = [[NSFileManager defaultManager]autorelease];
NSError *error;
NSArray *paths = NSSearchPathForDirectoriesInDomains( NSDocumentDirectory,
NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *documentDBFolderPath = [documentsDirectory stringByAppendingPathComponent:#"DB"];
success = [fileManager fileExistsAtPath:documentDBFolderPath];
if (success){
return;
}else{
NSString *resourceDBFolderPath = [[[NSBundle mainBundle] resourcePath]
stringByAppendingPathComponent:#"DB"];
[fileManager createDirectoryAtPath: documentDBFolderPath attributes:nil];
[fileManager copyItemAtPath:resourceDBFolderPath toPath:documentDBFolderPath
error:&error];
}
}
Like this.
Resources/DB/words.csv => DB folder copy => Document/DB/words.csv
I want to copy DB subdirectory at Resources folder. I thought that source is good. But that source makes folder and doesn't copy files in DB folder at Resources folder.
I really want to copy files in DB folder at Resources folder. please help me.
1) Do not -autorelease the NSFileManager. You are double-releasing it which will crash your app.
2) No need to call -createDirectoryAtPath:. From the SDK doc of -copyItemAtPath:toPath:error:,
The file specified in srcPath must exist, while dstPath must not exist prior to the operation
and creating the directory the copy to fail.
Swift 3.0
Using String
func copyFolder(){
// Get the resource folder
if let resourceMainPath = Bundle.main.resourcePath{
var isDirectory = ObjCBool(true)
// Get the path of the folder to copy
let originPath = (resourceMainPath as NSString).appendingPathComponent("NameOfFolder")
// Get the destination path, here copying to Caches
let destinationPath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first!
// Append the folder name to dest path so that system creates the directory if it doesnt exist
let destPath = (destinationPath as NSString).appendingPathComponent("/NameOfFolder")
let fileManager = FileManager.default
if fileManager.fileExists(atPath: destPath, isDirectory:&isDirectory ){
// If an overwrite behavior is needed, remove and copy again here
print("Exists")
}else{
// Do the copy
do {
try fileManager.copyItem(atPath: originPath, toPath: destPath)
}catch let error{
print(error.localizedDescription)
}
}
}else{
}
}
Using URL
func copyTheFolder(){
// Get the resource folder
if let resourceMainURL = Bundle.main.resourceURL{
var isDirectory = ObjCBool(true)
// Get the path of the folder to copy
let originPath = resourceMainURL.appendingPathComponent("NameOfFolder")
// Get the destination path, here copying to Caches
let destinationPath = NSSearchPathForDirectoriesInDomains(.cachesDirectory, .userDomainMask, true).first!
// Append the folder name to dest path so that system creates the directory if it doesnt exist
let destURL = URL(fileURLWithPath: destinationPath).appendingPathComponent("/NameOfFolder")
let fileManager = FileManager.default
if fileManager.fileExists(atPath: destURL.path, isDirectory:&isDirectory ){
// If an overwrite behavior is needed, remove and copy again here
print("Exists")
}else{
// Do the copy
do {
try fileManager.copyItem(at: originPath, to: destURL)
}catch let error{
print(error.localizedDescription)
}
}
}
}

iPhone - NSData from local file's URL

I have a NSURL object which gives me the path of a local file (in documents folder). I want to populate an NSData object with the contents of this file. Tried using dataWithContentsOfURL: but this fails. I know the file exists because the iPhone SDK returns the path.
Can someone please tell me how I can get an NSData object from the URL of a local file?
Thanks.
// Given some file path URL: NSURL *pathURL
// Note: [pathURL isFileURL] must return YES
NSString *path = [pathURL path];
NSData *data = [[NSFileManager defaultManager] contentsAtPath:path];
Swift code:
let data = FileManager.default.contents(atPath: path)
To get this work you just need to do:
NSURL *imgPath = [[NSBundle mainBundle] URLForResource:#"search" withExtension:#"png"];
NSString*stringPath = [imgPath absoluteString]; //this is correct
//you can again use it in NSURL eg if you have async loading images and your mechanism
//uses only url like mine (but sometimes i need local files to load)
NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:stringPath]];
UIImage *ready = [[[UIImage alloc] initWithData:data] autorelease];
Make sure your local URL starts with "file://"
then you would just have to do this:
NSData *fileData = [NSData dataWithContentsOfFile:fileURL.path];
For swift3 I found answer from following URL helpful
( I was getting following path , after capturing image using phonegap plugin
file:///var/mobile/Containers/Data/Application/B64B06DE-7976-45CF-9BE2-661F0F309A06/tmp/abcded.jpg )
https://stackoverflow.com/a/41043447/6383908
if let videoURL = URL(string: urlString), let videodata = try? Data(contentsOf: videoURL) {
//Add code of Alamofire here
}
guard let data = FileManager.default.contents(atPath: path) else
{ ...