I'm not sure I formed the title correctly since Google keeps silence on it.
I want to access a property (or an object, or an instance) by using path, consisting of known path + variable path. Let's say there are 5 properties: pr1, pr2... pr5. For rehearsal them I use:
for (int i = 1; i <=5; i++) {...}
Next I want to get the property, using i. Something like this: self.pr+i;. What is the correct way to do it in Objective C?
for (NSInteger i = 1; i <=5; i++)
{
// access read
id property = [self valueForKey:[NSString stringWithFormat:#"pr%ld",(long)i]];
// write
id someValue;
[self setValue:someValue forKey:[NSString stringWithFormat:#"pr%ld",(long)i]];
// remember pr1 must be a self property.
}
Generally, though you don't describe the exact case, you can use KVC:
id myVar = [self valueForKey:myVarName];
so once you know that you just need to create the string:
NSString *myVarName = [NSString stringWithFormat:#"pr%d", i];
Related
I have a dynamic settings page. It depends on user's scenario, the settings page contents will be varied. I need prompt notice if user modified any setting text field or switcher value. Which way is more efficiency to verify multiple text field strings in customized settings view?
I have two ideas:
1, Traversal all subviews, if subview is textField or switcher, add these strings or boolean values into one NSDictionary obj, and use hash method get the dictionary object hash value and store it. When other event happen, do it again and compare the two hash value. If different, it means some setting is modified.
2, Traversal all subviews, save them into NSDictionary. When other event happen, it will traversal all subviews and compare every text field or switcher value separately. If any comparison found different, it means the settings page has unsaved setting.
Is there any other intelligent way to achieve this goal?
How about adding a tag to each control, say from value 1 to 20 (if you have 20 settings). Store the initial value of each setting in a mutable array at the position of the tag value (so if tag is 12, store at position 12). Make a copy of this array, and when they adjust a control store the new value in this second array at the same position (using the tag value as before). Then when they click on save, just compare the values between the two arrays with a simple loop.
Hope this helps.
In my scenario, the settings page is still developing, and the objects in the view will be dynamically, depends on user authorities. For the security rasone, it is not good idea that copy settings to other variables. Some people might change a setting, then change the setting back after view other settings. If use a simple flag to indicating changes, the change backed settings will be verified as changed.
My final solution is use md5 hash to snapshot every settings' value, just take lowest 4 chars and xor all snapshots to get one long unsigned integer (NSUInteger) hash value. After view did appear, get this hash value as reference. When user want to save settings or pop to parent view, we do this hash again. Then compare with reference hash value.
MD5 Function
#import <CommonCrypto/CommonCrypto.h>
- (NSUInteger) md5:(NSString *) input
{
const char *cStr = [input UTF8String];
unsigned char digest[16];
CC_MD5( cStr, strlen(cStr), digest ); // This is the md5 call
NSUInteger output = [[NSNumber numberWithUnsignedChar:digest[0]] intValue];
NSUInteger i;
i = (0x00000000|digest[3])<<24;
i = i|(0x00000000|digest[2])<<16;
i = i|(0x00000000|digest[1])<<8;
i = i|(0x00000000|digest[0])<<0;
output =i;
return output;
}
Snapshot Settings
- (NSUInteger) hashSettings{
NSUInteger settingsHash = 0;
for (NSObject *obj in settingsScrollView.subviews){
if([obj isKindOfClass:[UITextField class]]){
UITextField *textField = (UITextField *)obj;
settingsHash = settingsHash ^ [self md5:textField.text];
}
if([obj isKindOfClass:[UISwitch class]]){
UISwitch *switcher = (UISwitch *)obj;
settingsHash = settingsHash ^ (switcher.isOn?switcher.hash:0xFFFFFFFF);
}
if([obj isKindOfClass:[UIButton class]]){
UIButton *button = (UIButton *)obj;
settingsHash = settingsHash ^ (button.isHidden?button.hash:0xFFFFFFFF);
}
}
NSLog(#"settings Hash : %#",[self getBitStringForInt:settingsHash]);
return settingsHash;
}
For NSLog easily
- (NSString *)getBitStringForInt:(NSUInteger)value {
NSString *bitsSting = #"";
for(int i = 0; i < 32; i ++) {
bitsSting = [NSString stringWithFormat:#"%i%#", value & (1 << i) ? 1 : 0, bitsSting];
}
return bitsSting;
}
I'm new to objective-c and have already released the first version of my app in the App Store but I want to improve my app because in the current version, I can only enter 4 player names.
In my new iOS app, I have a table view that lists all names that a user can enter in another view controller.
When the user presses play, I want to display a UIAlertView with the name of a random person.
at this moment, I would like to display all names in the NSLog, but I can't figure out how to do that. with my current code, the app keeps crashing.
I have a class, Zoep, which is a subclass of NSObject. and has the following properties:
#property (strong, nonatomic) NSString *playername;
#property BOOL *checked;
In the tableview controller, I have the following code to display items in the NSMutableArray and to display all names in NSLog. I think i'm that i'm almost doing it right now:
- (IBAction)play:(id)sender {
NSString *aantal = [NSString stringWithFormat: #"%ld", (long)[self.zoepers count]];
NSLog(#"array count: %#", aantal);
for (int i = 0; i < 2; ++i) {
NSLog(#"Naam: %lu", (unsigned long)[self.zoepers indexOfObject:[i]]);
}
}
with the above code, i'm still getting the following error and can't compile:
Expected identifier
Could someone point me in the right direction? When you have any tips for me, I would also like to know them.
Thanks a lot in advance!
NSString is an object and can be print with %# and not %lu. Update your code and you're with your name.
for (int i = 0; i < 2; ++i) {
Zoep *player = (Zoep *)[self.zoepers objectAtIndex:i];
NSLog(#"Naam: %#", player. playername);
}
Conclusion: You're storing Zoep class object into your zoepers array, so at the time of accessing zoepers you would first make reference of Zoep class object and then can access properties of that class.
BTW, indexOfObject: takes an object and will return index (position in array).
Change ur code as below..
indexOfObject refers to Object of type id..Actually u are passing int instead of object..
U can get the value of some property of object using (.) like obj.propertyname..
for (int i = 0; i < 2; ++i)
{
Zoep *zoepObj=[self.zoepers objectAtIndex:i];
NSLog(#"Naam: %#",zoepObj.playename);
}
Hope it helps u..
Im trying to inset data in to the array (temp) but for some reason it saves the same data over an over. I all ready checked the _singleSeismicInfo to verify that it was handling different data(you can see it in the double "/" printData method). So i know the problem is with the MutableArray.
Im new to iOS so if theres something Im not doing right let me know.
NSMutableArray *temp = [[NSMutableArray alloc] init];
[_httpContent getTextFromHTTP];
for (int index = 0; index < 10; index++) {
NSString *line = _httpContent.lines[index];
[_singleSeismicInfo fillSeismicInfo:line];
//[_singleSeismicInfo printData];
[temp addObject:_singleSeismicInfo];
}
You're adding _singleSeismicInfo over and over without ever reassigning a new object to the variable as far as I can see. So it's the same object over and over because that's what you add.
I have a NSMutableArray that i define in the header file as:
#property (strong, nonatomic) NSMutableArray *tempPhotosArray;
Then i allocate as:
_tempPhotosArray = [[NSMutableArray alloc] init];
What i'd like to know is if i then go to replaceObjectAtIndex the program will complain on an out of bounds. I want to keep only a set number of items in that array, so is it possible to do a insert or replace? i.e. if at index 0 it is empty do an insert, if there is an object already replace it?
Thanks
i think i agree with Hani Ibrahim. Since you said you only want to keep a set number of objects in the array. So how many you want?
// add these code when you initialize the array
int aSetNumber = 5;
_tempPhotosArray = [[NSMutableArray alloc] init];
for (int i = 0; i < aSetNumber; i++)
{
[_tempPhotosArray addobject: [NSNull null]];
}
i guess then you can do whatever you want, i don't know what exactly you want to do in this case, but i would check if the object in that position is NSNUll, if so, replace that, if not, i don't know what you want them
//use these code when you trying to insert the real object
if([[_tempPhotoArray objectAtIndex:anIndex] isKindOfClass: [NSNull class]])
{
//replace it here
}
As to why you are getting an error, what everyone else wrote is accurate, but....
The description of what you want doesn't match what an NSArray is. It sounds like you want a list of up to 5 items and never more than 5. It might be that if you try to add a 6th item the "oldest" goes away. Like a "recently opened" file history. You can make this type of functionality with an NSArray, but that's not what it is out of the box.
I would suggest making your own object class. I'm not going to write all the code for you, because this sounds suspiciously like programming homework, but I will point you in the correct direction.
FivePack <-- our class
NSArray *storage; <-- where we house the data
// a public method which lets you add things.
- (void)addItem:(id)item {
int indexOfLastItemInArrayToSave = 4;
if (storage.length < 4)
indexOfLastItemInArrayToSave = length-1;
NSRange range = NSMakeRange(0, indexOfLastItemInArrayToSave);
NSArray *temp = [storage subArrayWithRange:range];
// now create a new array with the first item being "item" that
// was passed in and the rest of the array being the contents of temp.
// Then save that to storage.
}
What you want to do with the data and writing something to get it from your new object is up to you, because I'm not sure how you want to do it.
There are no objects in the array when you initially created it, so there is nothing to replace.
Like this?
if([_tempPhotosArray count] > 0)
//replace object
else
//add object to array
I have an NSArray made of UILabels that I initialized with this statement (the actual pointer is created in the .h file):
interLabels = [NSArray arrayWithObjects:inter1,inter2,inter3, nil];
Later on I have an IBAction method that responds and is supposed to update the array of labels when a button is clicked:
-(IBAction)intervalButton:(id)sender{
int count = 0;
double val[3];
if(count < 3){
val[count] = number;
[interLabels objectAtIndex:count].text = [NSString stringWithFormat:#"%.2f", val[count]];
count++;
}
}
However, [interLabels objectAtIndex:count] doesn't seem to be recognized as a UILabel object, so I get a compiler error that states that the property "text" cannot be found on object type "id." How can I get the compiler to recognize this as a UILabel? Is this an issue that can be solved by typecasting?
objectAtIndex returns you an reference of type 'id'. You need to cast it to UILabel before the compiler / IDE will recognise the text property.
E.g.
((UILabel*) [interLabels objectAtIndex:count]).text = ...
Type id does not need to be casted if you assign it to another variable. And in your case i think it would be nicer since you actually do two things, first get a object from the array and then changes state on that object. Consider this.
-(IBAction)intervalButton:(id)sender
{
for ( UILabel *label in interLabels )
{
label.text = [NSString stringWithFormat:#"%.2f", number];
}
}
I assumed you wanted a loop not a if statement since the if statement always evaluated to YES. Also i assumed number is a instance variable in your class.
Actually when i looked at the code again you can probably remove most of it.