Possible duplicate: Looping through properties in a class
The problem is I have number of UILabels on each row upon a UITableView and I need to map the properties of my model class (which are of course NSStrings) to the label titles.
As there are multiple labels(More than 12, and it might increase later in my project), hence I was using a for loop to allocate all the labels. But for mapping the variables to the labels I have to hard code each time for the corresponding label.
Is there any way loop through all the properties of an class, so that I can declare them in an order and fetch them as an array and map it properly.
I have seen and understood the above possible duplicate link but it populates the code with as many switch cases as many times it is required to set. Instead of that is there any other alternative for concise and more clear coding using a loop.
Any help would be appreciated.
Happy coding.
If you're talking about UILabels, I will assume you want to use them via IB in Xcode, however you're creating them in code just because you can loop in code.
If so, you can think about using IBOutletCollection instead of IBOutlet like below:
#property (nonatomic, strong) IBOutletCollection(UILabel) NSArray *titleLabels;
the order in this array will be the same, as you add them in the IB ui.
Hope, this helps.
Related
In my app there's a UITableView that appears in several different UIViewControllers - same data base, same design, same IB. The difference is that in each different UIViewController the UITableView size and specific data taken from the data base is different.
I thought of creating one set of .h&.m files that will manage these UITableViews for all the different UIViewControllers and then I can avoid duplicating the UITableView methods.
I'm familiar with how to do that for UIView by creating a new Objective-C Class file of type UIView. Is there a way to do the same for UITableView or do I need to create a UIView.m&.h files and have them be delegated to UITableView?
EDIT: I misunderstood your question the first time - let me try again.
You want a class that can handle the datasource and delegate operations whereever the table is used. So this is a helper class, and it will be a subclass of NSObject. There are several ways to configure this - that said, you will almost for sure need a "delegate" - the object that instantiates this class and with whom you will most likely need to update as things happen.
So create a protocol - as you design this you will find out exactly what needs there as you code the class and try to use it.
to populate this class you have several methods:
1) use an NSArray property, and populate the array with dictionaries. Each dictionary will have the info for one row. Or if multiple sections, the array has arrays, each of the latter containing dictionaries with the information to populate cells with.
2) provide a large number of properties on the class that contain the information to configure each cell with
3) use the protocol to request information from the "owner" class on an as needed basis.
I need to know how many times a button in my program has been pressed. I tried making a category of UIButton and adding properties to it so that each time a button is pressed I would say sender.someproperty++; but the compiler complains when I add properties to a category.
Any way I can track this? I wish every object in Xcode had a random unassigned integer property that you could randomly assign it different values to keep track of each object
the first time I press the button, I want something to happen, the second time, I want something else to happen, the third time, I want something else to happen, and then the fourth time I want it to default so its like I'm pressing it the first time.
What youre going to want to do is to create a buttonPressedCounter property in the view controller of the view that the button is in, and keep track of it that way.
As for the changing functionality, define it for buttonPressedCounter = 0, 1, and 2, and after that either reset the counter in your behavior for buttonPressedCounter = 2, or your check should be based on buttonPressedCounter % 3.
EDITED FOR COMMENTS:
What you can also do, I think, is to create a new class that extends UIButton, and declare a counter property inside of it. This should work for you, and may fit your tastes better than an array of counter variables.
Might look something like this,
#interface UIButtonCountable : UIButton
{
int _clickCounter;
}
#property (nonatomic) int clickCounter;
#end
Another option again, is to not use a UIButton, but to use either a slider with 3 possible values, or segmented control, though I have little to no experience with either of those.
Subclassing UIButton is definitely dangerous, because UIButton not a single class but a class cluster. I highly recommend not doing this. According to Apple:
The class cluster architecture involves a trade-off between simplicity and extensibility: Having a few public classes stand in for a multitude of private ones makes it easier to learn and use the classes in a framework but somewhat harder to create subclasses within any of the clusters.
A new class that you create within a class cluster must:
-Be a subclass of the cluster’s abstract superclass
-Declare its own storage
-Override the superclass’s primitive methods
Instead of adding a property to the category, you can use associative references and add getter and setter methods to the category to simulate a property on the button.
I am guessing that this maybe a silly beginner question, but I cant figure out the answer to it. I basically have two view controllers in my iphone app that I would like them to share a third class (.m and .h) that suppose to hold data that both suppose to use. Lets say for example that both views are displaying locations and presenting a table with some of this information manipulated - what i'd like to do is to have a third class, like an engine, that will do all that, and those views will just instantiate this engine and read the table/location data when needed.
My question is - how can I instantiate this engine in both my views but have in fact only one copy of the engine that both views read from. I know that when instantiating twice, two copies are being created, and i dont want that. i am hoping to make this engine "global".
is this possible at all in objective c? what would be the best way to go about that?
Thank you much all.
You might consider adding a #property to both view controller's that points to your model ("engine") object. When the view controller's are created, you can set that #property to point to the model. If the #property is retain, then it won't copy the model.
You have a lot of options when it comes to this. Following an MVC approach, you are on the right track in that you should have a single copy of this data (the model). How you get that to your view controllers is up to you. I'll give two ways and you can see which works better in your situation, but there more than ways to do this. Option 1) Create a singleton to house your model/data. You've probably seen this in the SDK when using stuff like ... = [SomeController sharedInstance]. The two view controllers can just use that shared instace. Option 2) You can instantiate the model somewhere at startup and pass it directly to the view controllers. Whether it's a singleton or not is not their concern. They just know they have access to some data. You can create a property like #property (nonatomic, retain) TheData *theData for each of the view controllers and pass it that way.
Since you only have one of these "Engines", I'd suggest going the singleton route.
Create a static method that returns an instance to the object you want shared, then you can use that method in each class.
forgive my syntax... I don't have my objective C stuff in front of me atm, but essentially you'll want to do something like the following.
EngineClass.h file:
STATIC EngineClass * getSingleton();
STATIC EngineClass * INSTANCE;
EngineClass.m file:
STATIC EngineClass * getSingleton()
{
if(INSTANCE == null)
{
INSTANCE = new EngineClass();
}
return INSTANCE;
}
I'm going through a simple Objective-C/Cocoa program to try and learn the language and am getting a little confused about how some things are linked from the code I write to the interface builder.
For example, I have a simple NSString:
#property (assign) NSString *letters;
And in my interface builder, I have a text field and I use the text field's bindings to connect it to letters.
However, the example also has this:
#property (assign) IBOutlet NSArrayController *wordsController;
In the view I have a table that continuously changes and shows different words and those words are stored in an NSMutableArray. I suppose I can understand that I just can't bind the array to the the table because there are some more complexities. So in the Interface Builder I create an Array Controller and bind it to the table. In the Array Controller's bindings, I bind the Array Controller to the array of words.
I understand that the last thing I have to do is also bind the Array Controller to my NSArrayController object as well. I don't understand why I do this through the main controller object by making a connection between this outlet and the wordsController. In the Array Controller's bindings section there's a greyed out option, Content Object, which says "An NSArrayController that the NSArrayController treats as its content." Why wouldn't I set the binding here? What is the significance of it being an outlet and why is it different than my NSString letters?
Thanks
You are confusing bindings and IBOutlets. This is not unreasonable -- it's a lot of Control-dragging of connections and it can be hard to keep clear what's going on. Let me try to explain:
Bindings are a way to let Cocoa handle the mechanics of keeping a model (some collection of data, even something as simple as a single NSString) and a view (an object which displays on the screen) in sync. When you "bind" your NSString to a text field's value, you are asking the framework to communicate changes to the string or the text field "behind the scenes"; your object which owns the string gets notified to change the string's value when the text field changes, and vice versa.*
A similar situation applies to your mutable array, array controller, and table view. You're essentially right about the complications: the mutable array and the table view don't know how to talk to each other; the array controller stands in between and facilitates: ("Okay, tableView wants to know what to put in row i. Array, give me your object at index i." :) In the past, you would've had to write that code manually, and it looked very similar every time you did so.
That's what the bindings do. They are a way to reduce boilerplate code. The IBOutlet to the array controller gives your object a way to send messages to the array controller, if necessary. One simple example of why you might need to do this is to allow a menu item to trigger a method in the array controller; a document object or another controller might handle the action from the menu item and call the appropriate message on the array controller. You can also ask the array controller for its arrangedObjects to get, for example, the sorted and filtered version of its content array.
* One side note here is that your NSString property should almost certainly use retain, not assign. The object that contains this variable should be responsible for its memory.
I have view0 through view25. I don't particularly want to have a 25-case switch, so is there a way to do something like this?
- (void)modifyViewNumber:(int)number
{
[view*number* dosomething];
}
Put the views in an array at startup.
You could put a tag on each view and use a for loop with the following method:
- (id)viewWithTag:(NSInteger)aTag
Nobody's suggested NSMatrix yet? This sounds like what it's made for.
The caveat is that the views must all be controls, such as text fields or buttons. Basically, look at its class reference and see whether it inherits from NSControl at some point. If it passes that test, then NSMatrix is an option. (Here's the list of all AppKit classes, to make this easy.)
To make a control into a matrix in IB, create one of the control in the usual way, then option-drag its resize handle. It won't appear to do anything at first, but keep dragging. Instead of resizing, your control will proliferate; it is now a matrix of cells instead of a single control.
Why don't you put the views into an array and obtain references to them using the array index?
- (void)modifyViewNumber:(int)number
{
UIView* view = [views objectAtIndex:number];
[view dosomething];
}
Many people have said use an array--I do this all the time, it's really the only way to go when using an interface builder, but I wanted to add a little.
Sometimes getting the values into the array can be tricky. There is usually a way to get an array of all controls on the screen. usually I'll grab that and iterate over it looking for a type of control with a certain naming pattern and collect those into my own array.
In this way, you can often add a new control with no code change whatsoever (always one of my favorite goals).
Create an array of views. Add each one, in order, then reference it by the array index.
If the numbers are not sequential, use a hash table.
Reflection might be an option, but could be slower (I'm not an Objective C guru, don't even know if that is practical).
I assume you're using Interface Builder to setup those views?
Someone may have to correct me on this, but I believe you can create an NSArray Interface Builder outlet in your class and then assign all your views to it. For example, you could declare "IBOutlet NSArray * views;" in your header file, and then use interface builder bindings to tie all 25 views to that property. They'll automatically be added to the array, and then you can cleanly iterate over it in your code.
Either use a collection or Reflection.
Assuming Interface Builder (otherwise straightforward as answered before). This is the best I could manage:
In .h:
{
UILabel *banner[NUM_BANNERS];
}
#property (nonatomic, retain) IBOutlet UILabel *banner0;
#property (nonatomic, retain) IBOutlet UILabel *banner1;
#property (nonatomic, retain) IBOutlet UILabel *banner2;
etc.
In .m:
- (void)viewDidLoad
{
banner[0] = banner0;
banner[1] = banner1;
banner[2] = banner2;
etc.
Then can access by array index. Remember to release.