Я нашел решение этой проблемы.Тем не менее, я думаю, что это не очень хорошо.
Во время тестирования я обнаружил, что при удалении расширения файла, UIDocumentInteractionController
будет показывать приложения в зависимости от UTI
, который я указал.При отправке файла в целевое приложение ничего не произойдет.Я пришел к выводу, что для окончательной отправки мне нужно расширение файла.
Мой подход заключался в изменении свойства URL
перед отправкой файла в целевое приложение и предоставлении ему того же файла, но с расширением файла.целевое приложение принимает.Тем не менее, мое приложение просто упало.Я профилировал его с помощью Instruments и обнаружил, что проблема была в UIDocumentInteractionController
перевыпуске некоторого прокси-объекта.Я также увидел, что окончательный перевыпуск был вызван методом _invalidate
из категории UIDocumentInteractionController(Private)
, который освободил объект.
Поскольку категории не могут быть переопределены другими категориями, я решил изменить метод категории с помощью моегособственная реализация, проверяющая, содержит ли URL расширение файла, или перенаправляет вызов на оригинальный метод _invalidate
или просто ничего не делает.
В следующих кодах показано, что я сделал:
#include <objc/runtime.h>
@interface UIDocumentInteractionController(InvalidationRedirect)
-(void)_invalidateMY;
+(void)load;
void Swizzle(Class c, SEL orig, SEL newSEL);
@end
@implementation UIDocumentInteractionController(InvalidationRedirect)
void Swizzle(Class c, SEL orig, SEL newSEL)
{
Method origMethod = class_getInstanceMethod(c, orig);
Method newMethod = class_getInstanceMethod(c, newSEL);
if(class_addMethod(c, orig, method_getImplementation(newMethod), method_getTypeEncoding(newMethod)))
class_replaceMethod(c, newSEL, method_getImplementation(origMethod), method_getTypeEncoding(origMethod));
else
method_exchangeImplementations(origMethod, newMethod);
}
-(void)_invalidateMY{
@synchronized(self) {
if(![[[[self.URL lastPathComponent] componentsSeparatedByString:@"."] lastObject] isEqualToString:@"extension"]) {
[self _invalidateMY];
}
}
}
+(void)load
{
Swizzle([UIDocumentInteractionController class], @selector(_invalidate), @selector(_invalidateMY));
}
@end
Этот код заменяет оригинальный метод _invalidate
на _invalidateMY
, в результате каждый вызов _invalidate
вызывает _invalidateMY
ии наоборот.
Следующий код показывает, как я обрабатываю UIDocumentInteractionController
:
// create a file without extension
NSString *fileName = @"myFile";
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSURL* target = [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@/%@", documentsDirectory, fileName]];
if([[@"THIS IS JUST A TEST STRING" dataUsingEncoding:NSUTF8StringEncoding] writeToURL:target atomically:NO]) {
NSLog(@"file written successfully");
}else {
NSLog(@"Error.. file writing failed");
}
UIDocumentInteractionController* dic = [UIDocumentInteractionController interactionControllerWithURL:target];
[dic retain];
dic.delegate = self;
// set the UTI to the known UTI we want to list applications for
dic.UTI = @"com.mycomp.a";
[dic presentOpenInMenuFromRect:CGRectZero inView:superController.view animated:YES];
И этот код показывает метод делегата UIDocumentInteractionController
, который обменивается URL:
- (void)documentInteractionController:(UIDocumentInteractionController *)controller willBeginSendingToApplication:(NSString *)application
{
NSFileManager *fileMgr = [NSFileManager defaultManager];
NSError *error;
NSURL* newTarget = [NSURL URLWithString:[NSString stringWithFormat:@"%@.extension", controller.URL]];
// rename file to file with extension
if (![fileMgr moveItemAtURL:controller.URL toURL:newTarget error:&error] && error) {
NSLog(@"Error moving file: %@", [error localizedDescription]);
}
@synchronized(controller) {
//exchange URL with URL+extension
controller.URL = newTarget; //<- this results in calling _invalidate
}
NSLog(@"%@", [NSString stringWithContentsOfURL:controller.URL encoding:NSUTF8StringEncoding error:nil]);
}
Это решение работает, но, на мой взгляд, это грязный взлом, должно быть лучшее решение.