NKAssetDownload destinationURL does not exist as file or directory - nsurlconnection

I'm trying to migrate to NewsstandKit to benefit from background download.
I'm being able to start the NKAssetDownload and set a delegate. But when it comes to get the downloaded content I'm not able to get it from the file system.
I'm querying a CMS for content with certain parameters and it returns a file download. The download progresses normally BUT the file is nowhere to be found afterwards.
This is the code that corresponds to the download delegate:
- (void)connectionDidFinishDownloading:(NSURLConnection *)connection destinationURL:(NSURL *)destinationURL {
#if DEBUG
NSLog(#"NewsstandTracker.m connectionDidFinishDownloading destinationURL:%#",destinationURL);
NSLog(#"========= destination url contents =======");
NSFileManager *manager = [[[NSFileManager alloc] init] autorelease];
NSError *error = nil;
BOOL isdir = 0;
BOOL exists = [manager fileExistsAtPath:[destinationURL absoluteString] isDirectory:&isdir];
NSLog(#"file exists: %d isDir:%d",exists,isdir);
NSLog(#"error: %#",error);
NSString *f = [[[assetDownload URLRequest] URL] lastPathComponent];
NSDirectoryEnumerator * enumerator = [manager enumeratorAtPath:[[destinationURL absoluteString]stringByAppendingPathComponent:f]];
for (NSString *url in enumerator) {
NSLog(#"%#",url);
}
NSLog(#"======= contentURL contents =======");
manager = [[[NSFileManager alloc] init] autorelease];
NSDirectoryEnumerator * en = [manager enumeratorAtPath:[[[self getNewsstandIssue] contentURL] absoluteString]];
for (NSString *url in en) {
NSLog(#"%#",url);
}
#endif
//do more stuff according to NewsstandKit docs
This is the output of the console
2012-01-02 16:01:45.843[499:707] NewsstandKit: cleaning up abandoned asset downloads: (
"<NKAssetDownload: 0x36dc510> -> {identifier: '75F48F44-ADF9-4F83-ABF6-5C03F57524C1/508E80A2-A8AA-4DD1-A979-715395E4E8DD' request: <NSURLRequest http://server-content/getFreeIssue/a_product_id> downloading: NO}"
)
2012-01-02 16:02:43.613[499:707] NewsstandTracker.m connectionDidFinishDownloading destinationURL:file://localhost/private/var/mobile/Applications/992490C5-2607-4942-B06D-4EE9CD6226E4/Library/Caches/bgdl-499-2e4c509b06864f5c.issue23
2012-01-02 16:02:43.614[499:707] ========= destination url contents =======
2012-01-02 16:02:43.614[499:707] file exists: 0 isDir:0
2012-01-02 16:02:43.615[499:707] error: (null)
2012-01-02 16:02:43.616 GSMagazine[499:707] ======= contentURL contents =======
It seem that somehow is clearing up the download before I can even do something with it.
Any clues?

Pacu
Try using [destinationURL path] instead of [destinationURL absoluteString]. The file manager is expecting a path not a URL in string format

This is the same problem I faced after moving to NewsStand download. iOS cancel any pending downloads which you do not start again when application starts. This should be done in didFinishLaunchingWithOptions method
NSUInteger count = [[NKLibrary sharedLibrary] downloadingAssets].count;
for(NSUInteger i = 0 ; i < count ; i++)
{
MAZDebugLog(#"We have some pending downloads");
NKAssetDownload *asset = [[[NKLibrary sharedLibrary] downloadingAssets] objectAtIndex:i];
[asset downloadWithDelegate:self];
}

You need to restore downloads:
NKLibrary *nkLib = [NKLibrary sharedLibrary];
for(NKAssetDownload *asset in [nkLib downloadingAssets]) {
NSLog(#"Asset to downlaod: %#",asset);
[asset downloadWithDelegate:Downloader];
}
in the UIApplication's didFinishLaunchingWithOptions.
Unfortunately for me it works only before UIView and Controller's initializing. I've tried to put this code to the applicationDidBecomeActive but it doesn't work properly when app runs offline.

Related

macOS 10.13: "Scheduling the NSURLDownload loader is no longer supported."

Running my macOS app in macOS 10.13, I see printed to the console:
Scheduling the NSURLDownload loader is no longer supported.
What does this mean?
The Sparkle Updater seems to be the culprit in the instances I have found. I guess the Sparkle dev team will be on to it and hopefully we'll no longer see the message after Sparkle is updated.
It appears to mean You have just created an instance of the deprecated class NSURLDownload.
To show this, create a new Cocoa command-line tool project in Xcode and replace the code in main.m with the following:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSURL* url = [[NSURL alloc] initWithString:#"https://example.com"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url
cachePolicy:NSURLRequestReloadIgnoringCacheData
timeoutInterval:30.0];
NSLog(#"Will print strange sentence to console") ;
[[NSURLDownload alloc] initWithRequest:request
delegate:nil];
NSLog(#"Did print strange sentence to console") ;
}
return 0;
}
Build and run. I get the following result in console (timestamps removed):
Will print strange sentence to console:
Scheduling the NSURLDownload loader is no longer supported.
Did print strange sentence to console
I would say the "fix" is to replace the deprecated NSURLDownload with NSURLSession.
You can correct it directly in the source code for Sparkle. Update SUAppcast.m file at line 82 by replace the NSURLDownload with the following:
NSURLSessionDownloadTask *downloadTask = [[NSURLSession sharedSession] downloadTaskWithRequest:request completionHandler:^(NSURL *location, __unused NSURLResponse *response, NSError *error) {
if (location) {
NSString *destinationFilename = NSTemporaryDirectory();
if (destinationFilename) {
// The file will not persist if not moved, Sparkle will remove it later.
destinationFilename = [destinationFilename stringByAppendingPathComponent:#"Appcast.xml"];
NSFileManager *fileManager = [NSFileManager defaultManager];
NSError *anError = nil;
NSString *fromPath = [location path];
if ([fileManager fileExistsAtPath:destinationFilename])
[fileManager removeItemAtPath:destinationFilename error:&anError];
BOOL fileCopied = [fileManager moveItemAtPath:fromPath toPath:destinationFilename error:&anError];
if (fileCopied == NO) {
[self reportError:anError];
} else {
self.downloadFilename = destinationFilename;
dispatch_async(dispatch_get_main_queue(), ^{
[self downloadDidFinish:[[NSURLDownload alloc] init]];
});
}
}
} else {
[self reportError:error];
}
}];
[downloadTask resume];

non-persistence of object written to documentsDirectory - is

-- a question about how to make an object that is saved to the documents directory persist on the drive and be recoverable after the iDevice is rebooted.
Here's my problem. I make a data object with NSCoding and fill it with data. I write it to the documentsDirectory each time the data in the object are updated. I stop the app and start the app again, and my data object persists, with all of its data. But if I reboot the iPhone the code I wrote to recover and read the data object fails.
The code I wrote originally used only a NSString for the file path. It worked well under ios7 but it fails under ios8.
Reading up on things, I found this clue from the Apple documentation:
"Important: Although they are safe to use while your app is running, file reference URLs are not safe to store and reuse between launches of your app because a file’s ID may change if the system is rebooted. If you want to store the location of a file persistently between launches of your app, create a bookmark as described in Locating Files Using Bookmarks."
So I rewrote my ios7 file open and file close methods so they no longer use strings or urls but get their strings and urls from a bookmark that is saved using NSUserDefaults. Same problem: everything works fine so long as I do not power off the phone, but all is lost once I do. I am not able to solve this.
Here is my current series of steps. First I either determine (or if it already exists in NSUsrDefaults, I recover) the absolute path to the documentsDirectory, using a bookmark:
+ (NSString*) getGeoModelAbsolutePath
{
NSString *path;
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
NSURL *documentsDirectoryBookmarkURL;
NSData* documentsDirectoryBookmark = [userDefaults objectForKey:#"documentDirectoryBookmark"];
if(documentsDirectoryBookmark == nil)
{
documentsDirectoryBookmarkURL = [self getDocumentsDirectoryURL];
documentsDirectoryBookmark = [self bookmarkForURL:documentsDirectoryBookmarkURL];
}
documentsDirectoryBookmarkURL = [self urlForBookmark:documentsDirectoryBookmark];
path = documentsDirectoryBookmarkURL.path;
path = [path stringByAppendingString:#"/Model.mod"];
return path;
}
using methods modified from my ios7 code (which used only the getDocumentsDirectory method):
+ (NSString *)getDocumentsDirectory
{
NSURL *directory = [self getDocumentsDirectoryURL];
NSString * documentsDirectory = directory.path;
return documentsDirectory;
}
And
+ (NSURL *)getDocumentsDirectoryURL
{
NSURL *directory = [[[NSFileManager defaultManager]
URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask]
lastObject];
return directory;
}
And
+ (NSData*)bookmarkForURL:(NSURL*)url {
NSError* theError = nil;
NSData* bookmark = [url bookmarkDataWithOptions:NSURLBookmarkCreationSuitableForBookmarkFile
includingResourceValuesForKeys:nil
relativeToURL:nil
error:&theError];
if (theError || (bookmark == nil)) {
// Handle any errors.
return nil;
}
return bookmark;
}
So now I have a NSString path with the model filename that I can use to get to the GeoModel
- (GeoModel*) openGeoModel
{
GeoModel *geoModel;
NSString* documentsDirectoryGeoModel =[FileManager getGeoModelAbsolutePath];
if([FileManager fileExistsAtAbsolutePath:documentsDirectoryGeoModel])
{
NSData* data = [NSData dataWithContentsOfFile: documentsDirectoryGeoModel]; //]documentsDirectoryGeoModel];
geoModel = [NSKeyedUnarchiver unarchiveObjectWithData: data];
NSString *unarchivedGeoModelVersion = geoModel.geoModel_VersionID;
if(![unarchivedGeoModelVersion isEqual: currentGeoModelVersion])
{
[FileManager deleteFile:documentsDirectoryGeoModel];
geoModel = [GeoModel geoModelInit];
[Utilities setGeoProjectCounter:0];
}
}
else
{
geoModel = [GeoModel geoModelInit];
}
[FileManager saveGeoModel];
return geoModel;
}
Which I then can save to the documentsDirectory as follows:
+ (BOOL)saveGeoModel
{
NSError *error = nil;
NSString *path = [self getGeoModelAbsolutePath];
[NSKeyedArchiver archiveRootObject:appDelegate.currentGeoModel toFile:path];
NSData* encodedData = [NSKeyedArchiver archivedDataWithRootObject: appDelegate.currentGeoModel];
BOOL success = [encodedData writeToFile: path options:NSDataWritingAtomic error:&error];
return success;
}
Which is always successful -- but is persistent only if I do not turn off the device! I am not making any progress with this: Any help would be much appreciated!
Thanks in advance
Tim Redfield
There. I think it is answered -- unless someone else has a comment on how to improve the above listings, they DO work as they ought to!

Cannot record movie using AVCaptureMovieFileoutput

I trying to record a video and I'm getting the error like
Cannot record to URL <#file url> because it is not a file URL.
I define the destination url as follows:
NSString *Path = [[NSString alloc] init];
Path = #"/Users/me/Documents/My fols/recording_try/newMovie.mov";
NSURL *dest = [[NSURL alloc] initWithString:[Path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
Then after creating the session, input and output objects. I tried recording like this.
mMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init] ;
[mSession addOutput:mMovieFileOutput];
[mMovieFileOutput startRecordingToOutputFileURL:dest recordingDelegate:self];
I have started running the session, tried using begin and comitconfiguration, etc. But every time I run I get an error like:
[AVCaptureMovieFileOutput startRecordingToOutputFileURL:recordingDelegate:] - Cannot record to URL /Users/me/Documents/My%20fols/recording_try/newMovie.mov because it is not a file URL.
I don't know where I'm going wrong... Could someone please help???
Thanks in Advance...
Just change your NSURL configuration to conform to file URL type
Something like this:
NSURL *dest = [[NSURL alloc] initFileURLWithPath:<#(NSString *)#>]
Try something like this:
// variable names should start with lower case letters
// also, let's do as much as we can with auto-released objects
// so we don't have to worry about leaking (if we're not using ARC)
NSString *path = [NSString stringWithString: #"/Users/me/Documents/My fols/recording_try"];
NSURL *dest = [NSURL URLWithString:[path stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
if(dest == nil)
{
NSLog( #"does not appear to be a valid NSURL object" );
return;
}
NSError * error = nil;
if([[NSFileManager defaultManager] createDirectoryAtURL: dest withIntermediateDirectories: YES attributes: nil error: &error] == YES)
{
dest = [dest URLByAppendingPathComponent: #"newMovie.mov"];
// now you can create the session plus input and output objects
// within this block
} else {
NSLog( #"was not able to create the directory which contains path %# - error is %#", path, [error localizedDescription] );
}

How to download file to machine without storing information on iCloud?

How to download file without storing information on iCloud?
My App is the App for downloading pdf to the machine. It was rejected by Apple from the reason that "In particular, we found that after downloading two issues, your app stores 56.5 MB. To check how much data your app is storing: - Go to Settings> iCloud. > Storage & Backup> Manage Storage ". I would like to know how to write if the information is not stored on iClound.
My Script :
- (void) DownloadFile:(NSURL *)url Name:(NSString *)name Folder:(NSString *)folder{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSData *myData = [NSData dataWithContentsOfURL:url];
NSString *file = [NSString stringWithFormat:#"%#/%#",folder,name];
if(![fileManger fileExistsAtPath:file]){
[fileManger createFileAtPath:file contents:myData attributes:nil];
}
}
Just store the PDFs in the application document directory. You can still keep track of which files have been downloaded on which devices by using the iCloud's key-value store. However, the files to be downloaded onto the device would have to come from non-iCloud servers.
You will probably also have to implement a UI for showing which files have been downloaded and which are available and for deleting them from the device if desired.
OH Thank you it complete
#import <sys/xattr.h>
....
-(BOOL) addSkipBackupAttributeToItemAtURL:(NSURL *)URL{
if(&NSURLIsExcludeFromBackupKey == nil){
const char* filePath = [[URL path] fileSystemRepresentation];
const char* attrName = "com.apple.MobileBackup";
u_int8_t attrValue = 1;
int result = setxattr(filePath, attrName, &attrValue, sizeof(attrValue), 0, 0);
return result == 0;
}else{
return [URL setResourceValue:[NSNumber numberWithBool:YES] forKey:NSURLIsExcludedFromBackupKey error:nil];
}
}
- (void) DownloadFile:(NSURL *)url Name:(NSString *)name Folder:(NSString *)folder{
NSFileManager *fileManager = [NSFileManager defaultManager];
NSURL *curfile = [NSURL fileURLWithPath:folder];
[self addSkipBackupAttributeToItemAtURL:curfile];
NSData *myData = [NSData dataWithContentsOfURL:url];
NSString *file = [NSString stringWithFormat:#"%#/%#",folder,name];
if(![fileManger fileExistsAtPath:file]){
[fileManger createFileAtPath:file contents:myData attributes:nil];
}
}
Thank you

Cocoa: Getting image file metadata

I am building an app that allows users to select a file and/or folder either locally or across the network and list the contents of that selection in a NSTableView after some filtering (no hidden files, only accepting .tif, .eps). The user can then select a file name from the list and then have the files metadata shown to them. At least that is what I want to happen. Right now I am getting null returned for the metadata. Here's my code:
- (void)tableViewSelectionDidChange:(NSNotification *)notif {
NSDictionary* metadata = [[NSDictionary alloc] init];
//get selected item
NSString* rowData = [fileList objectAtIndex:[tblFileList selectedRow]];
//set path to file selected
NSString* filePath = [NSString stringWithFormat:#"%#/%#", objPath, rowData];
//declare a file manager
NSFileManager* fileManager = [[NSFileManager alloc] init];
//check to see if the file exists
if ([fileManager fileExistsAtPath:filePath] == YES) {
//escape all the garbage in the string
NSString *percentEscapedString = (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL, (CFStringRef)filePath, NULL, NULL, kCFStringEncodingUTF8);
//convert path to NSURL
NSURL* filePathURL = [[NSURL alloc] initFileURLWithPath:percentEscapedString];
NSError* error;
NSLog(#"%#", [filePathURL checkResourceIsReachableAndReturnError:error]);
//declare a cg source reference
CGImageSourceRef sourceRef;
//set the cg source references to the image by passign its url path
sourceRef = CGImageSourceCreateWithURL((CFURLRef)filePathURL, NULL);
//set a dictionary with the image metadata from the source reference
metadata = (NSDictionary *)CGImageSourceCopyPropertiesAtIndex(sourceRef,0,NULL);
NSLog(#"%#", metadata);
[filePathURL release];
} else {
[self showAlert:#"I cannot find this file."];
}
[fileManager release];
}
I'm guessing the problem here is the CFURLREF in CGImageSourceCreateWithURL. Instead of NSURL should I be using something else?
Thanks
Here's the path I am passing (logged from filePathURL): file://localhost/Volumes/STORAGE%20SVR/Illustration-Wofford/Illustration%20Pickup/Archive/AL013111_IL_Communication.eps
I can't tell where the "localhost" part in your file URL comes from, but I think that's the culprit. A file url doesn't usually contain a "localhost" part. In your example, it should look like this:
file:///Volumes/STORAGE%20SVR/Illustration-Wofford/Illustration%20Pickup/Archive/AL013111_IL_Communication.eps
But I'm pretty sure you've figured this out by now :)
Update: I stand corrected by Mike's comment: file://localhost/... is the same thing as file:///...!

Resources