A UITableViewCell by default has a textLabel property. Now, I've subclassed UITableViewCell, and have set up my own text layout system that doesn't use textLabel. To reduce chance of error, I'd like to make the default property textLabel unavailable to the compiler (auto-complete), and that if I try to access it outside the class, the code will not compile.
Making the property readonly will still allow me to access and change the label's properties, so that won't work.
Is there any way to do this?
Edit:
So the closest I've gotten so far is redeclaring the property in my subclass and deprecating it:
#property (nonatomic) UILabel *textLabel NS_DEPRECATED_IOS(2_0, 3_0);
which currently gives me a warning if I try to access the property. But this doesn't completely hide it from the compiler, and it also gives me a warning "Availability does not match previous declaration".
Ok, figured it out. You can use the UNAVAILABLE_ATTRIBUTE macro to accomplish this:
#property (nonatomic) UILabel *textLabel UNAVAILABLE_ATTRIBUTE;
and then doing cell.textLabel gives a compile error: textLabel is unavailable.
Its readonly. You can access but not assign. See header file.
#property(nonatomic,readonly,retain) UILabel *textLabel
//Example
#interface myCell : UITableViewCell
{
}
#end
#implementation myCell
-(void)check
{
//You can access
UILabel *label = self.textLabel;
//You canot assign
self.textLabel = label;
}
#end
Related
For reference, I'm trying to learn Objective-C through the Stanford iTunes-U course. I wanted to update one property from the setter of another (they are inherently connected. Also, is that bad style?). The property I am trying to update is a UILabel, but it doesn't work like I thought.
This code is in one of my view controllers:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
[segue.destinationViewController setProgram:self.brain.program];
}
Naturally, this code calls the setter for the Program property of the incoming viewController. Here's that setter code:
-(void)setProgram:(id)program {
_program = program;
self.title = [CalculatorBrain descriptionOfProgram:program];
[self.graphview setNeedsDisplay];
self.testLabel.text = #"Trying to update your text!";
}
and the header file:
#import <UIKit/UIKit.h>
#interface GraphViewController : UIViewController
#property (nonatomic, strong) id program;
#property (weak, nonatomic) IBOutlet UILabel *testLabel;
#end
Now, when this code is run, as the segue happens, the new view DOES have its title changed (the self.title line works). However, the UILabel DOES NOT get updated. Furthermore, if I call the setter again say in viewDidLoad, it does change the UILabel. Is this because of self being updated? What's going on here?
In one of the lectures, the professor explains that outlets aren't set yet in prepareForSegue. This means testLabel is nil, and you're sending a message to nil (which is allowed and doesn't crash your app). To solve your problem, set the textLabel's text in viewDidLoad or viewWillAppear.
I believe this is "fixed" in iOS 6, but it won't be backwards compatible, so if you want to support iOS 5 still, you'll have to use viewDidLoad or viewWillAppear to update outlets (which I think is better to do anyway).
I have a series of UILabels that form part of an IBOutletCollection
#property (strong, nonatomic) IBOutletCollection(UILabel) NSArray *labelCollection;
I have sequentially set the tags of the UILabels to 0,1,2,3 ... and I have sorted the *labelCollection by tag number. Thus, object '0' in the IBOutletCollection array is the UILabel with tag '0' etc.
Using the following function I can update the text of the UILabel at a particular obj/tag:
- (void) updateLabelAtTag:(int)objId {
[[self.labelCollection objectAtIndex:objId] setText:#"my new text"];
}
}
This works fine, however, when you click on the setText: in the IDE, Xcode Quick Help complains
setText:
#property(nonatomic, copy) NSString *text
iOS (2.0 and later)
Deprecated: Use the textLabel and detailTextLabel properties instead.
The text of the cell.
UITableViewCell.h
For the life of me I can't figure out what UITableViewCell has to do with this situation. I certainly don't appear to be able to access the textLabel or detailTextLabel properties.
Question: Am I using a deprecated property, or has Xcode got it wrong in this instance?
Xcode. I suspect
[(UILabel *)[self.labelCollection objectAtIndex:objId] setText:#"my new text"];
would make it go away.
I am trying to get an NSSrollView with an NSTextField in it to work, however the scrollbars do not seem to respond to anything that I am coding.
I am declaring the NSScrollView as an IBOutlet, add it as a property and then synthesizing it. However, it's to no avail.
The scrollbars do appear when I resize, however they serve no function at the moment.
I have tried to use the apple documentation, but again, no joy there.
Any help? Thanks!
As You was saying "For my purposes, any container which scrolls will do the trick" You can use NSTextView in an NSScrollView. And for setting text You need to use setString instead setStringValue.
Example how to set text in NSTextView:
.h
IBOutlet NSTextView *textView;
.m
-(void)awakeFromNib {
NSString *string = #"my text";
[textView setString:string];
}
Don't forget IBOutlet NSTextView not NSScrollView.
NSTextView is in NSScrollView:
Are the objects/controls that you created using IB accessible from a class method?
#Nekto:
#interface CopyController : UIViewController
{
UIActivityIndicatorView *myActivity;
}
#property (nonatomic, retain) IBOutlet UIActivityIndicatorView *myActivity;
+(void) activityIndicator:(BOOL)flag;
#end
This implementation in the .m will not be allowed, the error was "Instance variable'myActivety' accessed in class method".
+(void)activityIndicator:(BOOL)flag
{
if (flag)
[myActivity startAnimating];
else
[myActivity stopAnimating];
}
Yes, they are accessible.
You should add #property IBOutlet ib_object_class *ib_object_name;, open that object settings in IB and set reference outlet to File's Owner by selecting ib_object_name in drop down menu.
Full explanation can be found, for example, here : Creating and Connecting an Outlet
You may be able to connect the outlet to the first responder instead of the file's owner to achieve this, but I don't think you can access it from within a class method since your IBOutlet property is going to be an instance-level variable.
Found something similar for linking actions to multiple first responders here.
All,
In Apple's sample code "DateCell"
http://developer.apple.com/library/ios/#samplecode/DateCell/Introduction/Intro.html
the ivar "pickerView" is declared in MyTableViewController.h like this:
#interface MyTableViewController : UITableViewController
{
#private
UIDatePicker *pickerView;
UIBarButtonItem *doneButton; // this button appears only when the date picker is open
NSArray *dataArray;
NSDateFormatter *dateFormatter;
}
#property (nonatomic, retain) IBOutlet UIDatePicker *pickerView;
...
It is synthesized in the class file MyTableViewController.m like this:
#implementation MyTableViewController
#synthesize pickerView, doneButton, dataArray, dateFormatter;
...
When this app runs, I can insert NSLog(#"%#",pickerView) into ViewDidLoad and see that, sure enough, the ivar pickerView is real and has a value. Nowhere, though, does this class alloc/init pickerView. And that's the root of the question: how's it getting done if it's not being done explicitly?
Well, I naively copied this stuff to my code into my RootViewController.h and .m files figuring I could do the same, but pickerView stubbornly remains uninitialized (and my NSLog calls return "(nil)" as its value) no matter what I try short of explicitly alloc/initing it. Certainly RootViewController is being instantiated, or the RootView wouldn't be showing up, right? So shouldn't my pickerView be coming along for the ride just as it does for Apple?
So... do I have to manually alloc/init the pickerView instance variable? If so, where's Apple doing it? Or how are they doing it somehow otherwise?
I think I'm missing something very basic here, but I have no idea what it is. I can't see anything in Interface Builder or XCode that looks different between mine and theirs, but I've got tunnel vision at this point and can't see anything clearly anymore.
Thanks,
Bill
The IBOutlet modifier on this line is the key...
#property (nonatomic, retain) IBOutlet UIDatePicker *pickerView;
IBOutlet is a decorator that indicates that the object will be hooked up/connected/initialised when the corresponding xib (Interface Builder) file is loaded. The sample application you're looking up will contain a UITableViewController is a xib which has a connection to a UIPickerView.
You can either go the route of creating your own custom xib file and wire to an instance of UIPickerView or you can manually initialise the picker yourself.
Interface Builder (nib or xib) treats automatically IBOutlet ivar with connection of components.
IBOutlet is a special keyword that is
used only to tell Interface Builder to
treat an instance variable or property
as an outlet. It’s actually defined as
nothing so it has no effect at compile
time.
Your First iOS Application - The
View Controller Interface
Declaration, Making Connections
Interface Builder User Guide -
Defining Outlets and Actions in
Xcode