Now I understand that this question has been asked before, but the answers were unsatisfactory. My issue is that I have a view controller with a view and stuff in it including a label. I added a bunch of code for it and now I'm expanding on it. I now have an issue where I've decided to add another UIView to my interface and it has a label and that label is going to function EXACTLY like a label I have in my first UIView. My problem is that I don't want to have to go in my view controller method and add another line of code each time I manipulate that first label. Is there anyway I can link another label to my initial IBOutlet I have set for my first label? Or do I have to go in my code and add an extra line of code everytime I manipulate that first label?
It depends on what you want to do to that label. If you're looking to change some of the attributes of the label in the same way (e.g., font, text colour, alignment) then you can put both labels in an IBOutletCollection and iterate over the collection in your view controller.
If you want to have different data in the label, but other attributes the same, then you'll need a separate IBOutlet for that label.
You can combine the two techniques as well. e.g.
(interface)
#property (weak, nonatomic) IBOutlet UILabel *firstName;
#property (weak, nonatomic) IBOutlet UILabel *lastName;
#property (strong, nonatomic) IBOutletCollection(UILabel) NSArray *labels;
(implementation)
- (void)viewDidLoad {
[super viewDidLoad];
for (UILabel *aLabel in self.labels) {
// Set all label in the outlet collection to have center aligned text.
[aLabel setTextAlignment = NSTextAlignmentCenter;
}
[self.firstName setText:#"First Name"];
[self.lastName setText:#"Last Name"];
}
Basically the simple answer is no. Whether you use outlets or an outlet collection or tags or whatever, you ultimately have one reference in your code to one label in your interface, and another reference in your code to another reference in your interface. You can compress your mode of expression so as to cycle readily through those references (as suggested in a different answer), but the basic fact is inescapable that, ultimately, the only way to "talk to" a label is through the one reference that points to that label and to that label alone.
The only way of getting around that is not to use direct references at all. For example, a single message can be sent to multiple recipients by using an NSNotification. So you could have two instances of some UILabel subclass of your own, and "shout" to both instances simultaneously by posting a notification from your view controller - the notification is then automatically passed on to both labels, because you have arranged beforehand for them to register for it.
Similarly, another alternative is that you could use key-value observing so that a change in your view controller is automatically propagated to both labels automatically because they "observe" the change, meaning they are sent notifications - really just an inverted form of NSNotification. (If this were Mac OS X, you could make a simpler, safer version of this arrangement by using "bindings".)
However, I really cannot actually recommend that approach. The truth is that we still live in an excruciatingly primitive world of text-based programming, one line at a time, one command at a time, one reference at a time, and we must just bite the bullet and get on with it.
Swift 3, Xcode 8
Create a prototype cell with objects
then add another prototype
It will copy the objects from the first prototype cell.
The new objects will be connected to the same IBOutlet
Also, copy and pasting objects maintains IBActions, but does not maintain IBOutlets.
I hope this answers your question, as none of the other answers had this work around.
Related
Before you tell me that all I need to do is import UIKit, I know all about importing, and NO, that's not what I need to do in this case. Intrigued? Confused? Read on...
I have two different, but similar, custom UITableViewCells. Both have a UILabel and a UISwitch. Version one, DisplayCell, has a second UILabel, while version two, EditCell, has a UIPickerView. How I use them is like this, in a static UITableView that I'm using as a fill-in-the-data form, DisplayCell is the standard view which displays the selected value. The user can tap on DisplayCell to replace it with EditCell, then use the UIPickerView to pick a new value and hit done (button in the nav bar at the top). DisplayCell is then brought back, displaying the newly selected value. In either version the user can tap the switch to toggle whether or not the value from the UIPickerView should be used elsewhere in the form.
When it came time to write the code for the tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> (UITableViewCell) function I decided to rewrite my code so that I have a single class, SwitchCell that inherits from UITableViewCell and contains the IBOutlet and IBAction for the switch, then have DisplayCell and EditCell inherit from SwitchCell.
This works fine, however DisplayCell is now nothing more than a IBOutlet for a UILabel, and UITableViewCell, which DisplayCell inherits from via SwitchCell already has two UILabel IBOutlets, textLabel and detailTextLabel. The whole purpose in creating SwitchCell was to try and minimize code by only ever write any block of code once, something that I'm a bit of a fanatic about. Thus I would very much rather have the UILabel in DisplayCell use the detailTextLabel IBOutlet from UITabelViewCell, rather than having to create a 'redundant' UILabel IBOutlet for it.
In order to link to an IBOutlet in a superclass you must be able to bring up the code for that superclass in the assistant editor. Then you can just control+drag and link like normal. Which means, in theory, I believe it should be possible to link my UILabel to UITableViewCell's detailTextLabel, if I can access the appropriate line from the source code for UITableViewCell in the assistant editor. Is this possible, and if so, how?
Oh, and I'm working exclusively in Swift in this project, FYI.
tl;dr: It's really not anymore efficient to use UITableViewCell's default UILabels than it is to just add your own.
In order to link to an IBOutlet in a superclass you must be able to bring up the code for that superclass in the assistant editor.
Well, that's not correct. The assistant editor is not required to link to an IBOutlet defined in a superclass. But that's not important here anyway.
You can't link to detailTextLabel in Interface Builder because it's not defined with the #IBOutlet attribute. And although it is possible to override properties in Swift (so you can add #IBOutlet to it), that won't work in this case because an IBOutlet has to be mutable, and the superclass has defined the variable as immutable.
Now you could overcome this by adding your own setter method in the subclass to make the property mutable. I was able to do this with the following code:
var _detailTextLabel: UILabel?
#IBOutlet override var detailTextLabel: UILabel? {
get {
return super.detailTextLabel
}
set {
_detailTextLabel = newValue
}
}
I could wire this up in Interface Builder just fine. So perhaps I could tweak this code to actually get an set what I want (I don't think it would work as shown here). We're so far outside the realm of common-sense coding that we just need to stop and give up on this idea.
Thus I would very much rather have the UILabel in DisplayCell use the detailTextLabel IBOutlet from UITabelViewCell, rather than having to create a 'redundant' UILabel IBOutlet for it.
I can relate. I'm just as anal. :-)
However, if you do a little testing (or read the UITableViewCell header file) you'll see that UITableView is smart enough (optimized enough?) to not actually add a UILabel to the content view unless you try to use it. So at worst you have an unused property.
So it's really not inefficient to just add your own UILabel and property.
Quite a simple one I assume but searching has failed me.
I have a UITextView I set up in a Storyboard with some dummy text. Dynamically I would like to change the content of this, but I don't know how. Searching for this seems to only returns results in which the UITextView has been created programmatically as opposed to via a drag and drop on the Storyboard, hence they have direct access to a variable representing it.
Add an outlet to UITextView then changed it dynamically!
Like this:
#property (weak, nonatomic) IBOutlet UITextView *yourText;
self.yourText.text = // ANY TEXT HERE
How to change the diagrams displayed in the same view?
I have a view inside a view controller.
This view has another view inside it, to which I have allocated a custom class (sub-classing UIView).
This custom class has the code to draw interactive diagrams in this view.
The interactive code is operated by sliders in the main view.
I have all this in interface builder.
What if I want to draw a completely different diagram in this view?
I would like to be able to allocate a new class to this view, with a different set of drawing code? But how?
There are many ways to do this, but changing the class at runtime is not advisable
Here are a few suggestions:
1 / Replace customView1 with a different view instance of the right type in the same location as your first view...
self.customView2 = [[CustomView2 alloc] initWithFrame:self.customView1.frame];
[self.view addSubView:self.customView2];
[self.customView1 removeFromSuperView];
This example uses a distinct property for each of the swapped subviews, but you could use a single property just to refer to the current subview - this could help link up your sliders to do the right thing to the diagrams. If you are doing a lot of this you will need to think about memory issues - when customView1 has gone, will you be reusing it? You can keep it hanging around in a (strong) property (faster, needs more memory), or create a new one each time (slower, needs less memory).
2 / if you want to toggle between them, you could place both in Interface Builder and toggle their hidden properties or their order in the view hierarchy (self.view.subviews array). Saves having to constantly recreate the views.
3 (better...) / Keep to a single subclass of UIView and use properties to affect the diagram that gets drawn...
//CustomView.h
#property (nonatomic,assign) BOOL drawDiagram1;
#property (nonatomic, assign) BOOL drawDiagram2;
//CustomView.m
- (void)drawRect {
if (drawDiagram1) [self drawDiagram1];
if (drawDiagram2) [self drawDiagram2];
}
- (void) drawDiagram1 {
//drawDiagram1 code here
}
- (void) drawDiagram2 {
//drawDiagram2 code here
}
I have been developing in xCode for exactly 3 days now. The last time I did UI development it was in Windows 3.1 with the Petzold book. Regardless of that I have my first iOS app up and running and it basically does what I need. I have two sliders to select hue and saturation, and in response to them I dynamically draw a bunch of gradient shaded circles. I got that much running between the Hello World example and stackoverflow, including caching the gradient in CGLayer (so thanks to all the stackoverflow people). There is one little piece that I can't quite get right though:
I want to set the initial value of one slider to 1.0 instead of the default 0.5. I know I can do that in IB, but I prefer to code it and I think I'd like to move away from IB altogether. I don't really understand how it makes connections between things and I'd like to understand the code. I have code like this to try to set it:
- (void)viewDidLoad
{
NSLog(#"viewDidLoad");
[super viewDidLoad];
[hue_slider setValue:0.5];
[sat_slider setValue:1.0];
self.led_view.hue_slider_value=0.5;
self.led_view.sat_slider_value=1.0;
// Do any additional setup after loading the view, typically from a nib.
}
sat_slider still ends up in the middle instead of at the end (1.0 is the max value). From stackexchange reading I understand that I am probably calling this at the wrong time, that the slider hasn't really been loaded when viewDidLoad is called, and my initial value is overwritten by the one specified in IB. What I haven't seen though is where the call should be made. So the question:
Where in my program should I put
[sat_slider setValue:1.0];
so that it sets the initial value of the slider, overwriting the default in IB? Can someone explain the order of how things start up in an iOS program? And a pointer to online or printed books regarding iOS and Objective C programming would be great.
Edit
When I check the value of sat_slider it is nil. So that means a connection is missing? I dragged it in the storyboard and created an IBOutlet in addition to an action.
#interface led_testViewController : UIViewController
- (IBAction)saturation_scroll:(id)sender;
- (IBAction)hue_scroll:(id)sender;
#property (retain, nonatomic) IBOutlet UISlider *hue_slider;
#property (retain, nonatomic) IBOutlet UISlider *sat_slider;
#property (strong, nonatomic) IBOutlet led_view *led_view;
#end
You may put the code in - (void)viewWillAppear:(BOOL)animated;
I followed the suggestions of ABC and NJones to check sat_slider and it was nil. There were properties for both sat_slider and hue_slider in the ViewController.h file, but something was still missing. I deleted the properties, re-dragged them in IB, and then I was able to set the slider position in viewDidLoad with no problems.
Check if sat_slider nil. Also make sure that it is properly connected in IB. If not, remove it and add it again in nib/storyboard. That should fix the issue.
I am using one simple UIViewController for my application which is not too complicated. It has two pages. On the first page I enter data in to text boxes to indicate user changeable data which will be handled on the second page.
#property (weak, nonatomic) IBOutlet UITextField *routeText;
When I am running my actions on the second page, I use a command like this to access what was typed in to the text box:
NSString *variable = [[NSString alloc]initWithFormat:#"%#",self.routeLabel.text];
self.consoleView.text = variable;
But the value is always (null). I am using the same TravelViewController.h/.m for all of the code. My question is: Is this not acceptable coding behavior to share it in this way or do I need to define the objects in a different way so the text can be shared between views?
Thanks for any help you could provide.
If it is a different view controller you need to pass the text from parent view controller to child using #property. Declare it in second class and when you are pushing from first screen to second, set this value in #property. After that you can use it in second screen using self.text.