In my project I'm using WSAssetPickerController.
Despite the toolbar not working (not a huge issue), everything is working fine.
I have added a share button in the view controller, but I can't seem to get the UIDocumentInteractionController to get called, I tried copying the same method I'm using for files saved in the apps folder (which works fine). But here it's not.
How the irrelevant Downloads page works:
NSString *fileName = [directoryContents objectAtIndex:indexPath.row];
NSString *path;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
path = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"Downloads"];
path = [path stringByAppendingPathComponent:fileName];
documentController = [[UIDocumentInteractionController alloc] init];
documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]];
[documentController setDelegate:self];
[documentController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
How the images get loaded:
#pragma mark - Fetching Code
- (void)fetchAssets
{
// TODO: Listen to ALAssetsLibrary changes in order to update the library if it changes.
// (e.g. if user closes, opens Photos and deletes/takes a photo, we'll get out of range/other error when they come back.
// IDEA: Perhaps the best solution, since this is a modal controller, is to close the modal controller.
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[self.assetsGroup enumerateAssetsWithOptions:NSEnumerationReverse usingBlock:^(ALAsset *result, NSUInteger index, BOOL *stop) {
if (!result || index == NSNotFound) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.tableView reloadData];
self.navigationItem.title = [NSString stringWithFormat:#"%#", [self.assetsGroup valueForProperty:ALAssetsGroupPropertyName]];
});
return;
}
WSAssetWrapper *assetWrapper = [[WSAssetWrapper alloc] initWithAsset:result];
dispatch_async(dispatch_get_main_queue(), ^{
[self.fetchedAssets addObject:assetWrapper];
});
}];
});
[self.tableView performSelector:#selector(reloadData) withObject:nil afterDelay:0.5];
}
How I load and call the button:
- (void)viewDidLoad
{
self.navigationItem.title = #"Loading";
UIBarButtonItem *shareButton = [[UIBarButtonItem alloc]
initWithBarButtonSystemItem:UIBarButtonSystemItemAction
target:self
action:#selector(shareAction:)];
self.navigationItem.rightBarButtonItem = shareButton;
self.navigationItem.rightBarButtonItem.enabled = NO;
// TableView configuration.
self.tableView.contentInset = TABLEVIEW_INSETS;
self.tableView.separatorColor = [UIColor clearColor];
self.tableView.allowsSelection = NO;
// Fetch the assets.
[self fetchAssets];
}
Should and did select fetched assets
#pragma mark - WSAssetsTableViewCellDelegate Methods
- (BOOL)assetsTableViewCell:(WSAssetsTableViewCell *)cell shouldSelectAssetAtColumn:(NSUInteger)column
{
BOOL shouldSelectAsset = (self.assetPickerState.selectionLimit == 0 ||
(self.assetPickerState.selectedCount < self.assetPickerState.selectionLimit));
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
NSUInteger assetIndex = indexPath.row * self.assetsPerRow + column;
WSAssetWrapper *assetWrapper = [self.fetchedAssets objectAtIndex:assetIndex];
if ((shouldSelectAsset == NO) && (assetWrapper.isSelected == NO))
self.assetPickerState.state = WSAssetPickerStateSelectionLimitReached;
else
self.assetPickerState.state = WSAssetPickerStatePickingAssets;
return shouldSelectAsset;
}
- (void)assetsTableViewCell:(WSAssetsTableViewCell *)cell didSelectAsset:(BOOL)selected atColumn:(NSUInteger)column
{
NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
// Calculate the index of the corresponding asset.
NSUInteger assetIndex = indexPath.row * self.assetsPerRow + column;
WSAssetWrapper *assetWrapper = [self.fetchedAssets objectAtIndex:assetIndex];
assetWrapper.selected = selected;
// Update the state object's selectedAssets.
[self.assetPickerState changeSelectionState:selected forAsset:assetWrapper.asset];
// Update navigation bar with selected count and limit variables
dispatch_async(dispatch_get_main_queue(), ^{
if (self.assetPickerState.selectionLimit) {
self.navigationItem.title = [NSString stringWithFormat:#"%# (%lu/%ld)", [self.assetsGroup valueForProperty:ALAssetsGroupPropertyName], (unsigned long)self.assetPickerState.selectedCount, (long)self.assetPickerState.selectionLimit];
}
});
if (self.assetPickerState.selectedCount == 0) {
self.navigationItem.rightBarButtonItem.enabled = NO;
}
else {
self.navigationItem.rightBarButtonItem.enabled = YES;
}
}
Work needed to below with example from the download code I have used before.
-(void)shareAction:(id)sender {
//Launch UIDocumentInteractionController for selected images
documentController =[[UIDocumentInteractionController alloc]init];
documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath://Code needed here??//]];
documentController.delegate=self;
[documentController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
}
What would be the best practice to do this?
Thanks.
UPDATE 8/4:
-(void)shareAction:(id)sender {
//Launch UIDocumentInteractionController for selected images
if (self.assetPickerState.selectedCount >= 1) {
documentController = [[UIDocumentInteractionController alloc] init];
documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:#"public.image"]];
[documentController setDelegate:self];
[documentController presentOptionsMenuFromRect:CGRectZero inView:self.view animated:YES];
}
}
Returns: Unable to get data for URL: The operation couldn’t be completed. (Cocoa error 260.)
Your interactionControllerWithURL: doesn't seem to be a problem but I have observed that -presentOpenInMenuFromRect: does not show if there are no apps that can open the file.
If your purpose is to share the file, and generally that doesn't mean open the file in the conventional sense, then instead of:
-presentOpenInMenuFromRect:inView:animated:
use
-presentOptionsMenuFromRect:inView:animated:
The former is an OpenInMenu and latter is an OptionsMenu.
For the tiny difference, check my related answer or check Apple doc directly
Example:
//this seems fine
documentController = [UIDocumentInteractionController interactionControllerWithURL:[NSURL fileURLWithPath:path]];
//do this
[documentController presentOptionsMenuFromRect:CGRectZero
inView:self.view
animated:YES];
Also..., just before you present the documentInteractionController, it's good practice to specify the file's UTI so the documentInteractionController can populate itself with the appropriate options that can be performed & the list of all apps that can handle this file:
Example:
//assuming the file is a PDF
[documentController setUTI:#"com.adobe.pdf"];
//or... same thing but a more standardized way would be
[documentController setUTI:(NSString *)kUTTypePDF];
//but for this second style you'll need to add the `MobileCoreServices` framework
//to your project bundle and specify the following in your .h or .m
//#import <MobileCoreServices/MobileCoreServices.h>
Extra: Apple's Uniform Type Identifiers Reference
Related
I am having an interesting little problem using the uiimagepickercontroller and was wondering if anyone has any insight as to what might be happening. Users can take pictures with the camera or pick from the photo library until the cows come home as many times in a row as they like. My issue lies in allowing users to revert back to the original image that shipped with the app. Here is the flow:
Users go the the tableview which shows a thumbnail of the image.
Users navigate to the detail view which shows a larger view of the image.
Users can tap on the image in the detail view to bring up a custom alertcontroller with options to a) use the camera to take a picture, b) use a picture from their library, or c) revert back to the original image.
Users choose either option 'a' or option 'b' to either take a picture or use a picture from the photo library. IF they IMMEDIATELY change their mind about using one of those choices and want to just go back to using the original image, nothing happens! They can snap another picture or choose another image right away, but cannot revert back to the original image right away.
Reverting back to the original image DOES work perfectly when the app has been closed and then opened again. Sometimes it will work if you navigate around to other views within the app and then come back to the detail view where they just added their own image. By why the delay? I've searched around for two weeks but have not found anything resembling my problem or any solutions that help in any way (like reloading the headerview where image is sitting). Any thoughts?
Also I have figured out how to save the image to iCloud by using the documentation but cannot figure out how to retrieve them so there is no code for that. That is entirely different question. The same thing seems to occur even without that code.
Thanks for taking the time to look at this!
Here is some code:
-(void)bookImageTapped:(UIGestureRecognizer *)gesture
{
URBAlertView *changeImageAlertView = [[URBAlertView alloc] initWithTitle:#"Add A New Book Cover Image" message:nil cancelButtonTitle:#"Cancel" otherButtonTitles:#"Use Camera", #"Open Gallery", #"Use Original Photo", nil];
[changeImageAlertView setHandlerBlock:^(NSInteger buttonIndex, URBAlertView *alertView) {
[self checkPermission];
if (PHAuthorizationStatusAuthorized)
{
if(buttonIndex == 0)
{
if ([UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera])
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
UIImagePickerController *pickerController = [[UIImagePickerController alloc] init];
pickerController.sourceType = UIImagePickerControllerSourceTypeCamera;
pickerController.delegate = self;
pickerController.allowsEditing = NO;
pickerController.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypeCamera];
[self presentViewController:pickerController animated:YES completion:nil];
}];
[alertView hide];
}
else
{
NSLog(#"Camera not available");
[alertView hide];
}
}
else if (buttonIndex == 1)
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
UIImagePickerController *pickerController = [[UIImagePickerController alloc] init];
pickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
pickerController.delegate = self;
pickerController.allowsEditing = NO;
pickerController.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:UIImagePickerControllerSourceTypePhotoLibrary];
[self presentViewController:pickerController animated:YES completion:nil];
}];
[alertView hide];
}
else if (buttonIndex == 2)
{
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
[self restoreOriginalPhoto];
}];
[alertView hide];
}
else
{
NSLog(#"button 2 cancel");
[alertView hide];
}
}
}];
[changeImageAlertView show];
}
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(nonnull NSDictionary<NSString *,id> *)info
{
[picker dismissViewControllerAnimated:YES completion:nil];
_book.largeBookImage = [info objectForKey:UIImagePickerControllerOriginalImage];
_book.largeBookImage = [self scaleImage:_book.largeBookImage toSize:CGSizeMake(120, 168)];
_bookImageView.image = _book.largeBookImage;
_book.wasNewImageAdded = YES;
_book.originalImageUsed = NO;
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
[self saveImage:_book.largeBookImage withFileName:_book.bookImageID ofType:#"jpg" inDirectory:documentsDirectory];
}
-(void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[picker dismissViewControllerAnimated:YES completion:nil];
}
-(void)saveImage:(UIImage *)image withFileName:(NSString *)imageName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath
{
if ([[extension lowercaseString] isEqualToString:#"png"])
{
[UIImagePNGRepresentation(image) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", imageName, #"png"]] options:NSAtomicWrite error:nil];
//Create a URL to the local file
NSURL *resourceURL = [NSURL fileURLWithPath:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", imageName, #"png"]]];
if (resourceURL)
{
CKAsset *asset = [[CKAsset alloc] initWithFileURL:resourceURL];
//create a record object
CKRecord *bookCover = [[CKRecord alloc] initWithRecordType:#"Bookcover"];
//set the record's fields
bookCover[#"title"] = _book.title;
bookCover[#"bookImage"] = asset;
/* TO SAVE A RECORD */
//get the public database
CKContainer *appContainer = [CKContainer defaultContainer];
CKDatabase *publicDatabase = [appContainer publicCloudDatabase];
[publicDatabase saveRecord:bookCover completionHandler:^(CKRecord *bookCover, NSError *error) {
if (error)
{
//insert error handling
return;
}
//insert succesfully saved record code
NSLog(#"png record saved after using picker!");
}];
}
}
else if ([[extension lowercaseString] isEqualToString:#"jpg"] || [[extension lowercaseString] isEqualToString:#"jpeg"])
{
[UIImageJPEGRepresentation(image, 1.0) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", imageName, #"jpg"]] options:NSAtomicWrite error:nil];
//Create a URL to the local file
NSURL *resourceURL = [NSURL fileURLWithPath:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", imageName, #"jpg"]]];
if (resourceURL)
{
CKAsset *asset = [[CKAsset alloc] initWithFileURL:resourceURL];
//create a record object
CKRecord *bookCover = [[CKRecord alloc] initWithRecordType:#"Bookcover"];
//set the record's fields
bookCover[#"title"] = _book.title;
bookCover[#"bookImage"] = asset;
/* TO SAVE A RECORD */
//get the public database
CKContainer *appContainer = [CKContainer defaultContainer];
CKDatabase *publicDatabase = [appContainer publicCloudDatabase];
[publicDatabase saveRecord:bookCover completionHandler:^(CKRecord *bookCover, NSError *error) {
if (error)
{
//insert error handling
return;
}
//insert succesfully saved record code
NSLog(#"jpg record saved after using picker!");
}];
}
}
else
{
NSLog(#"Image Save Failed\nExtension: (%#) is not recognized, use (PNG/JPG)", extension);
}
}
- (UIImage *) scaleImage:(UIImage*)image toSize:(CGSize)newSize
{
UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0);
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
-(void)restoreOriginalPhoto
{
NSLog(#"restore photo called");
_book.originalImageUsed = YES;
_book.wasNewImageAdded = NO;
_bookImageView.image = _book.largeBookImage;
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
[self saveImage:_book.largeBookImage withFileName:_book.bookImageID ofType:#"jpg" inDirectory:documentsDirectory];
}
Here is the headerview with the imageview:
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
_headerView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, tableView.frame.size.width, 26)];
_headerView.backgroundColor = [UIColor colorWithRed:8/255.0 green:46/255.0 blue:46/255.0 alpha:0.8];
if (section == 0)
{
_headerView.backgroundColor = [UIColor whiteColor];
_bookImageView = [[UIImageView alloc] initWithFrame:CGRectMake((tableView.frame.size.width - 120)/2, 6, 120, 168)];
_bookImageView.contentMode = UIViewContentModeScaleAspectFit;
if (_book.wasNewImageAdded)
{
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
UIImage * image = [self loadImageWithFileName:_book.bookImageID ofType:#"jpg" inDirectory:documentsDirectory];
_bookImageView.image = image;
}
else
{
_bookImageView.image = _book.largeBookImage;
}
if(_book.originalImageUsed)
{
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
UIImage * image = [self loadImageWithFileName:_book.bookImageID ofType:#"jpg" inDirectory:documentsDirectory];
_bookImageView.image = image;
}
UITapGestureRecognizer *bookImageTouched = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(bookImageTapped:)];
bookImageTouched.numberOfTapsRequired = 1;
[_bookImageView addGestureRecognizer:bookImageTouched];
_bookImageView.userInteractionEnabled = YES;
[_headerView addSubview:_bookImageView];
}
I finally figured it out! It seems that I was confusing xcode with my property names. The code ended up much simpler in the end.
In didFinishPickingMediaWithInfo I created a UIImage and then set it to the bookImageView.image. Later, when I wanted to be able to update the image back to the original image, then I could call the bundle asset, _book.largeBookImage. Voila! The image was able to update immediately.
The most pertinent code is posted below.
-(void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(nonnull NSDictionary<NSString *,id> *)info
{
[picker dismissViewControllerAnimated:YES completion:nil];
_chosenImage = [[UIImage alloc] init];
_chosenImage = [info objectForKey:UIImagePickerControllerOriginalImage];
_bookImageView.image = _chosenImage;
_book.wasNewImageAdded = YES;
_book.originalImageUsed = NO;
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
[self saveImage:_chosenImage withFileName:_book.bookImageID ofType:#"jpg" inDirectory:documentsDirectory];
}
-(void)saveImage:(UIImage *)image withFileName:(NSString *)imageName ofType:(NSString *)extension inDirectory:(NSString *)directoryPath
{
if ([[extension lowercaseString] isEqualToString:#"png"])
{
[UIImagePNGRepresentation(image) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", imageName, #"png"]] options:NSAtomicWrite error:nil];
[self.tableView reloadData];
}
else if ([[extension lowercaseString] isEqualToString:#"jpg"] || [[extension lowercaseString] isEqualToString:#"jpeg"])
{
[UIImageJPEGRepresentation(image, 1.0) writeToFile:[directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.%#", imageName, #"jpg"]] options:NSAtomicWrite error:nil];
[self.tableView reloadData];
}
else
{
//NSLog(#"Image Save Failed\nExtension: (%#) is not recognized, use (PNG/JPG)", extension);
}
}
-(void)restoreOriginalPhoto
{
_book.originalImageUsed = YES;
_book.wasNewImageAdded = NO;
_bookImageView.image = _book.largeBookImage;
_backgroundImage.image = _book.largeBookImage;
}
-(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section
{
if (section == 0)
{
_bookImageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 120, 168)];
_bookImageView.contentMode = UIViewContentModeScaleAspectFit;
_bookImageView.clipsToBounds = YES;
_bookImageView.layer.cornerRadius = 10.0f;
if (_book.wasNewImageAdded)
{
NSString * documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
UIImage * image = [self loadImageWithFileName:_book.bookImageID ofType:#"jpg" inDirectory:documentsDirectory];
_bookImageView.image = image;
}
else
{
_bookImageView.image = _book.largeBookImage;
}
if(_book.originalImageUsed)
{
_bookImageView.image = _book.largeBookImage;
}
}
}
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if(_book.originalImageUsed)
{
_bookImageView.image = _book.largeBookImage;
}
[self.tableView reloadData];
[self.tableView setContentOffset:CGPointZero animated:NO];
}
I have code to show a document as follows:
documentInteractionController = [UIDocumentInteractionController interactionControllerWithURL:self.thisUrl];
NSString *pathExtension = [self.thisUrl pathExtension];
if (pathExtension) {
NSString *UTI = (__bridge NSString*)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)(pathExtension), NULL);
if (UTI) {
documentInteractionController.UTI = UTI;
}
}
documentInteractionController.delegate = self;
[documentInteractionController presentOptionsMenuFromBarButtonItem:shareButton animated:YES];
When the options menu is displayed, it shows a list of apps that can open the document (e.g. Message), along with a list of actions below.
The options menu shows a list actions that is different from the menu shown in e.g., the Mail app.
The main difference is that the Mail app shows a "print" option, while my options menu does not. How do I get the options menu to show the print option?
EDIT:
I did a further test where I implemented the methods:
- (BOOL)documentInteractionController:(UIDocumentInteractionController *)controller canPerformAction:(SEL)action
{
return YES;
}
- (BOOL)documentInteractionController:(UIDocumentInteractionController *)controller performAction:(SEL)action
{
return YES; // or NO, doesn't matter
}
This had the effect of showing the "print", "copy" and "save to camera roll" actions in the popup view. Nothing happened when I tapped them, probably because I didn't properly implement -performAction. I also get a warning in the console log about using legacy methods.
This was a step backwards in some ways because I could no longer print some documents which were able to print correctly with the document interaction controller before I added those methods.
Apple encourage you to use UIActivityViewController. You can easily achieve this with that. However Print option is available only if your sharing content type supports printing. You can see a list of supported activities by data types here
- (IBAction)shareButton:(UIBarButtonItem *)sender
{
NSString *textToShare = #"Text to share";
NSURL *myWebContent = [NSURL URLWithString:#"http://yourpath.com/yourfile.pdf"]; // set your printable file here!
NSData *myData = [NSData dataWithContentsOfURL:myWebContent];
NSArray *objectsToShare = #[textToShare, myData];
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:objectsToShare applicationActivities:nil];
//Add exclusions here
NSArray *excludeActivities = #[UIActivityTypeAirDrop,
UIActivityTypeAssignToContact,
UIActivityTypeSaveToCameraRoll,
UIActivityTypeAddToReadingList,
UIActivityTypePostToFlickr,
UIActivityTypePostToVimeo];
activityVC.excludedActivityTypes = excludeActivities;
[self presentViewController:activityVC animated:YES completion:nil];
}
I got this working using the QuickLook framework. I don't know why the "print" option sometimes doesn't appear for the document interaction controller, but then again, apparantly noone else does either.
The QuickLook framework supports previewing some document types but not all, so I left in my previous view controller and the document interaction controller for those unsupported types.
Below is a snippet of my working code.
#interface PreviewItemDataSource ()
#property (nonatomic, retain) NSURL* item;
#end
#implementation PreviewItemDataSource
#synthesize item=_item;
+(PreviewItemDataSource*)dataSourceWithItem:(NSURL*)item
{
PreviewItemDataSource *source = [[PreviewItemDataSource alloc] init];
source.item = item;
return source;
}
-(NSInteger) numberOfPreviewItemsInPreviewController:(QLPreviewController*)controller {
return 1;
}
- (id<QLPreviewItem>) previewController:(QLPreviewController*)controller previewItemAtIndex:(NSInteger)index {
return self.item;
}
#end
#interface AppDelegate ()
#property (nonatomic, retain) PreviewItemDataSource *dataSource;
#end
...
-(void) openExternalFile:(NSString*) filePath withDelegate:(id<ChildBrowserDelegate>)delegate
{
if ([filePath length] == 0)
return;
NSURL *item = [NSURL URLWithString:filePath];
if (item && [QLPreviewController canPreviewItem:item]) {
[self openQuickLookForItem:item];
} else {
// previous method unchanged
}
}
- (void) openQuickLookForItem:(NSURL*)item {
QLPreviewController *controller = [[QLPreviewController alloc] init];
PreviewItemDataSource *dataSource = [PreviewItemDataSource dataSourceWithItem:item];
controller.dataSource = dataSource;
controller.modalPresentationStyle = UIModalPresentationFullScreen;
[controller setCurrentPreviewItemIndex:0];
[self.viewController presentViewController:controller animated:YES completion:nil];
self.dataSource = dataSource;
}
I try to show with QlPreviewController a pdf from internet url without download it.
This is my code:
NSURL* url2 = [NSURL URLWithString:#"http://wwww.myweb.com/files/terms_en.pdf"];
// Check if can be shown
if(![QLPreviewController canPreviewItem:url2]) {
// cant show document
NSLog(#"can't show document");
}else {
NSLog(#"can show document");
// Show the document in preview
// _previewItemURL = url;
QLPreviewController* preview = [[QLPreviewController alloc] init];
[preview setDataSource:url2];
}
But it didn't show anything. In addition I have a warning in the last sentence [preview setDataSource:url2] saying 'Sending 'NSURL *_strong' to parameter of incompatible type 'id
As per the documentation, QLPreviewController requires NSFileURL, i.e. local files. Download your web resource with other means (e.g. NSData dataWithContentsOfURL), write to disk, and then feed the local URL to it.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
QLPreviewController *previewController = [[QLPreviewController alloc] init];
[previewController setDataSource:self];
[previewController setDelegate:self];
previewController.currentPreviewItemIndex = indexPath.row;
[self presentModalViewController:previewController animated:YES];
}
- (NSInteger)numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller
{
return [self.arrayForPDFList count];
}
- (id <QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
{
NSString *pathForPdf =[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
pathForPdf = [pathForPdf stringByAppendingFormat:#"/%#.pdf",[self.arrayForPDFList objectAtIndex:index]];
return [NSURL URLWithString:pathForPdf];
}
I'm trying to add the "presentOpenInMenuFromRect" functionality to Rhomobile. However, I have trouble referencing to the current view.
The Rhomobile function (### marks my additions):
- (void)openDocInteractCommand:(NSString*)url {
if (NSClassFromString(#"UIDocumentInteractionController")) {
NSURL *fileURL = [NSURL fileURLWithPath:url];
UIDocumentInteractionController* docController = [UIDocumentInteractionController interactionControllerWithURL:fileURL];
docController.delegate = self;//[AppManager instance];
BOOL result = [docController presentPreviewAnimated:YES];
if (!result) {
###
BOOL isValid = [docController presentOpenInMenuFromRect:CGRectZero inView:self.view animated:YES];
###
}
}
}
Essentially, if the preview fails, I want to open the "Open In" menu, because I;mtrying to open a .KMZ (Google Earth KML file) and it can't be previews.
Full source code: https://github.com/rhomobile/rhodes/blob/master/platform/iphone/Classes/AppManager/AppManager.m
Thanks,
Nick,
Here is the code solving my problem:
- (void)openDocInteractCommand:(NSString*)url { // inView:(UIView*)view
if (NSClassFromString(#"UIDocumentInteractionController")) {
NSURL *fileURL = [NSURL fileURLWithPath:url];
UIDocumentInteractionController* docController = [UIDocumentInteractionController interactionControllerWithURL:fileURL];
docController.delegate = self;//[AppManager instance];
BOOL result = [docController presentPreviewAnimated:YES];
if (!result) {
[docController retain];
CGPoint centerPoint = [Rhodes sharedInstance].window.center;
CGRect centerRec = CGRectMake(centerPoint.x, centerPoint.y, 0, 0);
BOOL isValid = [docController presentOpenInMenuFromRect:centerRec inView:[Rhodes sharedInstance].window animated:YES];
}
}
}
- (void)documentInteractionControllerDidEndPreview:(UIDocumentInteractionController *)docController
{
[docController autorelease];
}
The AppManager class inherits from NSObject and not from UIViewController - how come it would have a property named view? You have to find another way to present your view or view controller (maybe use the application's main window).
I have a tableView where the user can add contacts to. These contacts get saved to a mysql database and then returned to the user. Thing is, he has to update it manually in order to get the updated xml. But I wanna do it when he adds a contact so it gets shown right away. I tried various things and always ended up with either an error or he parsed the database more than once in the tableview. I thought of deleting all contacts and pasting all of them again and then update it, but this also didn't really work.
Here is how I do it at the moment:
To parse the XML:
- (void) doXMLParsing
{
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"Key22"] == nil) {
} else {
self.filteredListContent = [NSMutableArray arrayWithCapacity:[self.tabelle count]];
self.tableView.scrollEnabled = YES;
tabelle = [[NSMutableArray alloc] init];
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
NSString *fileName = [prefs stringForKey:#"Key22"];
NSString *urlString = [NSString stringWithFormat: #"http://www.---.com/%#.xml", fileName];
NSURL *url = [NSURL URLWithString: urlString];
DataFileToObjectParser *myParser = [[DataFileToObjectParser alloc] parseXMLAtUrl:url toObject:#"Telefonbuch" parseError:nil];
for(int i = 0; i < [[myParser items] count]; i++) {
Telefonbuch *new = [[Telefonbuch alloc] init];
new = (Telefonbuch *) [[myParser items] objectAtIndex:i];
[tabelle addObject:new];
[self.tableView reloadData];
}
[XMLActivity stopAnimating];
}
}
In the viewDidLoad:
XMLActivity = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(140.0f, 290.0f, 40.0f, 40.0f)];
[XMLActivity setActivityIndicatorViewStyle:UIActivityIndicatorViewStyleGray];
[self.view addSubview:XMLActivity];
[XMLActivity startAnimating];
[self performSelector:#selector(doXMLParsing)
withObject:nil
afterDelay:0];
return;
tabelle = [[NSMutableArray alloc] init];
Everything works fine right now. I just want to reparse the XML after a new contact is added so it will get displayed right away.
Have you tried calling [reloadData][1] on your UITableView?
If this does not answer, could you explain what happens exactly when you parse xml a second time?
The solution was as obvious as simple, and I still wasted way too many time on this.
Here is the solution:
Just put
[self doXMLParsing];
at the end when you added a contact to the database.