respondsToSelector always fails - iphone

I am in the process of writing my own gridview implementation( Based of the tableview pattern). I have followed a datasource model similar to table view, but when I check if the data source responds to the message the call always fails.
I have tried putting in break points and following execution, I even tried missing out the call to respondsToSelector. Nothing I try seems to work. What am I missing here? Thanks in advance
GridView.h
...
#protocol GridViewDataSource
- (NSInteger) numberOfRowsForGridView:(GridView *)gridView;
- (NSInteger) numberOfColumnsForGridView:(GridView *)gridView;
- (GridViewCell *) cellForRow:(NSInteger) row column:(NSInteger )column;
#end
GridView.m
...
#pragma mark datasource methods
-(NSInteger)numberOfRowsForGridView
{
if( [dataSource respondsToSelector:#selector(numberOfRowsForGridView:)] )
return [dataSource numberOfRowsForGridView:self];
// NSLog(#"Failed, dataSource does not implement properly");
return 0;
}
-(NSInteger)numberOfColumnsForGridView
{
if( [dataSource respondsToSelector:#selector(numberOfColumnsForGridView:)] )
return [dataSource numberOfColumnsForGridView:self];
return 0;
}
-(GridViewCell *)cellForRow:(NSInteger)row column:(NSInteger)column
{
if( [dataSource respondsToSelector:#selector(cellForRow:column:)])
return [dataSource cellForRow:row column:column];
return nil;
}
GridViewAppDelegate.h
...
#interface GridViewAppDelegate : NSObject <UIApplicationDelegate, GridViewDataSource>
...
GridViewAppDelegate.m
#pragma mark datasource methods
-(NSInteger)numberOfRowsForGridView:(GridView *)gridView
{
return 1;
}
-(NSInteger)numberOfColumnsForGridView:(GridView *)gridView
{
return 1;
}
-(GridViewCell *)cellForRow:(NSInteger)row column:(NSInteger)column
{
CGRect frame = [view bounds];
GridViewCell *cell = [[GridViewCell alloc]initWithFrame:frame];
return cell;
}

Is your dataSource object nil?
Any message sent to nil will return NO for boolean results (0 for numbers, and nil for objects as well).

Have you checked whether dataSource is non-nil?

Related

Two Independent Delegate Methods in a Class

I have two independent delegate methods in a class.
- (void)delegateMethod1:(id)data {
self.data = data;
}
- (void)delegateMethod2 {
[someClass sendData:self.data];
}
Now, this works fine sometimes but the other times, delegateMethod2 gets called before delegateMethod1.
I need to know how to manage this elegantly so that the line: [someClass sendData:self.data]; gets called only when both delegateMethod1 and delegateMethod2 have been called.
I know I can do it by using a variable to set to something on each delegate call but there has to be an elegant way to do this.
Any help?
Remembering which delegate has been called seems the easiest and cleanest solution to me.
But you can make it symmetric by moving the check to a separate method, so that
is does not matter which delegate is called first:
- (void)checkIfDataCanBeSent {
if (self.method1called && self.method2called) {
[someClass sendData:self.data];
}
}
- (void)delegateMethod1:(id)data {
self.method1called = YES;
// ...
[self checkIfDataCanBeSent];
}
- (void)delegateMethod2 {
self.method2called = YES;
// ...
[self checkIfDataCanBeSent];
}
(I have assumed that all delegate methods are called on the main thread, otherwise
one would have to add some synchronization.)
I believe, using a indicative variable to be the most elegant way to get over this. But this variable has to be kept in the delegate caller object.
Pseudo-type explanation
#interface DelegateCaller
{
BOOL hasCalled1stMethod;
}
#property(nonatomic,weak) id delegate;
#end
#implementation DelegateCaller
-(void)in_some_process_1
{
[self.delegate delegateMethod1]; //call
hasCalled1stMethod = YES; //set indicator
}
-(void)in_some_process_2
{
if(hasCalled1stMethod)
{
[self.delegate delegateMethod2]; //call
hasCalled1stMethod = NO; //reset indicator for reuse, if required.
}
}
#end
This way you'll not have to maintain any variable in the delegate itself, because the regulation of calling is maintained in the caller-object itself.
Another case:
If the delegateMethod1 is called from some object1 and the delegateMethod2 is called from some other object2, then again the indicative variable method is the most elegant way (in this limited scenario)
Pseudo-type explanation:
#interface ClassDelegateObject //aka the callee
{
BOOL hasCalledMethod1;
}
#end
#implementation ClassDelegateObject
-(void)delegateMethod1:(NSData*)data
{
self.data = data;
hasCalledMethod1 = YES; //set the indicator.
}
-(void)delegateMethod2
{
//here relying on the self.data!=nil will not be fruitful
//in case the self.data is not nil and hold some previous garbage data then
//this logic will fail.
if(hasCalledMethod1)
{
[someClass sendData:self.data];
hasCalledMethod1 = NO; //reset the variable for reuse if required.
}
}
#end
I would suggest that you rethink how the code works. Maybe you can check if there is no data and if so send it once it is ready:
- (void)delegateMethod1:(id)data {
self.data = data;
if (self.dataShouldBeSentWhenReady) {
[self sendData];
}
}
- (void)delegateMethod2 {
if (self.data) {
[self sendData];
} else {
[self setDataShouldBeSentWhenReady:YES];
}
}
- (void)sendData {
[self setDataShouldBeSentWhenReady:NO];
[someClass sendData:self.data];
}

Adding a method to my uitextfield in cell?

I am adding this Method to my code to format the textfield. I am using the code below to try and add the method, but it not working, what am I doing wrong?
.h file
NSString* phone_;
UITextField* phoneFieldTextField;
#property (nonatomic,copy) NSString* phone;
.m file
#synthesize phone = phone_;
ViewDidLoad{
self.phone = #"";
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
// Make cell unselectable and set font.
cell.selectionStyle = UITableViewCellSelectionStyleNone;
cell.textLabel.font = [UIFont fontWithName:#"ArialMT" size:13];
if (indexPath.section == 0) {
UITextField* tf = nil;
switch ( indexPath.row ) {
case 3: {
cell.textLabel.text = #"Phone" ;
tf = phoneFieldTextField = [self makeTextField:self.phone placeholder:#"xxx-xxx-xxxx"];
phoneFieldTextField.keyboardType = UIKeyboardTypePhonePad;
[self formatPhoneNumber:phoneFieldTextField.text deleteLastChar:YES];
[cell addSubview:phoneFieldTextField];
break ;
}
// Textfield dimensions
tf.frame = CGRectMake(120, 12, 170, 30);
// Workaround to dismiss keyboard when Done/Return is tapped
[tf addTarget:self action:#selector(textFieldFinished:) forControlEvents:UIControlEventEditingDidEndOnExit];
}
}
// Textfield value changed, store the new value.
- (void)textFieldDidEndEditing:(UITextField *)textField {
//Section 1.
if ( textField == nameFieldTextField ) {
self.name = textField.text ;
} else if ( textField == addressFieldTextField ) {
self.address = textField.text ;
} else if ( textField == emailFieldTextField ) {
self.email = textField.text ;
} else if ( textField == phoneFieldTextField ) {
self.phone = textField.text ;
}else if ( textField == dateOfBirthTextField ) {
self.dateOfBirth = textField.text ;
}
}
- (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string {
NSString* totalString = [NSString stringWithFormat:#"%#%#",textField.text,string];
// if it's the phone number textfield format it.
if(textField.tag == 10 ) {
if (range.length == 1) {
// Delete button was hit.. so tell the method to delete the last char.
textField.text = [self formatPhoneNumber:totalString deleteLastChar:YES];
} else {
textField.text = [self formatPhoneNumber:totalString deleteLastChar:NO ];
}
return false;
}
return YES;
NSLog(#"Testing should change character in range");
}
-(NSString*) formatPhoneNumber:(NSString*) simpleNumber deleteLastChar:(BOOL)deleteLastChar {
if(simpleNumber.length == 0) return #"";
// use regex to remove non-digits(including spaces) so we are left with just the numbers
NSError *error = NULL;
NSRegularExpression *regex = [NSRegularExpression regularExpressionWithPattern:#"[\\s-\\(\\)]" options:NSRegularExpressionCaseInsensitive error:&error];
simpleNumber = [regex stringByReplacingMatchesInString:simpleNumber options:0 range:NSMakeRange(0, [simpleNumber length]) withTemplate:#""];
// check if the number is to long
if(simpleNumber.length>10) {
// remove last extra chars.
simpleNumber = [simpleNumber substringToIndex:10];
}
if(deleteLastChar) {
// should we delete the last digit?
simpleNumber = [simpleNumber substringToIndex:[simpleNumber length] - 1];
}
// 123 456 7890
// format the number.. if it's less then 7 digits.. then use this regex.
if(simpleNumber.length<7)
simpleNumber = [simpleNumber stringByReplacingOccurrencesOfString:#"(\\d{3})(\\d+)"
withString:#"($1) $2"
options:NSRegularExpressionSearch
range:NSMakeRange(0, [simpleNumber length])];
else // else do this one..
simpleNumber = [simpleNumber stringByReplacingOccurrencesOfString:#"(\\d{3})(\\d{3})(\\d+)"
withString:#"($1) $2-$3"
options:NSRegularExpressionSearch
range:NSMakeRange(0, [simpleNumber length])];
if (simpleNumber.length == 10 && deleteLastChar == NO) { [self resignFirstResponder];}
return simpleNumber;
NSLog(#"Testing format phone number");
}
#pragma mark - TextField
-(UITextField*) makeTextField: (NSString*)text
placeholder: (NSString*)placeholder {
UITextField *tf = [[UITextField alloc] init];
tf.placeholder = placeholder;
tf.text = text ;
tf.autocorrectionType = UITextAutocorrectionTypeNo ;
tf.autocapitalizationType = UITextAutocapitalizationTypeNone;
tf.adjustsFontSizeToFitWidth = YES;
tf.returnKeyType = UIReturnKeyDone;
tf.textColor = [UIColor colorWithRed:56.0f/255.0f green:84.0f/255.0f blue:135.0f/255.0f alpha:1.0f];
return tf ;
}
The method you are using:
-(NSString*) formatPhoneNumber:(NSString*) simpleNumber deleteLastChar:(BOOL)deleteLastChar
Returns an NSString Object. In your case you are calling the method correctly but you are not setting the Returned NSString object to anything. It is simply hanging there. You need to set the phoneFieldTextField to the formatted text like so:
phoneFieldTextField.text = [self formatPhoneNumber:phoneFieldTextField.text deleteLastChar:YES];
NOTE - If you want to learn more about return methods then read the following:
If you noticed some most methods are of the void type. You know this when you see a method like this:
- (void)someMethod {
int x = 10;
}
What void means is that the someMethod does not return anything to you. It simply executes the code within the method. Now methods than return an object or some other data type look like this:
- (int)returnSomething {
int x = 10;
return x;
}
First thing you will notice is the return type is no longer void, it is an int. This means the method will return an integer type. In this case the code executes and you are returned the value of x.
This is just the start of the topic of return methods but hopefully it makes things a bit clearer for you.
First off you need to tell us What is not working we don't have your app and all your code. You need to explain what is working and what is not working exactly. It took longer then necessary to figure out that your question is why is textField:shouldChangeCharactersInRange: not working. Did you set a breakpoint in the function to see what it was doing. Was it not being called?
That said your bug is that textField:shouldChangeCharactersInRange: is using tags to identify text fields but the rest of the code is using pointers
// if it's the phone number textfield format it.
- if(textField.tag == 10 ) {
+ if(textField.tag == phoneFieldTextField ) {
Also you didn't include the code for makeTextField:placeholder: There could be issues in it too. Compare your code to the makeTextField:placeholder: in my sample.
I created a sample project on GitHub. To fix this. I also demos a better approach to creating input forms using table views.
https://github.com/GayleDDS/TestTableViewTextField.git
Look at both diffs to see what I did to YourTableViewController.m to make things work.
https://github.com/GayleDDS/TestTableViewTextField/commit/d65a288cb4da7e1e5b05790ea23d72d472564793
https://github.com/GayleDDS/TestTableViewTextField/commit/31ecaec8c9c01204643d72d6c3ca5a4c58982099
There is a bunch of other Issues here:
You need to call [super viewDidLoad]; in your viewDidLoad method
You need to correctly indent your code (could be a cut and paste issue)
You should be using the storyboard to create your views. See the better solution tab and BetterTableViewController implementation.
Must Watch - iOS Development Videos
WWDC 2011 - Session 309 - Introducing Interface Builder Storyboarding
https://developer.apple.com/videos/wwdc/2011/?id=309
Stanford iPhone Programing Class (Winter 2013)
Coding Together: Developing Apps for iPhone and iPad
https://itunes.apple.com/us/course/coding-together-developing/id593208016
Lecture 9. Scroll View and Table View
Lecture 16. Segues and Text Fields
Looks like you are not setting the delegate <UITextFieldDelegate> in the .h file, and not assigning your textfield's delegate property to self tf.delegate = self; in order to call - (BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementString:(NSString *)string
Try that and let me know how it goes
-Good Luck!
#koray was right: you need to setup the delegate for the class. Your class should be declared as implementing the protocol UITextFieldDelegate (in addition to UITableViewDataSource, I assume)
then in your makeTextField: (NSString*)text placeholder: (NSString*)placeholder method, you need to have something like:
-(UITextField*) makeTextField: (NSString*)text
placeholder: (NSString*)placeholder {
UITextField *tf = [[UITextField alloc] initWithFrame:CGRectMake(40, 0, 150, 40)];
tf.placeholder = placeholder;
// (...)
tf.delegate = self;
return tf ;
}
Then you need to setup the delegate methods correctly. In the following example, I have a nav bar, since the numbers pad doesn't have a return or a done button. I setup a button that will act as the done button (you may have another way of making the keyboard go, and switching between text fields will trigger the end of edition anyway):
- (void) textFieldDidBeginEditing:(UITextField *)textField {
UIBarButtonItem *doneBtn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(doneEditing:)];
self.navBar.topItem.rightBarButtonItem = doneBtn;
}
- (void) doneEditing:(id) sender {
if(phoneFieldTextField.isFirstResponder) {
[phoneFieldTextField resignFirstResponder];
}
// (...)
self.navBar.topItem.rightBarButtonItem = nil;
}
Then, the magic happens in the textDidEndEditing delegate method:
- (void)textFieldDidEndEditing:(UITextField *)textField {
if ( textField == phoneFieldTextField ) {
self.phone = [self formatPhoneNumber:textField.text deleteLastChar:YES] ; // convert
[phoneFieldTextField setText:self.phone]; // display
}
// (...)
}

run time catch method [duplicate]

I am developing an Objective-C application, and what I want to do, is something like the following:
+-----------------+ +---------------+
| Some Object | <---------- | Synchronize |
|(Not Thread Safe)| | Proxy |
+-----------------+ / +---------------+
/
/ Intercepts [someobject getCount]
/ #synchronize (someObject)
/
[someObject getCount] /
+----------------------+
| Some Calling Object |
+----------------------+
What I've asking is, how can I create an object in objective-c, that intercepts messages sent to another object, in order to perform code before the message is sent to that object.
Some things that I think will not work:
Categories (I need this to only happen for certain instances of a class)
Rewriting the object (I don't have access to the source of the object)
Method swizzling (once again, this need to only happen for certain instances of a class)
You would implement an NSProxy that forwards messages to your non-thread-safe object.
Here is a nice writeup of message forwarding in Objective-C, and here is Apple's documentation.
To handle thread safety, it depends on what you need. If your non-thread-safe object must run on a specific thread then you can use a NSRunLoop on said thread to serialize messages to that object.
Here is an example of using NSInvocation in conjunction with NSRunLoop. In that example they're using performSelector:withObject:afterDelay: but to use it with performSelector:onThread:withObject:waitUntilDone: would be very similar.
Otherwise, just use a single NSRecursiveLock in your proxy.
If you know exactly what instances should have the behavior you are trying to achieve you can go with method swizzling and call the base implementation if the instance is not the one you are looking for.
You can have a global shared object that lists the "interesting" instances and use it in the swizzling implementation whether you have to call the base one or your custom one.
So, I bit the bullet, and decided to make my own proxy class. To subclass, you simply override the 'forwardInvocation:' message, and you call any code you need there, before calling [super forwardInvocation:]. Please not this will NOT work with vardic methods, as NSInvocation doesn't work with vardic methods.
#import <Foundation/Foundation.h>
#import <objc/runtime.h>
#import <objc/objc.h>
#import <objc/message.h>
#interface RJProxy : NSObject {
#private
NSObject *target;
}
#property(readwrite, retain) NSObject *target;
-(NSObject *) getTarget;
#end
#implementation RJProxy
#synthesize target;
-(NSMethodSignature *) methodSignatureForSelector:(SEL)aSelector
{
if (objc_getAssociatedObject(self, "isProxy"))
{
IMP NSObjectImp = [NSObject instanceMethodForSelector:#selector(methodSignatureForSelector:)];
NSMethodSignature *methodSignature = (NSMethodSignature *) NSObjectImp(self, #selector(methodSignatureForSelector:), aSelector);
if (methodSignature)
return methodSignature;
return [target methodSignatureForSelector:aSelector];
}
else
{
Class subClass = self->isa;
#try {
self->isa = objc_getAssociatedObject(self, "realSuperclass");
return [super methodSignatureForSelector:aSelector];
}
#finally {
self->isa = subClass;
}
}
}
-(void) forwardInvocation:(NSInvocation *)anInvocation
{
if (objc_getAssociatedObject(self, "isProxy"))
{
Class subClass = target->isa;
target->isa = objc_getAssociatedObject(self, "realSuperclass");
[anInvocation invokeWithTarget:target];
target->isa = subClass;
}
else
{
Class realSuperclass = objc_getAssociatedObject(self, "realSuperclass");
Class subclass = self->isa;
self->isa = realSuperclass;
if ([self respondsToSelector:[anInvocation selector]])
{
[anInvocation invokeWithTarget:self];
}
else
{
[self doesNotRecognizeSelector:[anInvocation selector]];
}
self->isa = subclass;
}
}
-(NSObject *) getTarget
{
if (objc_getAssociatedObject(self, "isProxy"))
{
return target;
}
return self;
}
#end
BOOL object_setProxy(NSObject *object, RJProxy *proxy);
BOOL object_setProxy(NSObject *object, RJProxy *proxy)
{
proxy.target = object;
Class objectClass = object_getClass(object);
Class objectSub = objc_allocateClassPair(objectClass, [[NSString stringWithFormat:#"%s_sub%i", class_getName(objectClass), objc_getAssociatedObject(objectClass, "subclassTimes")] UTF8String], 0);
objc_setAssociatedObject(objectClass, "subclassTimes", (id) ((int) objc_getAssociatedObject(objectClass, "subclassTimes") + 1), OBJC_ASSOCIATION_ASSIGN);
objc_registerClassPair(objectSub);
Class proxyClass = object_getClass(proxy);
Class proxySub = objc_allocateClassPair(proxyClass, [[NSString stringWithFormat:#"%s_sub%i", class_getName(proxyClass), objc_getAssociatedObject(proxyClass, "subclassTimes")] UTF8String], 0);
objc_setAssociatedObject(proxyClass, "subclassTimes", (id) ((int) objc_getAssociatedObject(proxyClass, "subclassTimes") + 1), OBJC_ASSOCIATION_ASSIGN);
objc_registerClassPair(proxySub);
object_setClass(object, proxySub);
object_setClass(proxy, proxySub);
objc_setAssociatedObject(object, "isProxy", (id) NO, OBJC_ASSOCIATION_ASSIGN);
objc_setAssociatedObject(proxy, "isProxy", (id) YES, OBJC_ASSOCIATION_ASSIGN);
objc_setAssociatedObject(object, "realSuperclass", objectClass, OBJC_ASSOCIATION_ASSIGN);
objc_setAssociatedObject(proxy, "realSuperclass", proxyClass, OBJC_ASSOCIATION_ASSIGN);
return NO;
}
#interface SynchronizeProxy : RJProxy
#end
#implementation SynchronizeProxy
-(void) forwardInvocation:(NSInvocation *)anInvocation {
#synchronized ([self getTarget])
{
[super forwardInvocation:anInvocation];
}
}
#end
int main (int argc, const char * argv[])
{
#autoreleasepool {
NSArray *arrayToSynchronize = [NSArray arrayWithObjects:#"This, is, a, test!", nil];
SynchronizeProxy *myProxy = [SynchronizeProxy new];
object_setProxy(arrayToSynchronize, myProxy);
// now all calls will be synchronized!
NSLog(#"Array at address 0x%X with count of %lu, and Objects %# ", (unsigned) arrayToSynchronize, [arrayToSynchronize count], arrayToSynchronize);
[myProxy release];
[arrayToSynchronize release];
}
return 0;
}

NSValueTransformer, inserting NULL into core data

I'm having a problem with NSValueTransformer, instead of transforming the value (NSString) it's putting NULL into the database where the attributes are transformable. I'm using the apple example, which is the same are everyone else's example and I just can't get it to work on a simple level. I'm also putting breakpoints at transformedValue and reverseTransformedValue, but they never get hit.
My custom class
+ (void)registerValueTransformer {
[NSValueTransformer setValueTransformer:[[[self alloc] init] autorelease] forName:#"myTransformerTest"];
}
#pragma mark -
#pragma mark NSValueTransformer implementation
+ (BOOL)allowsReverseTransformation {
return YES;
}
+ (Class)transformedValueClass {
return [NSString class];
}
- (id)transformedValue:(id)value {
return #"Test in";
}
- (id)reverseTransformedValue:(id)value {
return #"Test Out";
}
And this in my app delegate
+(void) initialize
{
[super initialize];
[transformerTest registerValueTransformer];
}
And then in Core data I've made my attribute transformable with a name "myTransformerTest". And according to the apple documentation that should be it.

Why isn't my UILabel being changed?

Why isn't my UILabel being changed? I am using the following code, and nothing is happening:
- (void)awakeFromNib {
percentCorrect.adjustsFontSizeToFitWidth;
percentCorrect.numberOfLines = 3;
percentCorrect.minimumFontSize = 100;
}
Here is my Implemintation code:
- (void) updateScore {
double percentScore = 100.0 * varRight / (varWrong + varRight);
percentCorrect.text = [NSString stringWithFormat:#"%.2f%%", percentScore];
}
- (void)viewDidLoad {
percentCorrect.adjustsFontSizeToFitWidth = YES;
percentCorrect.numberOfLines = 3;
percentCorrect.minimumFontSize = 100;
percentCorrect.text = #"sesd";
}
- (void)correctAns {
numberRight.text = [NSString stringWithFormat:#"%i Correct", varRight];
}
-(void)wrongAns {
numberWrong.text = [NSString stringWithFormat:#"%i Incorrect", varWrong];
}
#pragma mark Reset Methods
- (IBAction)reset:(id)sender; {
NSString *message = #"Are you sure you would like to reset?";
self.wouldYouLikeToReset = [[UIAlertView alloc] initWithTitle:#"Reset?" message:message delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:nil];
[wouldYouLikeToReset addButtonWithTitle:#"Continue"];
[self.wouldYouLikeToReset show];
// Now goes to (void)alertView and see's what is being pressed!
}
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0)
{
NSLog(#"Cancel button pressed");
}
else
{
varRight = 0;
varWrong = 0;
[self wrongAns];
[self correctAns];
percentCorrect.text = [NSString stringWithFormat:#"0.0%%"];
}
}
#pragma mark Button Action Methods
- (IBAction)right:(id)sender; {
varRight++;
[self correctAns];
[self updateScore];
}
- (IBAction)wrong:(id)sender; {
varWrong++;
[self wrongAns];
[self updateScore];
}
- (IBAction)subOneRight:(id)sender {
if (varRight > 0 ) {
varRight--;
[self correctAns];
[self updateScore];
}
}
- (IBAction)subOneWrong:(id)sender {
if (varWrong > 0) {
varWrong--;
[self wrongAns];
[self updateScore];
}
}
-(IBAction)addHalfCredit:(id)sender;
{
varWrong++;
varRight++;
[self wrongAns];
[self correctAns];
[self updateScore];
}
#end
Any ideas?
Thanks
In order for the adjustsFontSizeToFitWidth setting to come into effect, the numberOfLines property must be set to 1. It won't work if it's != 1.
Are awakeFromNib, viewDidLoad, viewWillAppear being called at all?
The minimumFontSize property will do nothing if the text fits in the current bounds with the current font. Did you set the font property for the label?
percentCorrect.font = [UIFont systemFontOfSize:20];
Finally, isn't a minimumFontSize = 100 a little too big for a min font size?
Make sure everything is hooked up correctly. Make sure the IBOutlet for the UITextfield is setup and set break points within the method and see that the code is being touched. If it is, it's possible percentCorrect hasn't been hooked up correctly.
You shouldn't have to init your label if it is in the nib. If you are, then you created the label twice. So who knows which one you are messaging to. As soon as you initialized the label, you leaked the first one. So the label you have on screen is NOT the one you are manipulating in code.
Try placing your code in viewDidLoad instead. It should be initialized by then.
If that doesn't work, try viewDidAppear: simply to try to debug this.
It's possible that percentCorrect hasn't yet been initialized. Is percentCorrect equal to nil when that function is called, by any chance? If so, wait until after it's properly initialized to set its properties.
What are you expecting to happen? Does the label show when your code is commented out? How is percentCorrect defined in the nib?
Have you tried:
- (void)awakeFromNib {
percentCorrect.adjustsFontSizeToFitWidth = YES;
percentCorrect.numberOfLines = 3;
percentCorrect.minimumFontSize = 100;
percentcorrent.text = #"What is the text in percentCorrect?";
}
I had the same problem. Seems that setText doesn't automatically force a redraw when the change happens on a non-main thread. UI updates should always be done on the main thread to ensure responsiveness. There's another way to force it, using a selector:
label = [[UILabel alloc] init]; //assumes label is a data member of some class
...
(some later method where you want to update the label)
...
[label performSelectorOnMainThread:#selector(setText) withObject:#"New label value" waitUntilDone:false];
You may also get results from simply saying:
[label setNeedsDisplay];
which will force the update internally, but at the SDK's discretion. I found that didn't work for me, thus why I recommend the selector on the main thread.
What I found is sometimes , don't rely too much on IB , just add a line to set the frame :
labelx.frame=CGRectMake(labelx.frame.origin.x,labelx.frame.origin.y, 300, labelx.frame.size.height);
Then , autoresize works !