Pet*_*e C 5 multithreading objective-c uimanageddocument
这是我关于Stack Overflow的第一个问题,所以如果我打破任何礼仪,请原谅.我也是Objective-C/app创建的新手.
我一直在关注CS193P斯坦福课程,特别是CoreData讲座/演示.在Paul Hegarty的Photomania应用程序中,他以表格视图开始,并在后台填充数据,而不会中断UI流程.我一直在创建一个列出本地区域业务的应用程序(来自返回JSON数据的api).
我根据Paul的照片/摄影师课程创建了类别.类本身的创建不是问题,而是创建它们的地方.
A simplified data structure:
- Section
- Sub-section
- business
- business
- business
- business
- business
- business
Run Code Online (Sandbox Code Playgroud)
我的应用程序以带有几个按钮的UIViewController开始,每个按钮打开相应部分的tableview(这些都工作正常,我试图提供足够的信息,以便我的问题有意义).我调用一个帮助方法来创建/打开UIManagedDocument的URL,该URL基于这个问题.一旦应用程序运行,就会调用它,并且它会快速加载.
我有一个非常类似于Paul的fetchFlickrDataIntoDocument的方法:
-(void)refreshBusinessesInDocument:(UIManagedDocument *)document
{
dispatch_queue_t refreshBusinessQ = dispatch_queue_create("Refresh Business Listing", NULL);
dispatch_async(refreshBusinessQ, ^{
// Get latest business listing
myFunctions *myFunctions = [[myFunctions alloc] init];
NSArray *businesses = [myFunctions arrayOfBusinesses];
// Run IN document's thread
[document.managedObjectContext performBlock:^{
// Loop through new businesses and insert
for (NSDictionary *businessData in businesses) {
[Business businessWithJSONInfo:businessData inManageObjectContext:document.managedObjectContext];
}
// Explicitly save the document.
[document saveToURL:document.fileURL
forSaveOperation:UIDocumentSaveForOverwriting
completionHandler:^(BOOL success){
if (!success) {
NSLog(@"Document save failed");
}
}];
NSLog(@"Inserted Businesses");
}];
});
dispatch_release(refreshBusinessQ);
}
Run Code Online (Sandbox Code Playgroud)
[myFunctions arrayOfBusinesses]只解析JSON数据并返回包含各个业务的NSArray.
我已经在业务创建代码的开头和结尾处使用NSLog运行代码.每个企业都分配了一个部分,创建需要0.006秒,其中有几百个.插入物最终耗时约2秒钟.
帮手方法在这里:
// The following typedef has been defined in the .h file
// typedef void (^completion_block_t)(UIManagedDocument *document);
@implementation ManagedDocumentHelper
+(void)openDocument:(NSString *)documentName UsingBlock:(completion_block_t)completionBlock
{
// Get URL for document -> "<Documents directory>/<documentName>"
NSURL *url = [[[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask] lastObject];
url = [url URLByAppendingPathComponent:documentName];
// Attempt retrieval of existing document
UIManagedDocument *doc = [managedDocumentDictionary objectForKey:documentName];
// If no UIManagedDocument, create
if (!doc)
{
// Create with document at URL
doc = [[UIManagedDocument alloc] initWithFileURL:url];
// Save in managedDocumentDictionary
[managedDocumentDictionary setObject:doc forKey:documentName];
}
// If the document exists on disk
if ([[NSFileManager defaultManager] fileExistsAtPath:[url path]])
{
[doc openWithCompletionHandler:^(BOOL success)
{
// Run completion block
completionBlock(doc);
} ];
}
else
{
// Save temporary document to documents directory
[doc saveToURL:url
forSaveOperation:UIDocumentSaveForCreating
completionHandler:^(BOOL success)
{
// Run compeltion block
completionBlock(doc);
}];
}
}
Run Code Online (Sandbox Code Playgroud)
并在viewDidLoad中调用:
if (!self.lgtbDatabase) {
[ManagedDocumentHelper openDocument:@"DefaultLGTBDatabase" UsingBlock:^(UIManagedDocument *document){
[self useDocument:document];
}];
}
Run Code Online (Sandbox Code Playgroud)
useDocument只是将self.document设置为提供的文档.
我想将此代码更改为以便将数据插入另一个线程中,并且用户仍然可以单击按钮来查看节,而不会导致数据导入挂起UI.
任何帮助将不胜感激我已经在这个问题上工作了几天而无法解决它,即使这里有其他类似的问题.如果您需要任何其他信息,请告诉我们!
谢谢
编辑:
到目前为止,这个问题已经收到一票.如果有办法我可以改进这个问题,或者有人知道我无法找到的问题,请你评论一下如何或在哪里?如果还有其他原因让你失望,请告诉我,因为我无法理解这种消极情绪,并且愿意学习如何做出更好的贡献.
Lor*_*o B 11
有几种方法可以解决这个问题.
因为你正在使用UIManagedDocument你可以利用NSPrivateQueueConcurrencyType初始化一个新的NSManagedObjectContext和performBlock用来做你的东西.例如:
// create a context with a private queue so access happens on a separate thread.
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType:NSPrivateQueueConcurrencyType];
// insert this context into the current context hierarchy
context.parentContext = parentContext;
// execute the block on the queue of the context
context.performBlock:^{
// do your stuff (e.g. a long import operation)
// save the context here
// with parent/child contexts saving a context push the changes out of the current context
NSError* error = nil;
[context save:&error];
}];
Run Code Online (Sandbox Code Playgroud)
从上下文保存时,私有上下文的数据将被推送到当前上下文.保存仅在内存中可见,因此您需要访问主上下文(链接到该主上下文UIDocument)并在那里进行保存(请查看do -a-core-data-parent-managedobjectcontext-need-to-share -a-concurrency-type-wi).
另一种方式(我最喜欢的)是创建一个NSOperation子类并在那里做东西.例如,声明一个NSOperation如下的子类:
//.h
@interface MyOperation : NSOperation
- (id)initWithDocument:(UIManagedDocument*)document;
@end
//.m
@interface MyOperation()
@property (nonatomic, weak) UIManagedDocument *document;
@end
- (id)initWithDocument:(UIManagedDocument*)doc;
{
if (!(self = [super init])) return nil;
[self setDocument:doc];
return self;
}
- (void)main
{
NSManagedObjectContext *moc = [[NSManagedObjectContext alloc] init];
[moc setParentContext:[[self document] managedObjectContext]];
// do the long stuff here...
NSError *error = nil;
[moc save:&error];
NSManagedObjectContext *mainMOC = [[self document] managedObjectContext];
[mainMOC performBlock:^{
NSError *error = nil;
[mainMOC save:&error];
}];
// maybe you want to notify the main thread you have finished to import data, if you post a notification remember to deal with it in the main thread...
}
Run Code Online (Sandbox Code Playgroud)
现在在主线程中,您可以将该操作提供给队列,如下所示:
MyOperation *op = [[MyOperation alloc] initWithDocument:[self document]];
[[self someQueue] addOperation:op];
Run Code Online (Sandbox Code Playgroud)
PS您无法在a的main方法中启动异步操作NSOperation.当main完成后,与运营联代表将不会被调用.要说出真相,但这涉及到处理运行循环或并发行为.
希望有所帮助.
| 归档时间: |
|
| 查看次数: |
2465 次 |
| 最近记录: |