I have the following code that I need to use multiple times (at least 10 times):
if([_btn_gv_tl1 isEqualToString:#"on"])
{
btn_gv_tl1.tag = 1;
UIImage *btnIMG_gv_tl1 = [UIImage imageNamed:#"stateOn.png"];
[btn_gv_tl1 setImage:btnIMG_gv_tl1 forState:UIControlStateNormal];
}
else
{
btn_gv_tl1.tag = 0;
UIImage *btnIMG_gv_tl1 = [UIImage imageNamed:#"stateOff.png"];
[btn_gv_tl1 setImage:btnIMG_gv_tl1 forState:UIControlStateNormal];
}
The problem is that I use multiple variables. _btn_gv_tl1 is a string, btw_gv_tl1 is a button, etc.
I named my variables from _btn_gv_tl1 to _btn_gv_tlx with all the variables.
How can I use the code above multiple times without copying and pasting the code? I think it is much nicer to create a loop.
Thanks!
Store those items in NSArray. You can read about them here. If you do so, it's easy know to iterate thorough this objects:
for (id object in objectsArray) {
// Do anything with ths objects
}
Update
Do the multi-dimensinal array (array of arrays) like this:
NSArray *array = #[#[object1, object11, object111],
#[object2, object22, object222],
#[object3, object33, object333]];
Related
I have a user input in my app, according to which, the number of arrays that I need to create changes (user inputs the number of channels into which I need to split an incoming data stream, with one array for each channel). The number of channels can be any multiple of 4 up to 32. I want to know whether there is a way to automatically initialize arrays, perhaps using for loops like in this pseudocode:
for(initialization, numberOfChannels, increment) {
NSString (set array name to channel%dArray, i);
NSMutableArray *channeliArray = [[NSAMutablerray alloc] init];
}
Everywhere I've looked, I didn't find any way to set the name of the array dynamically and hence allow initializations like the one above. Even using a 2D array would have the same problem. Any help is appreciated. Thank you!
Just use a two dimensional array as per #Jonah's comments -
self.channels=[NSMutableArray new];
for (int i=0;i<numberOfChannels;i++) {
[self.channels addObject:[NSMutableArray new]];
}
Then you can access a particular channel's array by index -
NSMutableArray *channel=[self.channels objectAtIndex:channelNumber];
Or, if you wanted to use channel names as per your pseudocode, use a dictionary of arrays
self.channels=[NSMutableDictionary new];
for (int i=0;i<numberOfChannels;i++) {
[self.channels setObject:[NSMutableArray new] forKey:[NSString stringWithFormat:#"channel%dArray",i]];
}
Then you can access a particular channel's array by name -
NSMutableArray *channelArray=[self.channels objectForKey:#"channel3Array"];
I have an iOS app that I load data from a server into an NSArray and then into UITableView.
This works fine. However, when the user pulls down to refresh the data, I make a new call to my server and grab data again. This new data contains objects that my local data already has and any new objects.
So localArray when populated for the first time will have objects, [A,B,C,D]. I then add a new object server side and refresh the data on the iOS app.
serverData will now have objects [A,B,C,D,E,F] - I need to add, E,F to localArray.
I thought a nested for loop would be the answer, something like this:
NSMutableArray *newItems = [NSMutableArray array];
for (BBItem *itemA in serverDataArray){
for (BBItem *itemB in localArray){
if (![itemA.name isEqualToString:itemb.named]){
//add to a newItems array
}
}
}
However I end up with newItems array containing a lot of duplicates of the same item. What is going on here?
Your algorithm will add an item to newItems if it's not equal to one item from localArray. Therefore, you would end up with lots of identical items most of the time.
You cannot add inside the nested loop. You need to go through all localArray, see that the item is not there, and only then add it. Here is how to fix your code:
for (BBItem *itemA in serverDataArray){
BOOL there = NO;
for (BBItem *itemB in localArray){
if ([itemA.name isEqualToString:itemb.named]){
there = YES;
break;
}
}
if (!there) {
//add to a newItems array
}
}
This is inefficient, because the inner loop goes through all items that you currently have. As the number of local items grows, this loop will get slower and slower. You would be better off maintaining an NSMutableSet of names of local items, because you can check it in constant, rather than in linear, time:
NSMutableSet *localNames = [NSMutableSet set];
for (BBItem *itemB in localArray) {
[localNames addObject:itemB.name];
}
for (BBItem *itemA in serverDataArray){
if (![localNames containsObject:itemA.name]) {
//add to a newItems array
}
}
I'm not sure if I'm asking this correctly. What I want to do is be able to define my objects, a title and an image, in a different class and use it in ViewController.m. Currently, and I know this isn't good, I have a large if statement in ViewController.m defining all of these objects.
So, it's like:
v = arc4random() % 10000;
if ([textBox.text isEqualToString:#"1"]) {
if (v<=25) {
titleLbl.textColor = [UIColor orangeColor];
titleLbl.text = #"Text";
objectImg.image = [UIImage imageNamed:#"image.png"];
And this type of code repeats for a few hundred lines. With this code currently, as you can probably guess, I'm getting this:
WARNING: Slow defaults access for key ClientState took 0.076678 seconds, tolerance is 0.020000
I'm thinking that if define all of these in a different class, this error won't happen. I might be wrong though. So, the questions are will defining the objects in a different class fix this warning and how would I go about doing that?
This question already has answers here:
Getting a random object from NSArray without duplication
(3 answers)
Closed 7 years ago.
I have an array of random properties I would like to assign to equipment within the game I'm developing.
The code that I use below is returning an NSArray. I'm interested if there's way to get item indices from that array without getting duplicate values. The obvious solution is to create a mutable array with the returned array, do random, remove item that was returned and loop until the number of items is received.
But is there a different way of getting X random items from NSArray without getting duplicates?
//get possible enchantments
NSPredicate *p = [NSPredicate predicateWithFormat:#"type = %i AND grade >= %i", kEnchantmentArmor,armor.grade];
NSArray* possibleEnchantments = [[EquipmentGenerator allEnchantmentDictionary] objectForKey:#"enchantments"];
//get only applicable enchantments
NSArray *validEnchantments = [possibleEnchantments filteredArrayUsingPredicate:p];
NSMutableArray* mutableArray = [NSMutableArray arrayWithArray:validEnchantments];
NSDictionary* enchantment = nil;
if(mutableArray.count>0)
{
//got enchantments, assign number and intensity based on grade
for (int i = 0; i<3;i++)
{
enchantment = mutableArray[arc4random()%mutableArray.count];
[mutableArray removeObject:enchantment];
//create enchantment from dictionary and assign to item.
}
}
You can shuffle the array using one of the following techniques:
What's the Best Way to Shuffle an NSMutableArray?
Non repeating random numbers
Then, take the first X elements from the array.
Many years ago, I was working on card game and I realized that shuffling the deck was an inefficient way to get random cards. What I would do in your shoes is pick a random element, and then replace it with the element at the end of the array, like so:
#interface NSMutableArray (pickAndShrink)
- (id) pullElementFromIndex:(int) index // pass in your random value here
{
id pickedItem = [self elementAtIndex:index];
[self replaceObjectAtIndex:index withObject:[self lastObject]];
[self removeLastObject];
return pickedItem;
}
#end
The array will shrink by one every time you pull an element this way.
You could use a random number generator to pick a starting index, and then pick the subsequent indices based on some kind of math function. You would still need to loop depending on how many properties you want.
Eg:
-(NSMutableArray*)getRandomPropertiesFromArray:(NSArray*)myArray
{
int lengthOfMyArray = myArray.count;
int startingIndex = arc4random()%lengthOfMyArray;
NSMutableArray *finalArray = [[NSMutableArray alloc]init]autorelease];
for(int i=0; i<numberOfPropertiesRequired; i++)
{
int index = [self computeIndex:i usingStartingIndex:startingIndex origninalArray:myArray];
[finalArray addObject:[myArray objectAtIndex:index]];
}
return finalArray;
}
-(int)computeIndex:(int)index usingStartingIndex:(int)startingIndex
{
//You write your custom function here. This is just an example.
//You will have to write some code to make use you don't pick an Index greater than the length of your array.
int computedIndex = startingIndex + index*2;
return startingIndex;
}
EDIT: Even your computeIndex function could use randomness in picking the subsequent indices. Since you have a startingIndex, and another index, you could use that to offset your function so that you never pick a duplicate.
EDIT: If your array is very large, and the subset you need to pick is small, then rather than shuffle the entire array (maybe more expensive), you could use this method to pick the number of items you need. But if your array is small, or if the number of items you need to pick are almost the size of the array, then the godel9's solution is better.
You can use a mutable array and then remove them as the are selected, use something like random()%array.count to get a random index. If you don't want to modify the array then copy it with [array mutableCopy].
UIActivityItemSources, it seems, can only return one kind of placeholder item? This seems strange, because I have a UIActivityItemSource that could return a string, an NSData object, or an image depending upon the activity it's given.
Is there really no way to return more than one kind of placeholder? (NSArrays don't seem to work.)
(I could imagine a solution where I instantiate a bunch of UIActivityItemProvider instances, each supporting the different datatypes mentioned above. But that seems like a lot more work than should be necessary...?)
If you add a trace inside your itemForActivityType function you will see that this function will be called multiple times. One for each activity available for share.
For example - if I want to provide different text for Twitter and mail/sms sharing I would have something like this:
- (id) activityViewController: (UIActivityViewController*) activityViewController itemForActivityType: (NSString*) activityType {
if (activityType == UIActivityTypePostToTwitter) {
return #"Sharing by Twitter";
}
else
return #"Other kind of sharing";
}
UPDATE:
If you want to provide different types of data to share (say text and images) - you need to wrote your placeholder function in a way so it returns two different kind of object when called multiple times.
- (id) activityViewControllerPlaceholderItem: (UIActivityViewController*) activityViewController {
static int step = 0;
if (step == 0) {
step = 1;
return #"text";
}
else if (step == 1) {
step = 2;
return [UIImage imageNamed: #"image"];
}
}