I am trying to display a file using QLPreviewController. The QL view displays correctly (is pushed on top of my Navigation Controller) but the content is blank. However, no errors are displayed and application doesn't crash.
Checks on existence of file return true. (A proof is that if I use [self.docInteractionController presentPreviewAnimated:YES]; where docInteractionController is a UIDocumentInteractionController the file is correctly shown).
The code is taken directly from Apple sample code DocInteraction.
previewController.dataSource = self;
previewController.delegate = self;
// start previewing the document at the current section index
previewController.currentPreviewItemIndex = 0; //I want the first (and only) document
[[self navigationController] pushViewController:previewController animated:YES];
[previewController release];
The current view is a QLPreviewControllerDataSource, QLPreviewControllerDelegate,, and the delegate methods are as follow:
- (NSInteger) numberOfPreviewItemsInPreviewController: (QLPreviewController *) controller
{
return self.documentURLs.count;
}
- (id)previewController:(QLPreviewController *)previewController previewItemAtIndex: (NSInteger)index
{
return [self.documentURLs objectAtIndex:index];
}
documentURLs is a NSArray that contains the fileURLs of the documents. The same fileURL passed to the UIDocumentInteractionController displays correctly. I don't necessarily have to use QuickLook, I may just rely on UIDocumentInteractionController, however the fact that it's not working is really annoying.
Thank you in advance
Giovanni
Make a sample that demoes the issue. If you find that it still occurs on iOS 7, pls file a bug report.
I reported a bug on this class (pass nil URL to get loading indicator) and it got fixed within 2 weeks.
Related
Here's the scenario: I am using MWPhotoBrowser. I can push it fine once. The second time I try to push it the app crashes with nothing helpful. This is an ARC project, and this exact same code works fine in previous versions of the app. I am dumbfounded.
-(void)collectionView:(UICollectionView *)collectionView didSelectItemAtIndexPath:(NSIndexPath *)indexPath
{
selectedIndexPath = indexPath;
if(browser == nil)
{
browser = [[MWPhotoBrowser alloc] initWithDelegate:self];
}
// Set options
browser.displayActionButton = YES; // Show action button to allow sharing, copying, etc (defaults to YES)
browser.displayNavArrows = YES; // Whether to display left and right nav arrows on toolbar (defaults to NO)
browser.zoomPhotosToFill = NO; // Images that almost fill the screen will be initially zoomed to fill (defaults to YES)
[browser setCurrentPhotoIndex:indexPath.row]; // Example: allows second image to be presented first
//browser.wantsFullScreenLayout = YES; // iOS 5 & 6 only: Decide if you want the photo browser full screen, i.e. whether the status bar is affected (defaults to YES)
// Present
[self.navigationController pushViewController:browser animated:YES];
}
Tap a cell once, MWPhotoBrowser opens fine. Go back, tap a cell again, the app crashes just with the debugger but no call stack or error reason:
(lldb):
browser is a strong member variable. It isn't being deallocated prematurely. I can also guarantee it is crashing exactly on the last line of the method.
Can someone please enlighten me on this? I'd solve it if the app at least gave me a reason for the crash and not just throw the debugger on my face.
I have used MWPhotoBrowser extensively and ran across the same problem once. The way I solved it was by checking the MWPhoto objects to see if they actually had been set properly. I realised that I had not created some of them, hence the crash. I would check the place where you store your MWPhotos and make sure they are all set. Hope this helps!
I'm using the UIDocumentInteractionController in iOS 7.1 and it's performing really badly.
I'm using it in a UICollectionViewController to view documents in a collection view.
On pressing an item in the collection view, it takes about around 6 (yes, that's six) seconds to appear. From a user experience perspective, they've pressed the screen a few more times before it appears because it takes so long.
I'm using the same code since iOS 6, but it seems particularly bad now. If anyone has any thoughts as to how I can speed things up, that would be greatly appreciated.
Essentially, I have the following in my header file:
interface MyViewController : UICollectionViewController <UIDocumentInteractionControllerDelegate>
{
UIDocumentInteractionController *docController;
}
#end
and in the implementation, I'm just doing the following:
In viewDidLoad (recently moved to here to see if it improves things):
docController = [[UIDocumentInteractionController alloc] init];
docController.delegate = self;
And then in the collectionView:didSelectItemAtIndexPath: I'm doing this:
NSURL *fileURL = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:document.Link ofType:#"" ]];
[docController setURL:fileURL];
PresentationViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:#"DocumentCell" forIndexPath:indexPath];
CGRect rect1 = cell.frame;
bool didShow = [docController presentOptionsMenuFromRect:rect1 inView:collectionView animated:YES];
where document is just a class with a string for the URL.
Let me know if you need any further detail.
Thanks in advance for any assistance anyone can provide.
-- Update:
After some NSLogs, I noticed that it's definitely the following line that's slow:
bool didShow = [docController presentOptionsMenuFromRect:rect1 inView:collectionView animated:YES];
TL;DR:
The method you are using is a synchronous request that uses your document data for find which apps are capable of reading your file. You need to swap with the asynchronous version that restricts the enumeration to only apps that can parse your file type.
Remove this method:
- (BOOL)presentOptionsMenuFromRect:(CGRect)rect
inView:(UIView *)view
animated:(BOOL)animated
And replace with this method:
- (BOOL)presentOpenInMenuFromRect:(CGRect)rect
inView:(UIView *)view
animated:(BOOL)animated
Excerpt from the Apple Docs:
This method is similar to the presentOptionsMenuFromRect:inView:animated: method, but presents a menu restricted to a list of apps capable of opening the current document. This determination is made based on the document type (as indicated by the UTI property) and on the document types supported by the installed apps. To support one or more document types, an app must register those types in its Info.plist file using the CFBundleDocumentTypes key.
If there are no registered apps that support opening the document, the document interaction controller does not display a menu.
This method displays the options menu asynchronously. The document interaction controller dismisses the menu automatically when the user selects an appropriate option. You can also dismiss it programmatically using the dismissMenuAnimated: method.
I was encountering a similar problem with:
UIDocumentInteractionController.presentPreviewAnimated
It would take an incredibly long time to complete. I found adding a brief delay between saving the file to be previewed and presenting the preview fixed the problem:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(100 * NSEC_PER_MSEC)), dispatch_get_main_queue(), {
self.controller.presentPreviewAnimated(false)
})
Swift 4.2
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
self.controller.presentPreviewAnimated(false)
}
This is used to work fine for my pre-ARC code, but since refactoring all the project to be ARC compatible, I start getting this crash:
[CustomViewController respondsToSelector:]: message sent to deallocated instance
My project is an iPad app with a split view, but contrary to apple documentation, previous developer has put another view controller to be visible on app launch before split view. So I know this is not the right way to do, but as I said it used to work before ARC integration so I need to get a workaround with this.
The root view controller which contain a menu of items, each item display a detail form to be filled, then a click on next button move to the next detail screen, etc.
The issue starts when I click on home button put on root view to get back to the home view, here is the relevant code that move the user to the home screen:
//this method is in the appdelegate, and it gets called when clikc on home button located on the root view
- (void) showHome
{
homeController.delegate = self;
self.window.rootViewController = homeController;
[self.window makeKeyAndVisible];
}
Then when I click on a button to get back to the split view (where are the root/details view), the app crashes with the above description. I profiled the app with instruments and the line of code responsible of that is located in the RootViewController, in the didSelectRowAtIndexPath method, here is the relevant code:
if(indexPath.row == MenuCustomViewController){
self.customVC=[[CustomViewController alloc] initWithNibName:#"CustomVC"
bundle:nil];
[viewControllerArray addObject:self.customVC];
self.appDelegate.splitViewController.delegate = self.customVC;
}
customVC is a strong property, I tried to allocate directly and assign to the instance variable but that didn't help to fix the crash. Any thoughts ?
EDIT:
Here is the stack trace given by instruments:
[self.appDelegate.splitViewController setViewControllers:viewControllerArray];//this line caused the crash
[viewControllerArray addObject:self.appDescVC];//this statement is called before the above one
self.custinfoVC=[[CustInfoViewController alloc] initWithNibName:#"CustInfo" bundle:nil];//this statement is called before the above one
self.appDelegate.splitViewController.delegate = self.appDescVC;//this statement is called before the above one
custinfoVC and appDescVC are strong properties.
I solved this problem by setting my delegates and datasources to nil in the dealloc method. Not sure if it'll help you but its worth a try.
- (void)dealloc
{
homeController.delegate = nil;
//if you have any table views these would also need to be set to nil
self.tableView.delegate = nil;
self.tableView.dataSource = nil;
}
You may want to setup the CustomViewController during app launch, and display the other views modally on top if necessary. The error message you're getting is because something is getting released by ARC prematurely. It might have not manifested before because pre-arc stuff wasn't always deallocated immediately. ARC is pretty serious about releasing stuff when it leaves scope
Hard to tell without seeing a lot more of the code involved, and what line it breaks on, etc.
This:
- (void) showHome {
//THIS: where is homeController allocated?
homeController.delegate = self;
self.window.rootViewController = homeController;
[self.window makeKeyAndVisible];
}
EDIT:
Add this line right above the line that causes your crash
for (id object in viewControllerArray) {
NSLog(#"Object: %#",object);
}
I had the same Problem.If you are not using "dealloc" method then use "viewWillDisappear" to set nil.
It was difficult to find which delegate cause issue, because it does not indicate any line or code statement for my App So I have try some way to identify delegate, Maybe it becomes helpful to you.
1.Open xib file and from file's owner, Select "show the connections inspector" right hand side menu. Delegates are listed, set them to nil which are suspected.
(Same as my case)Property Object like Textfield can create issue, So set its delegate to nil.
-(void) viewWillDisappear:(BOOL) animated{
[super viewWillDisappear:animated];
if ([self isMovingFromParentViewController]){
self.countryTextField.delegate = nil;
self.stateTextField.delegate = nil;
}
}
I am experimenting with various document types being displayed with a QLPreviewController but ive come across an issue with QLPreviewController not being able to switch between excel sheets if i have more that one document being fed to it,
self.fileNames = [NSArray arrayWithObjects:#"Doc1.xlsx",#"Doc2.html",#"Doc3.csv",#"Doc4.pdf",#"Doc.txt", nil];
//
- (id <QLPreviewItem>)previewController:(QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
{
NSString *contentURL = [[NSBundle mainBundle] pathForResource:[self.fileNames objectAtIndex:index] ofType:nil];
return [NSURL fileURLWithPath:contentURL];
}
- (NSInteger) numberOfPreviewItemsInPreviewController:(QLPreviewController *)controller
{
return [self.fileNames count];
}
If the number of preview items is set to 1 then you can navigate through all of the sheets of the xlsx file, but if the previewer has more than 1 doc then you can only zoom in and out.
Note this is an iOS 6 issue only, iOS 5 works as expected.
I get a feeling that it maybe to do with the changes to QLPreviewController to make it into a remote view controller and this effecting the gesture recogniser? (http://oleb.net/blog/2012/10/remote-view-controllers-in-ios-6/)
Any other ideas or known work arounds would be greatly appretiated.
Although not a solution a work around it to put a blank document into the 0 position of the array of documents whenever a xls detected there, then on loading the view advance to the second page without an animation.
I have a UIActivity subclass that creates its own activityViewController:
- (UIViewController *)activityViewController {
WSLInProgressViewController* progressView = [[[WSLInProgressViewController alloc] init] autorelease];
progressView.message = [NSString stringWithFormat:NSLocalizedString(#"Posting to %#...",#"Posting to..."),
self.activityType];
return progressView;
}
I've add a full repro on GitHub.
According to the documentation, you aren't supposed to dismiss this manually. Instead, the OS does that when you call activityDidFinish:. This works fine when ran on an iPhone.
When I say "works," this is the sequence of events that I'm expecting (and see on the iPhone):
Display the UIActivityViewController
User presses my custom activity
My view controller appears
I call activityDidFinish:
My custom view controller is dismissed
The UIActivityViewController is also dismissed
However, when I run this same code on the iPad Simulator -- the only difference being that I put the UIActivityViewController in a popup, as the documentation says you should -- the activityViewController never dismisses.
As I say, this is code wo/the popUP works on the iPhone and I have stepped through the code so I know that activityDidFinish: is getting called.
I found this Radar talking about the same problem in iOS6 beta 3, but it seems such fundamental functionality that I suspect a bug in my code rather than OS (also note that it works correctly with the Twitter and Facebook functionality!).
Am I missing something? Do I need to do something special in the activityViewController when it's run in a UIPopoverViewController? Is the "flow" supposed to be different on the iPad?
The automatic dismissal only appears to happen when your 'activity' controller is directly presented, not wrapped in anything. So just before showing the popup it's wrapped in, add a completion handler
activity.completionHandler = ^(NSString *activityType, BOOL completed){
[self.popup dismissPopoverAnimated:YES];
};
and you'll be good.
I see the question is quite old, but we've been debugging the same view-controller-not-dismissing issue here and I hope my answer will provide some additional details and a better solution than calling up -dismissPopoverAnimated: manually.
The documentation on the UIActivity is quite sparse and while it hints on the way an implementation should be structured, the question shows it's not so obvious as it could be.
The first thing you should notice is the documentation states you should not be dismissing the view controller manually in anyway. This actually holds true.
What the documentation doesn't say, and what comes as an observable thing when you come across debugging the non-dissmissing-view-controller issue, is iOS will call your -activityViewController method when it needs a reference to the subject view controller. As it turns out, probably only on iPad, iOS doesn't actually store the returned view controller instance anywhere in it's structures and then, when it wants to dismiss the view controller, it merely asks your -activityViewController for the object and then dismisses it. The view controller instantiated in the first call to the method (when it was shown) is thus never dismissed. Ouch. This is the cause of the issue.
How do we properly fix this?
Skimming the UIActivity docs further one may stumble accross the -prepareWithActivityItems: method. The particular hint lies along the following text:
If the implementation of your service requires displaying additional UI to the user, you can use this method to prepare your view controller object and make it available from the activityViewController method.
So, the idea is to instantiate your view controller in the -prepareWithActivityItems: method and tackle it into an instance variable. Then merely return the same instance from your -activityViewController method.
Given this, the view controller will be properly hidden after you call the -activityDidFinish: method w/o any further manual intervention.
Bingo.
NB! Digging this a bit further, the -prepareWithActivityItems: should not instantiate a new view controller each time it's called. If you have previously created one, you should merely re-use it. In our case it happily crashed if we didn't.
I hope this helps someone. :)
I had the same problem. It solved for me saving activityViewController as member and return stored controller. Activity return new object and dismiss invoked on new one.
- (UIViewController *)activityViewController {
if (!self.detaisController) {
// create detailsController
}
return self.detailsController;
}
I pass through the UIActivity to another view then call the following...
[myActivity activityDidFinish:YES];
This works on my device as well as in the simulator. Make sure you're not overriding the activityDidFinish method in your UIActivity .m file as I was doing previously. You can see the code i'm using here.
a workaround is to ask the calling ViewController to perform segue to your destination ViewController via - (void)performActivity although Apple does not recommend to do so.
For example:
- (void)performActivity
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
[self.delegate performSomething]; // (delegate is the calling VC)
[self activityDidFinish: YES];
}
}
- (UIViewController *)activityViewController
{
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone)
{
UIViewController* vc=XXX;
return vc;
}
else
{
return nil;
}
}
Do you use storyboards? Maybe in your iPad storyboard, the UIActivityIndicatorView doesn't have a check on "Hides When Stopped"?
Hope it helps!
So I had the same problem, I had a custom UIActivity with a custom activityViewController and when it was presented modally it would not dismiss not matter what I tried. The work around I choose to go with so that the experience remained the same to the user was to still use a custom UIActivity but give that activity a delegate. So in my UIActiviy subclass I have the following:
- (void)performActivity
{
if ([self.delegate respondsToSelector:#selector(showViewController)]) {
[self.delegate showViewController];
}
[self activityDidFinish:YES];
}
- (UIViewController *)activityViewController
{
return nil;
}
Then I make the view controller that shows the UIActivityViewController the delegate and it shows the view controller that you would otherwise show in activityViewController in the delegate method.
what about releasing at the end? Using non-arc project!
[progressView release];
Many Users have the same problem as u do! Another solution is:
UIActivityIndicatorView *progress= [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake(125, 50, 30, 30)];
progress.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
[alert addSubview:progress];
[progress startAnimating];
If you are using storyboard be sure that when u click on the activityind. "Hides When Stopped" is clicked!
Hope that helped...