Có, bạn CÓ THỂ truy cập các tệp được lưu trữ trong Bộ nhớ ngoài. Phải mất một chút hack, và có thể không hoàn toàn kosher với App Store của Apple, nhưng bạn có thể làm điều đó khá một cách dễ dàng.
Giả sử chúng ta có một NSManagedObject Subclass 'Media', với một tài sản 'dữ liệu' đã được thiết lập để 'Cho phép lưu trữ bên ngoài' trong Core Data Editor:
// 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
Và một loại NSString tiện dụng-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
Bây giờ là lúc dùng một số phép thuật .... Chúng ta sẽ tạo phương pháp Phân loại phân tích tên tệp từ chuỗi [mô tả dữ liệu]. Khi hoạt động trên một thể hiện của lớp con Media, 'dữ liệu' thực sự là 'Tham chiếu bộ nhớ ngoài', không phải là một đối tượng NSData. Tên tệp của dữ liệu thực được lưu trữ trong chuỗi mô tả.
// 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
Bây giờ bạn có đường dẫn NSString và đường dẫn NSURL vào tệp. JOY !!!
Một điều cần lưu ý là tôi đã gặp phải sự cố khi tải phim bằng phương pháp này ... nhưng tôi cũng đã đưa ra giải pháp. Có vẻ như MPMoviePlayer sẽ không truy cập các tệp trong thư mục này, do đó giải pháp là tạm thời sao chép tệp vào thư mục tài liệu và phát tệp đó. Sau đó xóa bản sao tạm thời khi tôi bỏ chế độ xem của tôi:
- (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];
}
}
Chúc may mắn!
Câu trả lời hay, cảm ơn bạn. Tôi không muốn tự xử lý các tệp và chỉ theo dõi các ID thông qua Dữ liệu cốt lõi, vì việc loại bỏ quản lý tệp thủ công là một trong những điều chính khiến tôi cân nhắc viết lại dữ liệu cốt lõi ngay từ đầu.Và khai thác vào API thông qua 'UIManagedDocument' cảm thấy quá hung hăng, quá xa so với các trường hợp sử dụng dự kiến để tôi cảm thấy an toàn về nó. – zoul
Không thể hiểu được UIManagedDocument xử lý nội dung bổ sung. Làm cách nào để xóa blob, ví dụ:? – Shmidt