UILabel category and setFont: crash - iphone

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.

Related

PDF ScrollView not scrolling

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.

Really weird "[UIAccessibilityBundle setWhatever:]: unrecognized selector sent to instance 0xnnnnnnn"

So, I'm puzzled by a really weird crash occurring in my app.
Background: I have a class CustomButton overriding UIButton. Briefly, the interface looks like:
#interface CustomButton : UIButton
#property (nonatomic, getter = isLoading) BOOL loading;
#end
Implementation:
#implementation CustomButton
#synthesize loading = loading_;
- (id)init {
if ((self = [UIButton buttonWithType:UIButtonTypeCustom])) {
[self setTitle:NSLocalizedString(#"My Button", nil) forState:UIControlStateNormal];
[[self titleLabel] setShadowColor:[UIColor blackColor]];
[[self titleLabel] setShadowOffset:CGSizeMake(0, -1)];
[self setContentEdgeInsets:UIEdgeInsetsMake(0, 77, 0, 30)];
UIImage *backgroundImage = [[UIImage imageNamed:#"back.png"] stretchableImageWithLeftCapWidth:77 topCapHeight:0];
UIImage *highlightedBackgroundImage = [[UIImage imageNamed:#"back_highlighted.png"] stretchableImageWithLeftCapWidth:77 topCapHeight:0];
[self setBackgroundImage:backgroundImage forState:UIControlStateNormal];
[self setBackgroundImage:highlightedBackgroundImage forState:UIControlStateHighlighted];
[self sizeToFit];
}
return self;
}
- (void)setLoading:(BOOL)loading {
if (loading_ != loading) {
// Do fancy things
}
}
#end
Problem: I'm trying to use the button in a class, so I have property and so on:
...
#property(nonatomic, strong) CustomButton *customButton;
...
#syntesize customButton = customButton_;
...
- (void)aMethod {
self.customButton.loading = YES;
}
...
The button, of course, is initialized.
Then, upon executing the statement self.bookButton.loading = YES, I get this error
2012-08-28 12:54:25.091 MyApp[9465:15803] -[UIAccessibilityBundle
setLoading:]: unrecognized selector sent to instance 0x8650cc0
2012-08-28 12:54:25.091 MyApp[9465:15803] *** Terminating app due
to uncaught exception 'NSInvalidArgumentException', reason:
'-[UIAccessibilityBundle setLoading:]: unrecognized selector sent to
instance 0x8650cc0'
*** First throw call stack: (0x1ead022 0x203ecd6 0x1eaecbd 0x1e13ed0 0x1e13cb2 0x26bf5 0x257ce 0xfa938f 0xfa96a4 0xfa99a7 0xfb8aea
0x11600be 0x11603c7 0x1160436 0xf10e49 0xf10f34 0xc5bcaac 0xe04b54
0x272e509 0x1de4803 0x1de3d84 0x1de3c9b 0x27887d8 0x278888a 0xee0626
0x14cce 0x27b5 0x1) terminate called throwing an exception
I honestly have no idea about what to look for. It's either something really really stupid, or something really subdle.
I've been searching on google/stackoverflow already of course, but I didn't manage to get an answer.
Usually that error occurs, as far as I know, when the object doesn't "understand" the sent message, but this shouldn't be the case. I don't even get a warning from the compiler.
If you have even just an idea of what I could look for or you want more details, let me know, thanks.
EDIT: forgot to specify that I am using ARC.
UPDATE: In the answers below Phillip Mills said that it might have been a premature memory release issue. It's a good point, but Instrument didn't find any zombie. Moreover, I've put a log right before the crashy statement, where I try print information about the CustomButton object and few things related to a UIButton, like the title. Everything looks ok. The title is the one I've set, the frame is there and so on... so I believe the object (an actual UIButton) exists and it's also the expected one. The only thing is the "loading" property that messes everything up.
SOLUTION: the init method was the source of the problem. Instead of initializing an instance of the subclass of the button, it was initializing an instance of UIButton. So, conequentely, no "loading" properties could be found. Substituting init with initWithFrame and using the standard procedure to override the initializer, everything works great.
Still a mistery, though, the reason why I got UIAccessibilityBundle as the origin of the error and not a UIButton.
Are you casting anything to (CustomButton *) in your app? Double-check the casts - you might be incorrectly casting something that's not a CustomButton and storing the result in the customButton property.
The button is almost certainly being released prematurely and having its address re-used for a UIAccessibilityBundle object. Try turning on zombies (or run Instruments to look for zombies) and you should see better information if the memory management problem isn't obvious.
Try
#interface CustomButton : UIButton
#property (nonatomic, assign) BOOL loading;
#end
and
#implementation CustomButton
#synthesize loading = _loading;
- (id)init {
....
}
- (void)setLoading:(BOOL)loading {
if (self.loading != loading) {
// Do fancy things
}
}
#end
For all other instances of loading, use self.loading.
Without seeing the other parts of your code, this is my best guess.

deleting contents of a label - Objective C

I have a label which stores any data that is entered. it has a property and has been synthesized.
#property (strong, nonatomic) IBOutlet UILabel *memoryDisplay;
#synthesize memoryDisplay;
-(void)viewDidLoad
{
[super viewDidLoad];
view.hidden = YES;
}
The label is in a view which is hidden on load
The view has a property and has been synthesized
on the same view there is a button for clearing a label
It has an Action
.h
- (IBAction)clearMemory:(id)sender;
And
.m
- (IBAction)clearMemory:(id)sender
{
self.memoryDisplay.text = #"";
}
However, when ever I try to run the app it crashes and gives me this error
* Terminating app due to uncaught exception 'NSUnknownKeyException', reason: '[ setValue:forUndefinedKey:]: this class is not key value coding-compliant for the key clearMemory.'
* First throw call stack:
(0x13bc052 0x154dd0a 0x13bbf11 0x9b3032 0x924f7b 0x924eeb 0x93fd60 0x23291a 0x13bde1a 0x1327821 0x23146e 0xd8e2c 0xd93a9 0xd95cb 0x39a73 0x39ce2 0x39ea8 0x40d9a 0x11be6 0x128a6 0x21743 0x221f8 0x15aa9 0x12a6fa9 0x13901c5 0x12f5022 0x12f390a 0x12f2db4 0x12f2ccb 0x122a7 0x13a9b 0x1b28 0x1a85)
terminate called throwing an exceptionsharedlibrary apply-load-rules all
I also tried to add some if statements to check for possible problems:
- (IBAction)clearMemory:(id)sender
{
if (!view.hidden) {
if ([memoryDisplay.text length] > 1)
{
self.memoryDisplay.text = #"";
}
}
Can anyone tell me what the problem might be?
If I take off everything got to do with the clear button it all works perfectly.
Thanks :)
Check all IB outlet bindings for broken links
Check to see if your memoryDisplay property is connected from the viewController to the UILabel in the nib/xib.
I couldn't do it the way I wanted, however I did find a workaround.
I placed a hidden, uneditable text box in the view which was empty and set the labels text to the text box whenever the clear button was pressed.

iphone sdk - problem pasting into current text location

I'm trying to paste text right into where the cursor currently is. I have been trying to do what it says at:
- http://dev.ragfield.com/2009/09/insert-text-at-current-cursor-location.html
The main deal is that I can't just go textbox1.text (etc) because the textfield is in the middle of a custom cell. I want to just have some text added to where the cursor is (when I press a custom key on a keyboard).
-I just want to paste a decimal into the textbox...
The error I get is:
2010-05-15 22:37:20.797 PageControl[37962:207] * -[MyDetailController paste:]: unrecognized selector sent to instance 0x1973d10
2010-05-15 22:37:20.797 PageControl[37962:207] * Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[MyDetailController paste:]: unrecognized selector sent to instance 0x1973d10'
Note: I have access to the textfield tag (if that helps?)
I'm a little past the beginner stage in objective-c, but still not great. My code is currently below, and at https://gist.github.com/d634329e5ddf52945989
Thanks all.
MyDetailController.h
#interface MyDetailController : UITableViewController <UITextFieldDelegate,UINavigationControllerDelegate>
{
//...(lots in here)
}
#end
#interface UIResponder(UIResponderInsertTextAdditions)
- (void) insertText: (NSString*) text;
#end
MyDetailController.m
#implementation MyDetailController
//.... (lots in here)
- (void)addDecimal:(NSNotification *)notification {
// Apend the Decimal to the TextField.
//savedAmount.text = [savedAmount.text stringByAppendingString:#"."];
NSLog(#"Decimal Pressed");
NSLog(#"tagClicked: %d",tagClicked);
switch (tagClicked) {
case 7:
//savedAmount.text = [savedAmount.text stringByAppendingString:#"."];
break;
case 8:
//goalAmount.text = [goalAmount.text stringByAppendingString:#"."];
break;
case 9:
//incrementAmount.text = [incrementAmount.text stringByAppendingString:#"."];
break;
case 10:
//incrementAmount.text = [incrementAmount.text stringByAppendingString:#"."];
break;
}
[self insertText:#"."];
}
-(void)textFieldDidBeginEditing:(UITextField *)textfield{
//UITextField *theCell = (UITextField *)sender;
tagClicked = textfield.tag;
NSLog(#"textfield changed. tagClicked: %d",tagClicked);
}
#end
#implementation UIResponder(UIResponderInsertTextAdditions)
- (void) insertText: (NSString*) text
{
// Get a refererence to the system pasteboard because that's
// the only one #selector(paste:) will use.
UIPasteboard* generalPasteboard = [UIPasteboard generalPasteboard];
// Save a copy of the system pasteboard's items
// so we can restore them later.
NSArray* items = [generalPasteboard.items copy];
// Set the contents of the system pasteboard
// to the text we wish to insert.
generalPasteboard.string = text;
// Tell this responder to paste the contents of the
// system pasteboard at the current cursor location.
[self paste: self];
// Restore the system pasteboard to its original items.
generalPasteboard.items = items;
// Free the items array we copied earlier.
[items release];
}
#end
UIViewController is a UIResponder... but it's not the UIResopnder that should receive the insertText: message. You want to call insertText: on the UITextField itself. If you take a look at UIResponder.h you'll see the following comment near the paste: method
// these methods are not implemented in NSObject
Meaning that it's not necessarily safe to call them on just any UIResponder. They can only safely be called on subclasses such as UITextField and UITextView which actually implement them. This was a really strange design decision on Apple's part.

iPhone Dev = maps and deselecting annotations

I am successfully drawing annotations on a map using an array of annotations. I can even click on the annotation and change it’s colour or image. My problem arises when the use selects the second annotation and I want to dynamically change the colour or image of the first one back to a non-selected colour/image. I can get the array of all the annotations and work through the array but once I try to set the colour or image ot the array I get a similar error.
for (MKAnnotationView *ann in map.selectedAnnotations){
if ([ann isMemberOfClass:[Place class]]) {
place = (Place *)ann;
if (currentPlaceID != place.placeID) {
UIImage *i = [UIImage imageNamed:#"pin.png"];
ann.image = i;
}
}
the above code works ok until I get to ann.image = i; then it errors. The errors I get are:-
-[Place setImage:]: unrecognized selector sent to instance 0x4514370 Terminating app due to uncaught exception
'NSInvalidArgumentException', reason: '** -[Place setImage:]:
unrecognized selector sent to instance 0x4514370'
Please advise as I have been going around in circles on this one for 2 days now!!!!
Any ideas on how best to do this?
thanks in advance
Do you have a property on the class Place called image?
Something like... #property (nonatomic, retain) UIImage* image; and is it properly synthesized? #synthesize image;?
The error is pretty straight forward, some object is receiving a message that it doesn't respond to, namely 'setImage' which is invoked by the .image.
Here is your code:
1. for (MKAnnotationView *ann in map.selectedAnnotations) {
2. if ([ann isMemberOfClass:[Place class]]) {
3. place = (Place *)ann;
4. if (currentPlaceID != place.placeID) {
5. UIImage *i = [UIImage imageNamed:#"pin.png"];
6. ann.image = i;
7. }
8. }
9. }
What I can see:
ann is an MKAnnotationView (from map.selectedAnnotations)
you are typecasting your annotation to a place on line 3 (is this right? Does Place subclass MKAnnotationView?)
you are properly setting the image to the annotation
What this means:
If Place is indeed a subclass of MKAnnotationView, you hid the setImage (somehow) method
If Place is NOT a subclass of MKAnnotationView, you've added an invalid annotation to the annotations (sure) that you're trying to treat as an annotation.
I finally figured out how to do this. As usual it's not that hard once you know how. Just thought I would pass this on.
- (void)setSelected:(BOOL)selected animated:(BOOL)animated
{
[super setSelected:selected animated:animated];
NSLog(#"here I am in set selected");
if (YES == selected)
{
NSLog(#"I am selected");
}
else
{
self.backgroundColor = [UIColor clearColor];
NSLog(#"not selected");
}
}