My PDF scroll view (copied from Apple’s ZoomingPDFViewer example, but modified a bit) can’t seem to zoom, although it’s displaying the data.
Here is what Apple uses in the example to add it:
CGPDFPageRef PDFPage = CGPDFDocumentGetPage(PDFDocument, 1);
[(PDFScrollView *)self.view setPDFPage:PDFPage];
And because that second line gave me errors, I changed it to this:
CGPDFPageRef PDFPage = CGPDFDocumentGetPage(PDFDocument, 1);
PDFScrollView *sv = [[PDFScrollView alloc] initWithFrame:self.view.frame];
[sv setPDFPage:PDFPage];
self.view = sv;
But now I can’t seem to zoom the PDF.
The Apple one works well without errors, but if I use this line in my app, I get the following error when that view loads:
-[UIView setPDFPage:]: unrecognized selector sent to instance 0x1c5b10b0
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIView setPDFPage:]: unrecognized selector sent to instance 0x1c5b10b0'
*** First throw call stack:
(0x3424c2a3 0x33a1e97f 0x3424fe07 0x3424e531 0x341a5f68 0x8c499 0x36da3595 0x36df813b 0x36df8081 0x36df7f65 0x36df7e89 0x36df75c9 0x36df74b1 0x36de5b93 0x36de5833 0x79acd 0x36e46275 0x36ec8ea9 0x39249a6f 0x342215df 0x34221291 0x3421ff01 0x34192ebd 0x34192d49 0x34efb2eb 0x36dd8301 0x6e601 0x38e17b20)
libc++abi.dylib: terminate called throwing an exception
The only other difference in my setup is that the view controller where this is called is inside a navigation controller, which is inside of a tab bar controller. But I can’t see how this would affect the problem.
Any tips?
[UPDATE]
This is my custom init method:
- (id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if (self) {
self.decelerationRate = UIScrollViewDecelerationRateFast;
self.delegate = self;
self.scrollEnabled = true;
}
return self;
}
It is the same as initWithCoder except that I added self.scrollEnabled = true;.
I also tried these, and it still didn’t work:
//UIScrollView *sv = [[UIScrollView alloc] initWithFrame:self.view.frame];
PDFScrollView *sv = [[PDFScrollView alloc] initWithFrame:self.view.frame];
self.view = sv;
[(PDFScrollView *)self.view setPDFPage:PDFPage];
When I use the commented-out line (UIScrollView), it gives me the same error, except that it says [UIScrollView setPDFPage:]: unrecognized.... When I use the uncommented line (PDFScrollView), it gives me no error and shows the PDF, but there’s still no zooming.
self.view must be a scroll view in order to be cast as a PDFScrollView and accept its methods. By default, self.view is a UIView. Either change the view to a scroll view in your XIB file (delete the view and link the scroll view to view in File's Owner) or do it programmatically.
Related
This question already has an answer here:
Method calling via performSelectorOnMainThread Vs Normal method calling
(1 answer)
Closed 9 years ago.
In my viewDidLoad, I call a function:
[common startActivityIndicatorOnView:self.view];
This method adds a view with Activity indicator, in the center of self.view.
My current view is pushed on a Navigation Stack. This is how the view looks after this method returns (the activity indicator view is not in center):
However, if I call the same method this way:
[common performSelectorOnMainThread:#selector(startActivityIndicatorOnView:) withObject:self.view waitUntilDone:NO];
The view looks like the following image (the activity indicator view is in center):
I do not get, How does it make a difference if the calling line is written in viewDidLoad.
If any one can help me get this, thanks in advance.
Just for reference,
the method looks like this:
-(void) startActivityIndicatorOnView:(UIView *)view {
if ([NSRunLoop currentRunLoop] != [NSRunLoop mainRunLoop]) {
[self performSelectorOnMainThread:#selector(startActivityIndicatorOnView:) withObject:view waitUntilDone:NO];
return;
}
view.userInteractionEnabled = NO;
activityBgView = [[UIView alloc] initWithFrame:CGRectMake((view.frame.size.width/2) - 50, (view.frame.size.width/2) - 50, 100, 100)];
activityBgView.center = view.center;
activityBgView.backgroundColor = [UIColor grayColor];
activityBgView.alpha = 0.8;
spinner = [[UIActivityIndicatorView alloc] initWithFrame:CGRectMake((activityBgView.frame.size.width/2)-10, (activityBgView.frame.size.width/2)-10, 20, 20)];
spinner.activityIndicatorViewStyle = UIActivityIndicatorViewStyleWhiteLarge;
spinner.center = view.center;
[view addSubview:activityBgView];
[view addSubview:spinner];
[spinner startAnimating];
}
ViewDidLoad is called when you load viewControllers (via nib/xib or created programmatically in the loadView method), meaning xcode create all views and instantiate and alloc all objects in xib...
but, your viewController view (and subViews) are still not added in any view...
yourViewController.view.superView = nil;
so, its view has got the frame that you set in xib, but if you tell it to resize inside its superview, when you add it (e.g. with a push or an addsubview), its frame changes, but your
spinner won't change its position.
calling a performSelectorOnMainThread just will call your method later, when your current thread step ahead and may have pushed your viewController.view, so, when executed, yourViewController.view.superView exists, and so view.frame has already changed.
try to move your call to
[common startActivityIndicatorOnView:self.view];
in a viewWillAppear method: at that point yourViewController.view should been already resized to fit its superView
EDIT:
# pavel question:
after what moment yourViewController.view.superView will be not nil?
banally: when you add its view to a view. that is, firts you allocate and init it (init with a nib or via code)
something like:
yourViewControllerInstance = [[YourViewController alloc]initWithNibName:#"yourViewControllerNib" bundle:nil];
at this point the method viewDidLoad in your class is called (but yourViewController.view.superview 0 nil)
later, you usually use your new viewController, so you "push" it in the stack of a navigationController, or you just add its view to the current viewController.view... something like:
[currentViewController.view addSubview:yourViewController.view];
after this line, as you may imagine, yourViewController.view.superView = currentViewController.view, and the method viewWillAppear of yourViewController is called, so you can use superView inside it.
Notice that at this point your viewController.view is still not visible on screen, so you can adjust sizes, move or add views here without users see any changes.
after this, yourViewController will show, and at the end, and the method viewDidAppear of yourViewController is called (for any other code, in case)
Terminating app due to uncaught exception 'NSGenericException'
Terminating app due to uncaught exception 'NSGenericException', reason: 'Unable to install constraint on view. Does the constraint
reference something from outside the subtree of the view? That's
illegal. constraint:
view:; layer = ; contentOffset: {0, 0}>'
You need to install the constraint on the "higher" of the two views. A good, general way to do this is like this:
NSLayoutConstraint* constraint = ...;
NSView* firstView = constraint.firstItem;
NSView* secondView = constraint.secondItem;
[[firstView ancestorSharedWithView: secondView] addConstraint: constraint];
Just a word of caution: It's good to remember here that constraint attributes are evaluated in the context of the view on which they are added. So for instance, the value of NSLayoutAttributeLeft of viewA, for a constraint installed on viewB, is interpreted in the coordinate space of viewB. For constraints that only reference sibling views or their superview, that fact is largely irrelevant, but there's no restriction that constraints can't reference two views that aren't siblings or direct parents.
Similar to neoneye I was getting this due to removing subviews with constraints. However I had a constraint that was positioning the parent view, and this was being removed if I called [self.view removeConstraints:self.view.constraints]; Instead I made this change,
Original Code:
for (UIView *subview in [view subviews]) {
[subview removeFromSuperview];
}
Fixed to remove constraints on subviews:
NSMutableArray * constraints_to_remove = [ #[] mutableCopy] ;
for( NSLayoutConstraint * constraint in view.constraints) {
if( [view.subviews containsObject:constraint.firstItem] ||
[view.subviews containsObject:constraint.secondItem] ) {
[constraints_to_remove addObject:constraint];
}
}
[view removeConstraints:constraints_to_remove];
for (UIView *subview in [view subviews]) {
[subview removeFromSuperview];
}
UPDATE: So I hit this error again - and it was due to removing a single view this time. Added a function to remove the view cleanly:
void cleanRemoveFromSuperview( UIView * view ) {
if(!view || !view.superview) return;
//First remove any constraints on the superview
NSMutableArray * constraints_to_remove = [NSMutableArray new];
UIView * superview = view.superview;
for( NSLayoutConstraint * constraint in superview.constraints) {
if( constraint.firstItem == view ||constraint.secondItem == view ) {
[constraints_to_remove addObject:constraint];
}
}
[superview removeConstraints:constraints_to_remove];
//Then remove the view itself.
[view removeFromSuperview];
}
I experienced this error on iOS6. In my case it was because I started removing subviews without first removing constraints.
// I had forgotten to remove constraints first. This caused the crash.
[self.view removeConstraints:self.view.constraints];
NSArray *subviews = self.view.subviews;
for (UIView *subview in subviews) {
[subview removeFromSuperview];
}
[self addYourSubviewsHere];
I got this problem using a UIPickerView like input of a UITextField (using Autolayout). When I push another viewController and thus a pop it to the viewController with the picker, the app crashes. I found the following solution, in the UIPickerViewController:
-(void)viewWillAppear:(BOOL)animated{
[self.pickerView removeFromSuperview];
[self.pickerView setTranslateAutoresizingMaskIntoContraints:YES];
[self.view addSubview];
}
You can also set the UIPickerViewPosition after removing from superview. I hope that can help you!
I found adding this one line of code fixed this issue for a cocoa ScrollView.
[scrollView setTranslatesAutoresizingMaskIntoConstraints:NO];
I think certain views add constraints at run time therefore conflicting when you add your own via objective c, so you need to disable this behaviour...
Same error, different solution here:
I got this error on starting up my app on iOS 6 after adding a new view and forgetting to switch off Use Auto Layout on it in the interface builder ... I hate it there's no standard setting to NOT use auto layout by default for new views ...
I had the same crash, and it turned out to be a floating-point precision problem with constraint multiplier values. I converted all my constraint multipliers to nice floating-point values (e.g. 0.375 instead of 0.35) and that fixed the crash.
AutoLayout: removeFromSuperview / removeConstraints throws exception and crashes hard
I created UILabel category which would do extra work when font property is changed.
I have chosen category over sublassing so I do not have to change class for all labels in my all XIB files. I just add this category declaration to the prefix header and category is visible in the whole project scope.
Implementation file:
//
// UILabel+XIBCustomFonts.m
#import "UILabel+XIBCustomFonts.h"
#implementation UILabel (XIBCustomFonts)
BOOL comes_from_nib = NO;
-(id)initWithCoder:(NSCoder *)aDecoder_{
self = [super initWithCoder:aDecoder_];
if (self) {
comes_from_nib = YES;
}
return self;
}
-(void)setFont:(UIFont *)font_{
[super setFont:font_];
NSLog(#"Setting from for label from XIB for name:%# size: %.1f - do font theme replacement if needed", self.font.fontName, self.font.pointSize);
}
#end
The surprising thing is the crash with following log:
-[UIButtonLabel setFont:]: unrecognized selector sent to instance 0x9ad1b70
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UIButtonLabel setFont:]: unrecognized selector sent to instance 0x9ad1b70'
Where did UIButtonLabel came form?
It happens even if I do extra Class checking in setFont: setter:
if ([self class] != [UILabel class] || !comes_from_nib) {
[super setFont:font_];
return;
}
Is there any way to override setFont: setter in UILabel without subclassing?
You cannot call super methods in categories! Never!
This is not possible when you use a category to augment a class' functionality, you are not extending the class, you are actually wholly overriding the existing method, you lose the original method completely. That's why your error appears.
My application is crashing when it returns back from the background at certain places:
-[UITableViewCellContentView updateToInterfaceOrientation]: unrecognized selector sent to instance 0x165470
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[UITableViewCellContentView updateToInterfaceOrientation]: unrecognized selector sent to instance 0x165470'
The error is always similiar somtimes its with
[UIScrollViewDelayedTouchesBeganGestureRecognizer updateToInterfaceOrientation]
I'm really clueless as to why this is happening, any help would be much appreciated.
EDIT:
Ok, this is how I am creating my table view in the loadView method:
int tableCells = [formDS.tableItems count];
int tableHeight = FORM_TABLE_CELL_HEIGHT * (tableCells);
UITableView *table = [[UITableView alloc] initWithFrame:CGRectMake(0, yCoord, FORM_TABLE_WIDTH, tableHeight) style:UITableViewStyleGrouped];
[table setBackgroundView:nil];
table.backgroundView.backgroundColor = UIColorFromRGB(FORM_BODY_COLOR);
table.backgroundColor = UIColorFromRGB(FORM_BODY_COLOR);
table.dataSource = self;
table.delegate = self;
[localContainerView addSubview:table];
It looks like you have some released object and because of that some other objects now present at the same address in memory receive the call for updateToInterfaceOrientation.
Try hitting COMMAND + SHIFT + B (or go to Product -> Analyze in XCode's top bar menu) to have XCode make a static analyze of your code and get some hints of what might go wrong.
Hope that's going to help!
I would like to show a modal view but don't want to use the standard methods because they don't let me animate the subview as I like.
I tried the fowlloing code:
EventsCalendarController *calController = [[EventsCalendarController alloc] init];
calController.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentModalViewController:calController animated:YES];
[calController release];
but the problem is that I would like to show it using some animation, so I am using the following code along with [UIView beginAnimation] etc...
EventsCalendarController *calController = [[EventsCalendarController alloc] init];
calController.modalPresentationStyle = UIModalPresentationFormSheet;
[self.view addSubview:calController.view];
[calController release];
The problem is that whenever I call the following code from the 'EventsCalendarController' I get an exception:
- (IBAction)btnClose_TouchUpInside:(id)sender {
[self.view removeFromSuperview];
}
here is the exception:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSCFType btnClose_TouchUpInside:]: unrecognized selector sent to instance 0x7029d60'
How can I solve/overcome this problem? Thank you.
UPDATE:
Solved: I found the following code on GitHub: https://github.com/horaceho/iphone-custom-dialogbox
It is a complete example with very few code to write. I did not find the original author, so I am just linking to the code...
Are you trying to remove the calendar view which you have added as a subview ? if so then
the code must be like this :
[calController removeFromSuperview];