Why setting labels.text from NSMutableArray does not work? - ios

The following code
NSMutableArray *textLabels = [[NSMutableArray alloc] initWithObjects:cell.textLabel1.text, cell.textLabel2.text, cell.textLabel3.text, cell.textLabel4.text, cell.textLabel5.text, nil];
for (int i=0; i<json.count; ++i)
{
textLabels[i] = [NSString stringWithFormat:#"#%#",[json[i] valueForKey:#"text"]]];
}
write to textLabels array correct string values, but labels on the simulator do not change. Why?

It seems that you think asking the label for its text returns an updatable reference to the label value, but this is not the case. The returned string is an immutable object and your code is simply replacing those values with other immutable values.
To update the labels you should hold references to the labels themselves in an array, then you can index into that array and set the text of each. You don't need to store any of the text in an array.
You can add the labels to an array manually or with an IBOutletCollection depending on what your UI definition is.

Related

How to compare various NSArrays in Objective-c?

My code contains four NSArrays, each of which contains two objects which represent XY-Coordinate at any point on the screen. Two or more arrays may contain same set of coordinates. I need to find the coordinate which has highest number of repetition among these four arrays. Can the isEqualTo: method help in this case?
One approach would be to maintain an NSDictionary, use the coordinates in your arrays as keys and then maintain a counter for each coordinate (i.e. key) that you increment whenever you see the same coordinate.
This could look somewhat like this:
NSMutableDictionary *coordinateCount = [[NSMutableDictionary alloc] init];
for (int i = 0; i < coordinates.length; i++) { // do this loop for each of your 4 arrays
Coordinate *c = coordinates[i];
if ([coordinateCount containsKey:c]) {
NSInteger count = [coordinateCount[c] integerValue];
count++;
coordinateCount[c] = #(count);
}
else {
coordinateCount[c] = #(1);
}
}
// now you can retrieve the max count value from all collected values
Note that this code is not tested and has to be adjusted depending on your types and variable names.

iPhone - how to select from a collection of UILabels?

I have a few UILabels, any one of which will update according to the index of an NSArray index they represent. I thought of selecting them by their tag
self.displayLabel.tag = myArray[index];
but that changes the tag value to whatever my array is holding at the moment
Using a dictionary for whatever tricks it offers instead of an NSArray doesn't help because i still have to select the correct matching label. This is the effect i want to achieve.
self.|mySelectedLabel|.text = myArray[index];
what should i put in |mySelectedLabel| to get the one i'm looking for?
I'm almost ashamed to ask at my reputation level, but this is stymie-ing me
every search only turns up how to set Labels and change, not the process of selecting
Assuming you have set the tags to the appropriate index to match your
array indices you can use [self.view viewWithTag:index];
Why are you not setting the tag with:
self.displayLabel.tag = index;
Also, you could just loop though an array of labels and find the right one:
for (UILabel *label : labelArray) {
if (label.tag == index) {
label.text = #"I found you!";
}
}
Rather than using tags you can refer to your specific textfields by reference:
// Create an array to hold your textfields
NSMutableArray *textFields = [NSMutableArray array]
// Create your textfields and add them to the array
UITextField *textField;
for (NSUInteger idx = 0: idx++; idx < numberOfTextFieldsYouWant) {
textField = [UITextField alloc] initWithFrame:<whateverYouWant>];
[textFields addObject:textField];
}
Since you are adding the objects to an array, rather than using the tag value 0, 1, 2... you can just access it by it's index in the array
So, for what you want to do you can just do:
textfields[index].text = myArray[index];
It's a lot cleaner, doesn't rely on magic tags, and you have an array of all your dynamic textfields that you can remove, or change in one place.
I think tags are vastly overused, and they aren't necessary in most cases.
Just letting you know I reframed the problem and this eventually worked for me without having to use an array
( with endless experimenting, I sort of bumped into it so I don't know if it constitutes good technique )
the desired label corresponding to the bag weight ( one of a number possible ) displays the right update
- (IBAction)acceptWeight:(UIButton *)sender {
int tempValue = (int) currentWeight;
// current weight comes from a UISegementedController
for (UILabel *labels in self.view.subviews)
{
if (labels.tag == currentWeight)
{
bags[tempValue]++;
labels.text = [NSString stringWithFormat:#"%i",bags[tempValue]];
}
}
totalKilo = totalKilo + (int)currentWeight;
self.totalKilo.text = [NSString stringWithFormat:#"%d",totalKilo];
}

Loop in a variable of type IBOutlet

I have twelve text fields as you can see below:
IBOutlet UITextField *ce_1;
IBOutlet UITextField *ce_2;
IBOutlet UITextField *ce_3;
....
IBOutlet UITextField *ce_12;
All I have to do is to set an existing object in an array in each of the variables that are responsible for the text fields, I'm currently doing as follows:
ce_1.text = myArray[1];
ce_2.text = myArray[2];
ce_3.text = myArray[3];
....
ce_12.text = myArray[12];
Not to be writing a lot, I thought I'd put this in an automated way within a loop as follows:
for(i=1;i<13;i++){
ce_[i].text = myArray[i];
}
But this command does not work the way I expected, so I would like your help to try to solve my idea and put it into practice, is there any way of doing this?
Research and start using IBOutletCollection. It will give you an array of text fields that you can build in your storyboard XIB.
Note that you may need to consider the order of the array, and that you might want to sort it (possibly based on the tag of each view).
Technically, you could use string formats and KVC to do what you're currently trying to but it is far from ideal.
You can't just replace ce_1 ce_2 ce_3 with ce_[i] it doesn't work that way. You can only use [number] with an nsarray variable (or decendents).
for example:
NSArray* myArray = #[#1];
NSLog(#"%#", myArray[0]);
You might want to look into IBOutletCollection in order to achieve something similar to what you're looking for.
However, contrary to other answers here IBOutletCollection are ordered by how you link them in the interface builder.
Refer to this for IBOutletCollections: How can I use IBOutletCollection to connect multiple UIImageViews to the same outlet?
You can use IBOutletCollection. You can also use key-value coding:
for(NSUInteger i = 0; i < 13; i++)
{
[[self valueForKey:[NSString stringWithFormat:#"ce_%u", i]] setText: myArray[i]];
}
This will give you what you want.
The way I like to handle these situations is creating a temporary array containing all the text fields:
NSArray *allFields = #[_ce_1, _ce_2, _ce_3, ...];
NSInteger i = 0;
for (UITextField *tf in allFields)
{
tf.text = myArray[i];
i++
}
IBOutletCollection also work but sometimes it gets hard to figure out when you come back to your project which label is #3 or #5 and such... I find this works better for me usually :)

Clarification on Objects in NSArray

If this is a noob question, I apologize in advance. I just want to clarify how the relationship between the objects inside an array relates to the actual object. For example:
UILabel *labelOne = //init stuff
[self.view addSubview: labelOne];
[labelArray addObject: labelOne];
Now if I change the property of the object inside the array like so:
[[labelArray objectAtIndex:0] setText:#"NEW STRING"];
Am I updating just what is inside the array or will it also update my initial UILabel and therefore reflect the change on the view? Are there any situations where the results might differ? (i.e. releasing initial UILabel with object still in the array, etc.)
The array stores a strong reference to the object, but doesn't copy it. So there is only ever one label. So the code you showed will update the label's text.
It will change the UILabel you have on screen since NSArray only holds references to objects, it doesn't make copies. So whatever labels you are putting into the array are just references to what you've already created.
Yes it will update your initial UILabel and therefore reflect the change on the UIView as reference of UILabel is stored in array.
IT will update your initial UILabel as NSArray is holding the reference of original UILabel and not there copies
Your labelArray will contain pointers to each adding object. And it increment retain counter for each adding object. So [[labelArray objectAtIndex:0] setText:#"NEW STRING"]; will change labelOne.text too, because you reference to one UILabel object.
UILabel *labelOne = //init stuff
[self.view addSubview: labelOne];
[labelArray addObject: labelOne];
[[labelArray objectAtIndex:0] setText:#"NEW STRING"];
The label which you add to labelArray is the same object as initial labelOne.
But if you what to avoid such behavior you can add a copy of labelOne to labelArray by using copy method.
[labelArray addObject: [labelOne copy]];
This will give you a copy of labelOne object in you labelArray. And this copy will not be changed after you change label text.
So after you get labelOne from array the label will be in initial state.
Yes this will change the value of the label text displayed on the view. See here I have simulate the scenario..
Code....
UILabel *labelOne = [[UILabel alloc] initWithFrame:CGRectMake(20, 30, 200, 20)];
labelOne.text = #"Dilip";
[self.view addSubview: labelOne];
NSMutableArray *labelArray =[[NSMutableArray alloc] init];
[labelArray addObject: labelOne];
[[labelArray objectAtIndex:0] setText:#"Hi Dilip"];
And here is the output..
You can see that instead of text "Dilip" there is displayed text is "Hi Dilip".
The labelArray stores only the reference of the labelOne. so if you change anything in the labelArray affect the labelOne.

uitableview ios: sorting array based on calculated distance not part of the array

I have an array of points on a map.
I populate the array correctly and I make annotations for them on the map. everything is working fine.
I have another tableview with the same array, and in the "subtitle" of the cells, I calculate the distance to user and present. everything working fine.
Now,I want to sort the list in the table view, in other words I want to sort the same array by distance, lowest to highest.
The thing is that the distance is not part of the array. so how can I cross match the distance with the array, so that when I sort the distance, it takes its belonging object in the array with it and sorts the array as well?
I am fairly new to ios but I have managed to release 3 apps now, and this one is the fourth, far more complex and I think I have covered pretty good ground with making the app so far. From the mapview, to the tableview with a search controller and everything. I am only missing the sorting.
I imagine I need to add some tag or property to each object in the array and assign it to each distance in the distance array.
Any suggestions would be appreciated :)
Thanks in advance.
// Assuming you have your points on the map in an NSArray called
// pointsOnMapArray and your distances in distanceArray, create a
// new mutable array to hold both. Note, the "distances" in this
// case are stored as NSStrings. We'll want to convert them to
// doubles before sorting them.
NSMutableArray *newArray = [[NSMutableArray alloc] init];
// Iterate over all of the points, and add a new element to the mutable
// array which is a new array containing a point and its distance. The
// distance is converted from an NSString to an NSNumber containing a
// doubleValue.
int i;
for (i = 0; i < pointsOnMapArray.count; i++) {
NSArray *newItem = [NSArray arrayWithObjects: [pointsOnMapArray objectAtIndex: i], [NSNumber numberWithDouble:[[distanceArray objectAtIndex: i] doubleValue]], nil];
[newArray addObject: newItem];
}
// Now, sort the new array based upon the distance in the second element
// of each array (ie, the distance).
[newArray sortUsingComparator: ^(id obj1, id obj2) {
NSNumber *dist1 = [obj1 objectAtIndex:1];
NSNumber *dist2 = [obj2 objectAtIndex:1];
return [dist1 compare:dist2];
}];
try making a dictionary with distances and elements of array . then by sorting the distances , array elements can be sorted accordingly.
NSMutableDictionary *dict=[[NSMutableDictionary alloc]init];
[dict setObject:(array element) forKey:(correspondingDistance)];
Now by sorting the keys , you can sort the elements of your array accordingly.

Resources