Sì, è possibile accedere ai file archiviati nella memoria esterna. Ci vuole un po 'di hacking e può non essere completamente kosher con l'App Store di Apple, ma puoi farlo facilmente .
Supponendo che abbiamo un NSManagedObject sottoclasse 'media', con una proprietà 'dati' che è stato impostato a 'consente la memorizzazione esterno' nel Data Editor Nucleo:
// Media.h
// Examples
//
// Created by Garrett Shearer on 11/21/12.
// Copyright (c) 2012 Garrett Shearer. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <CoreData/CoreData.h>
@interface CRMMedia : NSManagedObject
@property (nonatomic, retain) NSString * name;
@property (nonatomic, retain) NSData * data;
@end
e una categoria NSString pratico-dandy :
// NSString+Parse.m
// Examples
//
// Created by Garrett Shearer on 11/21/12.
// Copyright (c) 2012 Garrett Shearer. All rights reserved.
//
#import "NSString+Parse.h"
@implementation NSString (Parse)
- (NSString*)returnBetweenString:(NSString *)inString1
andString:(NSString *)inString2
{
NSRange substringRange = [self rangeBetweenString:inString1
andString:inString2];
logger(@"substringRange: (%d, %d)",substringRange.location,substringRange.length);
logger(@"string (self): %@",self);
return [self substringWithRange:substringRange];
}
/*
Return the range of a substring, searching between a starting and ending delimeters
Original Source: <http://cocoa.karelia.com/Foundation_Categories/NSString/Return_the_range_of.m>
(See copyright notice at <http://cocoa.karelia.com>)
*/
/*" Find a string between the two given strings with the default options; the delimeter strings are not included in the result.
"*/
- (NSRange) rangeBetweenString:(NSString *)inString1 andString:(NSString *)inString2
{
return [self rangeBetweenString:inString1 andString:inString2 options:0];
}
/*" Find a string between the two given strings with the given options inMask; the delimeter strings are not included in the result. The inMask parameter is the same as is passed to [NSString rangeOfString:options:range:].
"*/
- (NSRange) rangeBetweenString:(NSString *)inString1 andString:(NSString *)inString2
options:(unsigned)inMask
{
return [self rangeBetweenString:inString1 andString:inString2
options:inMask
range:NSMakeRange(0,[self length])];
}
/*" Find a string between the two given strings with the given options inMask and the given substring range inSearchRange; the delimeter strings are not included in the result. The inMask parameter is the same as is passed to [NSString rangeOfString:options:range:].
"*/
- (NSRange) rangeBetweenString:(NSString *)inString1 andString:(NSString *)inString2
options:(unsigned)inMask range:(NSRange)inSearchRange
{
NSRange result;
unsigned int foundLocation = inSearchRange.location; // if no start string, start here
NSRange stringEnd = NSMakeRange(NSMaxRange(inSearchRange),0); // if no end string, end here
NSRange endSearchRange;
if (nil != inString1)
{
// Find the range of the list start
NSRange stringStart = [self rangeOfString:inString1 options:inMask range:inSearchRange];
if (NSNotFound == stringStart.location)
{
return stringStart; // not found
}
foundLocation = NSMaxRange(stringStart);
}
endSearchRange = NSMakeRange(foundLocation, NSMaxRange(inSearchRange) - foundLocation);
if (nil != inString2)
{
stringEnd = [self rangeOfString:inString2 options:inMask range:endSearchRange];
if (NSNotFound == stringEnd.location)
{
return stringEnd; // not found
}
}
result = NSMakeRange(foundLocation, stringEnd.location - foundLocation);
return result;
}
@end
Ora il suo tempo per un po 'di magia .... Stiamo per creare un metodo categoria che analizza il nome del file dalla [descrizione dei dati] stringa. Quando si opera su un'istanza della sottoclasse Media, "dati" è in realtà un "Riferimento di archiviazione esterno", non un oggetto NSData. Il nome file dei dati effettivi è memorizzato nella stringa descrittiva.
// Media+ExternalData.m
// Examples
//
// Created by Garrett Shearer on 11/21/12.
// Copyright (c) 2012 Garrett Shearer. All rights reserved.
//
#import "Media+ExternalData.h"
#import "NSString+Parse.h"
@implementation Media (ExternalData)
- (NSString*)filePathString
{
// Parse out the filename
NSString *description = [self.data description];
NSString *filename = [description returnBetweenString:@"path = " andString:@" ;"];
// Determine the name of the store
NSPersistentStoreCoordinator *psc = self.managedObjectContext.persistentStoreCoordinator;
NSPersistentStore *ps = [psc.persistentStores objectAtIndex:0];
NSURL *storeURL = [psc URLForPersistentStore:ps];
NSString *storeNameWithExt = [storeURL lastPathComponent];
NSString *storeName = [storeNameWithExt stringByDeletingPathExtension];
// Generate path to the 'external data' directory
NSString *documentsPath = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject] path];
NSString *pathComponentToExternalStorage = [NSString stringWithFormat:@".%@_SUPPORT/_EXTERNAL_DATA",storeName];
NSString *pathToExternalStorage = [documentsPath stringByAppendingPathComponent:pathComponentToExternalStorage];
// Generate path to the media file
NSString *pathToMedia = [pathToExternalStorage stringByAppendingPathComponent:filename];
logger(@"pathToMedia: %@",pathToMedia);
return pathToMedia;
}
- (NSURL*)filePathUrl
{
NSURL *urlToMedia = [NSURL fileURLWithPath:[self filePathString]];
return urlToMedia;
}
@end
Ora si ha un percorso NSString e un percorso NSURL per il file. GIOIA !!!
Qualcosa di cui prendere atto, ho avuto problemi nel caricare film con questo metodo ... ma ho anche trovato una soluzione alternativa. Sembra che MPMoviePlayer non acceda ai file in questa directory, quindi la soluzione è stata copiare temporaneamente il file nella directory dei documenti e riprodurlo. Quindi eliminare la copia temporanea quando scarico la vista:
- (void)viewDidLoad
{
[super viewDidLoad];
[self copyTmpFile];
}
- (void)viewDidUnload
{
logger(@"viewDidUnload");
[_moviePlayer stop];
[_moviePlayer.view removeFromSuperview];
[self cleanupTmpFile];
[super viewDidUnload];
}
- (NSString*)tmpFilePath
{
NSString *documentsPath = [[[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory
inDomains:NSUserDomainMask] lastObject] path];
NSString *tmpFilePath = [documentsPath stringByAppendingPathComponent:@"temp_video.m4v"];
return tmpFilePath;
}
- (void)copyTmpFile
{
NSString *tmpFilePath = [self tmpFilePath];
NSFileManager *mgr = [NSFileManager defaultManager];
NSError *err = nil;
if([mgr fileExistsAtPath:tmpFilePath])
{
[mgr removeItemAtPath:tmpFilePath error:nil];
}
[mgr copyItemAtPath:_media.filePathString toPath:tmpFilePath error:&err];
if(err)
{
logger(@"error: %@",err.description);
}
}
- (void)cleanupTmpFile
{
NSString *tmpFilePath = [self tmpFilePath];
NSFileManager *mgr = [NSFileManager defaultManager];
if([mgr fileExistsAtPath:tmpFilePath])
{
[mgr removeItemAtPath:tmpFilePath error:nil];
}
}
Buona fortuna!
Bella risposta, grazie. Non sono molto entusiasta di gestire i file da solo e di monitorare gli ID solo tramite i dati principali, perché eliminare la gestione manuale dei file è stata una delle cose principali che mi ha fatto prendere in considerazione la possibilità di riscrivere i dati di base in primo luogo.E toccare l'API con 'UIManagedDocument' sembra troppo impreciso, troppo lontano dai casi d'uso previsti per farmi sentire al sicuro. – zoul
Impossibile capire UIManagedDocument gestire il contenuto aggiuntivo. Come posso cancellare BLOB, per esempio? – Shmidt