从新的Photos.app拖动图片时,作为拖动信息的一部分,粘贴板中不会传递任何URL.我的应用已正确处理从例如iPhoto,Photo Booth,Aperture,…
我尝试从Photos.app拖动图片:Finder或Pages处理正确,但不是TextEdit或预览. Photos.app与存储在其库中的图片的工作方式似乎有所不同.
解决方法
在深入了解NSPasteboard并逐步浏览应用程序之后,我意识到Photos.app正在粘贴板中传递“承诺文件”,并在Apple的邮件列表中找到了这个帖子,其中包含一些答案:
http://prod.lists.apple.com/archives/cocoa-dev/2015/Apr/msg00448.html
以下是我在处理文件拖放到文档中的类中最终解决它的方法.该类是一个视图控制器,它处理通常的拖放方法,因为它位于响应器链中.
- (BOOL)hasFileURLOrPromisedFileURLWithDraggingInfo:(id <NSDraggingInfo>)sender { NSArray *relevantTypes = @[@"com.apple.pasteboard.promised-file-url",@"public.file-url"]; for(NSPasteboardItem *item in [[sender draggingPasteboard] pasteboardItems]) { if ([item availableTypeFromArray:relevantTypes] != nil) { return YES; } } return NO; }
- (NSURL *)fileURLWithDraggingInfo:(id <NSDraggingInfo>)sender { NSPasteboard *pasteboard = [sender draggingPasteboard]; NSDictionary *options = [NSDictionary dictionaryWithObject:@YES forKey:NSPasteboardURLReadingFileURLsOnlyKey]; NSArray *results = [pasteboard readobjectsForClasses:[NSArray arrayWithObject:[NSURL class]] options:options]; return [results lastObject]; }
最后是用于处理drop的方法.这不完全是我的代码,因为我简化了拖动到便利方法的内部处理,允许我隐藏特定于应用程序的部分.我还有一个特殊的类来处理文件系统事件FileSystemEventCenter作为练习留给读者.此外,在这里介绍的情况下,我只处理拖动一个文件.您必须根据自己的情况调整这些部件.
- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender { if ([self hasFileURLOrPromisedFileURLWithDraggingInfo:sender]) { [self updateAppearanceWithDraggingInfo:sender]; return NSDragOperationcopy; } else { return NSDragOperationNone; } } - (NSDragOperation)draggingUpdated:(id <NSDraggingInfo>)sender { return [self draggingEntered:sender]; } - (void)draggingExited:(id <NSDraggingInfo>)sender { [self updateAppearanceWithDraggingInfo:nil]; } - (void)draggingEnded:(id <NSDraggingInfo>)sender { [self updateAppearanceWithDraggingInfo:nil]; } - (BOOL)prepareForDragOperation:(id <NSDraggingInfo>)sender { return [self hasFileURLOrPromisedFileURLWithDraggingInfo:sender]; } - (BOOL)performDragOperation:(id <NSDraggingInfo>)sender { // promised URL NSPasteboard *pasteboard = [sender draggingPasteboard]; if ([[pasteboard types] containsObject:NSFilesPromisePboardType]) { // promised files have to be created in a specific directory Nsstring *tempPath = [NstemporaryDirectory() stringByAppendingPathComponent:[[NSUUID UUID] UUIDString]]; if ([[NSFileManager defaultManager] createDirectoryAtPath:tempPath withIntermediateDirectories:NO attributes:nil error:NULL] == NO) { return NO; } // the files will be created later: we keep an eye on that using filesystem events // `FileSystemEventCenter` is a wrapper around FSEvent NSArray *filenames = [sender namesOfPromisedFilesDroppedAtDestination:[NSURL fileURLWithPath:tempPath]]; DLog(@"file names: %@",filenames); if (filenames.count > 0) { self.promisedFileNames = filenames; self.directoryForPromisedFiles = tempPath.stringByStandardizingPath; self.targetForPromisedFiles = [self dropTargetForDraggingInfo:sender]; [[FileSystemEventCenter defaultCenter] addobserver:self selector:@selector(promisedFilesUpdated:) path:tempPath]; return YES; } else { return NO; } } // URL already here NSURL *fileURL = [self fileURLWithDraggingInfo:sender]; if (fileURL) { [self insertURL:fileURL target:[self dropTargetForDraggingInfo:sender]]; return YES; } else { return NO; } } - (void)promisedFilesUpdated:(FDFileSystemEvent *)event { dispatch_async(dispatch_get_main_queue(),^ { if (self.directoryForPromisedFiles == nil) { return; } Nsstring *eventPath = event.path.stringByStandardizingPath; if ([eventPath hasSuffix:self.directoryForPromisedFiles] == NO) { [[FileSystemEventCenter defaultCenter] removeObserver:self path:self.directoryForPromisedFiles]; self.directoryForPromisedFiles = nil; self.promisedFileNames = nil; self.targetForPromisedFiles = nil; return; } for (Nsstring *fileName in self.promisedFileNames) { NSURL *fileURL = [NSURL fileURLWithPath:[self.directoryForPromisedFiles stringByAppendingPathComponent:fileName]]; if ([[NSFileManager defaultManager] fileExistsAtPath:fileURL.path]) { [self insertURL:fileURL target:[self dropTargetForDraggingInfo:sender]]; [[FileSystemEventCenter defaultCenter] removeObserver:self path:self.directoryForPromisedFiles]; self.directoryForPromisedFiles = nil; self.promisedFileNames = nil; self.targetForPromisedFiles = nil; return; } } }); }