No such file or directory iOS - ios

I am trying to get size of the file by its path. Those files are saved videos from my app. i used the below code its returning the error saying there is no file or directory.
NSString *urlPath = [self.localPathArray objectAtIndex:indexPath.row];
NSError *err;
NSDictionary * properties = [[NSFileManager defaultManager] attributesOfItemAtPath:urlPath error:&err];
This is how am saving the file path after downloading the file
- (void)URLSession:(NSURLSession *)session assetDownloadTask:
(AVAssetDownloadTask *)assetDownloadTask didFinishDownloadingToURL:(NSURL *)location {
NSString *localPath = location.relativePath;
NSLog(#"localPath: %#", localPath);
[[NSUserDefaults standardUserDefaults]setValue:self.localPathArray forKey:#"AssetPath"];
}
See the error screenshot and my app storage details screenshot below

The path with reference to root directory is called absolute. The path with reference to current directory is called relative
so try
NSString *localPath = location.path;
instead of
NSString *localPath = location.relativePath;
for e.g
- (void)URLSession:(NSURLSession *)session assetDownloadTask:
(AVAssetDownloadTask *)assetDownloadTask didFinishDownloadingToURL:(NSURL *)location {
NSString *localPath = location.path;
NSLog(#"localPath: %#", localPath);
[self.localPathArray addObject: localPath];
[[NSUserDefaults standardUserDefaults]setValue:self.localPathArray forKey:#"AssetPath"];
}
for sample see this answer already answered in Stack overflow

Related

NSURLSessionDownloadTask: How to change the location where tem files are saved

Under normal circumstances, downloading (video) files will be saved under the location path (.tmp), then move the file (.tmp) to our target folder using the following de;egate method.
But I want to do the downloading and playing, how can I change the file path(location) to the target path(destinationURL) before I download it.
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *destinationFileName = downloadTask.originalRequest.URL.lastPathComponent;
NSURL *destinationURL = [self.downloadDirURL URLByAppendingPathComponent:destinationFileName];
if([fileManager fileExistsAtPath:[destinationURL path]])
{
[fileManager removeItemAtURL:destinationURL error:nil];
}
BOOL success = [fileManager moveItemAtURL:location toURL:destinationURL error:&error];
}
But I want to do the downloading and playing, how can I change the file path(location) to the target path(destinationURL) before I download it
You can't. What you are doing is correct for a download task: download to where it downloads to (which is no concern of yours), and immediately move it to a useful location as soon as the download is complete.
(Note, however, that you do not need to download a video file merely in order to play it. You can just start playing the file across the Internet. So perhaps the problem here is that you are downloading in the first place.)

Saved files no longer exists after closing the app

I am downloading a file using NSURLSessionDownloadTask. it get downloaded and saved. and I can display data normally.
Unfortunitly I only have the iOS simulator to test. What is happenning if I close the app with the stop button on Xcode. then I relaunch, the file is no longer exists.
But, If I closed it by removing it from apps. running list by clicking cmd + shift + H twice. and reluanch it by tapping app. on simulator. I find the file.
BOOL found = [[NSFileManager defaultManager] fileExistsAtPath:path];
Is this a simulator problem? and I shouldn't worry about it in a real device?
Actually, I just managed to test on iPhone. exactly the same behaviour!! Any explanation.
I call this on the NSURLSessionDownloadTask which I sent a destination block that returns the destination to save:
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
progress:(NSProgress * __autoreleasing *)progress
destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
Destination block code:
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSLibraryDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
Try to log documentsDirectoryURL and you will see that it is different each time you launch the app. Solution is to save between launches not an absolute URL, but a path relative to NSLibraryDirectory directory. I had the same problem and I have solved it with two methods:
// [self uploadFolder] returns a folder in NSLibraryDirectory
+ (NSString*)relativePathForURL:(NSURL*)url
{
NSURL *uploadFolderURL = [self uploadFolder];
if ([url.baseURL isEqual:uploadFolderURL])
{
return url.relativeString;
}
else if ([url.absoluteString hasPrefix:uploadFolderURL.absoluteString])
{
return [url.absoluteString substringFromIndex:uploadFolderURL.absoluteString.length];
}
return nil;
}
+ (NSURL*)urlForRelativePath:(NSString*)path
{
return [NSURL URLWithString:path relativeToURL:[self uploadFolder]];
}
They should be used following way:
Download file and move it to NSLibraryDirectory folder with some URL
savedURL.
Call relativePath = [self relativePathForURL:savedURL] and save it.
When app is relaunched call savedURL = [self urlForRelativePath:relativePath]
savedURL is valid now.
Heres the solution;
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
//location is the temporary "destination" which you returned (can be Temp directory) and it now contains the downloaded file. Now copy the file to a new location (eg documents directory) for future use.
BOOL fileCopied = [[[NSFileManager defaultManager] copyItemAtURL:location toURL:documentsDirectoryURLForSavingFileForFutureUe error:&error];
}

Error in file provider app extension

I'm developing an app extension for open mode for my document management application. I have already implemented the import mode which is working fine. But in the open mode , when a third party application tries to open any documents from my storage provider, the following methods of file provider is executing multiple times,kind of an inifinite execution and in turn resulting in a memory warning exception.
- (instancetype)init
- (void)startProvidingItemAtURL:(NSURL *)url completionHandler:(void (^)(NSError *))completionHandler
And also for your reference the complete code fo file provider as follows
- (NSFileCoordinator *)fileCoordinator {
NSFileCoordinator *fileCoordinator = [[NSFileCoordinator alloc] init];
[fileCoordinator setPurposeIdentifier:[self providerIdentifier]];
return fileCoordinator;
}
- (instancetype)init {
self = [super init];
if (self) {
[self.fileCoordinator coordinateWritingItemAtURL:[self documentStorageURL] options:0 error:nil byAccessor:^(NSURL *newURL) {
// ensure the documentStorageURL actually exists
NSError *error = nil;
[[NSFileManager defaultManager] createDirectoryAtURL:newURL withIntermediateDirectories:YES attributes:nil error:&error];
}];
}
return self;
}
- (void)providePlaceholderAtURL:(NSURL *)url completionHandler:(void (^)(NSError *error))completionHandler {
// Should call + writePlaceholderAtURL:withMetadata:error: with the placeholder URL, then call the completion handler with the error if applicable.
NSString* fileName = [url lastPathComponent];
NSURL *placeholderURL = [NSFileProviderExtension placeholderURLForURL:[self.documentStorageURL URLByAppendingPathComponent:fileName]];
NSUInteger fileSize = 0;
// TODO: get file size for file at <url> from model
[self.fileCoordinator coordinateWritingItemAtURL:placeholderURL options:0 error:NULL byAccessor:^(NSURL *newURL) {
NSDictionary* metadata = #{ NSURLFileSizeKey : #(fileSize)};
[NSFileProviderExtension writePlaceholderAtURL:placeholderURL withMetadata:metadata error:NULL];
}];
if (completionHandler) {
completionHandler(nil);
}
}
- (void)startProvidingItemAtURL:(NSURL *)url completionHandler:(void (^)(NSError *))completionHandler {
// Should ensure that the actual file is in the position returned by URLForItemWithIdentifier:, then call the completion handler
NSError* error = nil;
__block NSError* fileError = nil;
//getting the actual fiile from the shared container
NSURL *storeURL = [[NSFileManager defaultManager] containerURLForSecurityApplicationGroupIdentifier:#"group.company.test.NBox"];
storeURL = [storeURL URLByAppendingPathComponent:[url.path lastPathComponent]];
NSData* fileData = [NSData dataWithContentsOfFile:[storeURL path]];
// TODO: get the contents of file at <url> from model
//Writing the file data to the documentStorage location
//[self.fileCoordinator coordinateWritingItemAtURL:url options:0 error:&error byAccessor:^(NSURL *newURL) {
[fileData writeToURL:url options:0 error:&fileError];
//}];
if (error!=nil) {
completionHandler(error);
} else {
completionHandler(fileError);
}
}
- (void)itemChangedAtURL:(NSURL *)url {
// Called at some point after the file has changed; the provider may then trigger an upload
// TODO: mark file at <url> as needing an update in the model; kick off update process
NSLog(#"Item changed at URL %#", url);
}
- (void)stopProvidingItemAtURL:(NSURL *)url {
// Called after the last claim to the file has been released. At this point, it is safe for the file provider to remove the content file.
// Care should be taken that the corresponding placeholder file stays behind after the content file has been deleted.
[self.fileCoordinator coordinateWritingItemAtURL:url options:NSFileCoordinatorWritingForDeleting error:NULL byAccessor:^(NSURL *newURL) {
[[NSFileManager defaultManager] removeItemAtURL:newURL error:NULL];
}];
[self providePlaceholderAtURL:url completionHandler:NULL];
}
Thanks,
Vsh
I'm also trying to develop an app extension for open mode. I haven't been successful yet but I don't get the infinite execution. Looking at your code, it's possible that storeURL in startProvidingItemAtURL: points to something inside your container. If so, then the assignment to fileData would trigger an infinite recursion.
As a test, try setting fileData with a test message like this:
NSString *message = [NSString stringWithFormat:#"This is a test."];
NSData *fileData = [NSKeyedArchiver archivedDataWithRootObject:message];
If that works, then it's a problem with storeURL and you'll have to figure out some different location to get the data.
(Incidentally, I noticed that you commented out the file coordinator in startProvidingItemAtURL:. I also ended up doing that to prevent deadlocks and because there's a note in the documentation that says "Do not use file coordination inside this method." But it's very confusing because the template code for file providers puts the file coordinator in that method!)

newsstand memory storage issue, how do i get the app cache directory?

I have a newsstand app which has magazines and uses the newsstand framework. I realized there was something wrong when deleting the magazines and/or when downloading them because when I accessed settings/usage my app keeps growing in memory usage when downloading and deleting the same magazine.
Found the issue... when downloading the issue in the delegate method:
-(void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL
I just needed to add something like this at the end:
NSError *error;
[[NSFileManager defaultManager] removeItemAtPath:[destinationURL path] error:&error];
if (error){
NSLog(#"ERROR:%#", error);
}
Even the directory is called "caches" you need to manually delete. Ok problem solved but what about the customers who already download my app and have tons of MBs dead in the cache directory.
I wanted to know how to get this directory and delete everything on it at launch and only once...
I can do it only once using a NSUserdefault but how do I get this directory and delete any zip files in it... an example of this directory and a file within is:
/private/var/mobile/Applications/1291CC20-C55F-48F6-86B6-B0909F887C58/Library/Caches/bgdl-280-6e4e063c922d1f58.zip
but this path varies with the device. I want to do this at launch so I'm sure there are no downloads in progress but any other solutions are welcome, thanks in advance.
Everything that you need is enumerate all files from Caches directory and remove ones that have zip extension:
- (void)removeZipFilesFromCachesDirectory {
static NSString *const kZIPExtension = #"zip";
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *cachesDirectoryPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSError *error = nil;
NSArray *fileNames = [fileManager contentsOfDirectoryAtPath:cachesDirectoryPath error:&error];
if (error == nil) {
for (NSString *fileName in fileNames) {
NSString *filePath = [cachesDirectoryPath stringByAppendingPathComponent:fileName];
if ([filePath.pathExtension.lowercaseString isEqualToString:kZIPExtension]) {
NSError *anError = nil;
[fileManager removeItemAtPath:filePath error:&anError];
if (anError != nil) {
NSLog(#"%#", anError);
}
}
}
} else {
NSLog(#"%#", error);
}
}

Moving a core data model that allows external storage into a UIManagedDocument

What is the right way to move a core data model that allows external storage into a UIManagedDocument? I have a core data store that I am trying to move into a UIManagedDocument. I have users with lots of data. Some of it is 2 - 3 minute audio clips. I am subclassing UIManaged document and overriding the configurePersistentStoreCoordinatorForURL. Then copying the files over into the UIManagedDocument bundle. It all seems to work great accept for the Audio files that are stored externally. In my Core Data Model, my audio files are set up to allow external storage. These files are no longer connected after the move and when I try to play them int the app after the move, I get an audio session error. Thanks for any help you can offer on the topic. Here is my code that I am using to override the UIMD…
- (BOOL)configurePersistentStoreCoordinatorForURL:(NSURL *)storeURL
ofType:(NSString *)fileType
modelConfiguration:(NSString *)configuration
storeOptions:(NSDictionary *)storeOptions
error:(NSError *__autoreleasing *)error{
[self printFileDir];
// If legacy store exists, create a UIManaged Document and store it there
NSURL *docsDir = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
NSURL *legacyStoreURL = [docsDir URLByAppendingPathComponent:#"RRLevelBook.sqlite"];
NSFileManager* fileManager = [NSFileManager defaultManager];
if ([fileManager fileExistsAtPath:legacyStoreURL.path])
{
NSLog(#"Old db exists");
//swap files
NSURL *storeURLshm = [NSURL URLWithString:[[storeURL absoluteString] stringByAppendingString:#"-shm"]];
NSURL *storeURLwal = [NSURL URLWithString:[[storeURL absoluteString] stringByAppendingString:#"-wal"]];
NSURL *supportFiles = [[storeURL URLByDeletingLastPathComponent] URLByAppendingPathComponent:#".persistenStore_SUPPORT"];
NSURL *legacyStoreURLshm = [NSURL URLWithString:[[legacyStoreURL absoluteString] stringByAppendingString:#"-shm"]];
NSURL *legacyStoreURLwal = [NSURL URLWithString:[[legacyStoreURL absoluteString] stringByAppendingString:#"-wal"]];
NSURL *legacySupportFiles = [[legacyStoreURL URLByDeletingLastPathComponent] URLByAppendingPathComponent:#".RRLevelBook_SUPPORT"];
NSError* thisError = nil;
//swap the sqlite file
[fileManager replaceItemAtURL:storeURL
withItemAtURL:legacyStoreURL
backupItemName:nil
options:NSFileManagerItemReplacementUsingNewMetadataOnly
resultingItemURL:nil
error:&thisError];
//swap the -shm file
[fileManager replaceItemAtURL:storeURLshm
withItemAtURL:legacyStoreURLshm
backupItemName:nil
options:NSFileManagerItemReplacementUsingNewMetadataOnly
resultingItemURL:nil
error:&thisError];
//swap the -wal file
[fileManager replaceItemAtURL:storeURLwal
withItemAtURL:legacyStoreURLwal
backupItemName:nil
options:NSFileManagerItemReplacementUsingNewMetadataOnly
resultingItemURL:nil
error:&thisError];
//Move in the Support files
[fileManager moveItemAtURL:legacySupportFiles toURL:supportFiles error:nil];
//delete old files that have been swapped
[fileManager removeItemAtURL:legacyStoreURL error:nil];
[fileManager removeItemAtURL:legacyStoreURLwal error:nil];
[fileManager removeItemAtURL:legacyStoreURLshm error:nil];
[fileManager removeItemAtURL:legacySupportFiles error:nil];
NSLog(#"%#",[thisError localizedDescription]);
}
[self printFileDir];
return [super configurePersistentStoreCoordinatorForURL:storeURL ofType:fileType modelConfiguration:configuration storeOptions:storeOptions error:error];
}
Well, here is what I ended up doing - for better or worse:
Open the new UIManagedDocument.
Open up the legacy Core Data Model.
Copy each audio file (NSData) from Legacy CoreData Context to the UIManagedDocument Context.
Reconnect all relationships based on the Legacy CoreData Context.
NSManagedObjectContext *legacyMOC = [[NSManagedObjectContext alloc]init];
[legacyMOC setPersistentStoreCoordinator:psc];
//fetch all audio recordings from legacyStore
NSArray *legacyRecordingArray = [self fetchAudioRecordingsfrom:legacyMOC];
//fetch all audio recordings form UIMDStore
NSArray *uimdRecordingArray = [self fetchAudioRecordingsfrom:self.managedObjectContext];
//for each audio recording, copy the audio object from legacy and save it to UIMDStore
for (int i = 0; i < legacyRecordingArray.count; i++) {
//save audio to core data
RunningRecord *legacyRR = (RunningRecord *)legacyRecordingArray[i];
RunningRecord *uimdRR = (RunningRecord *)uimdRecordingArray[i];
uimdRR.audioData = [NSData dataWithData:legacyRR.audio.file];
uimdRR.audio.file = nil;
}
if (![self.managedObjectContext save:&error]) {
NSLog(#"Whoops, couldn't save: %#", [error localizedDescription]);
}

Resources