gpt4 book ai didi

objective-c - 我可以访问用于 Core Data 中外部二进制存储的文件吗?

转载 作者:技术小花猫 更新时间:2023-10-29 11:04:30 24 4
gpt4 key购买 nike

我正在开发媒体数据库应用程序。我有一个带有数据存储的自定义模型,并考虑将其重写为 Core Data。我特别感兴趣的一个用例是电影存储。我将电影文件存储在数据库中,但媒体框架只能从文件(而不是数据)中读取电影。

Core Data 提供了一种称为“外部二进制存储”的便捷功能,其中实体数据不存储在数据库中,而是存储在外部文件中。这对 Core Data API 用户是透明的。我的问题是,我能否获得外部文件的路径,以便我可以使用 Core Data 存储电影,然后轻松地从其 Core Data 外部文件加载它?

最佳答案

是的,您可以访问存储在外部存储中的文件。这需要一些技巧,而且可能与 Apple 的 App Store 不完全一致,但您可以相当轻松地做到这一点。

假设我们有一个 NSManagedObject 子类“媒体”,其“数据”属性已在核心数据编辑器中设置为“允许外部存储”:

//  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

还有一个方便的 NSString 类别:

//  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

现在是施展魔法的时候了……我们将创建一个 Category 方法来从 [data description] 字符串中解析文件名。在 Media 子类的实例上操作时,'data' 实际上是一个'External Storage Reference',而不是 NSData 对象。实际数据的文件名存储在描述字符串中。

//  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

现在你有了文件的 NSString 路径和 NSURL 路径。 快乐!!!

需要注意的一点是,我在使用这种方法加载电影时遇到了问题...但我也想出了一个解决方法。看来MPMoviePlayer不会访问这个目录下的文件,所以解决方法是暂时把文件复制到documents目录下,然后播放。然后在我卸载 View 时删除临时副本:

- (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];
}
}

祝你好运!

关于objective-c - 我可以访问用于 Core Data 中外部二进制存储的文件吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10222632/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com