Using method parameters check to see if array object is equal to another string (objective-C)? - objective-c

I'm all self taught so please keep the techincal jargin to a minimum. Theoretically if I had a method and it had a parameter that is the name of an array. How do I check to see if that array index 5 is equal to #"Yes" or #"No". I know it's one of these because its testing to see if the picture is appearing in the veiw controller. Here is an example:
-(void)methodName :(NSMutableArray *)arrayNameInMethod {
if ( [NSMutableArray *(arrayNameInMethod) indexOfObject:5] == #"Yes"){
//Hide a different picture assocciated with the Array
} else {
//Unhide a different picture assocciated with the Array
};
Also how do you do use the parameter "arrayNameInMethod" to replace the object. Basically:
if(Picture Clicked and picture is Unhidden) {
[NSMutableArray *(differentArrayNameInMethod) replaceObjectAtIndex:5 withObject: #"True)
};
(this is all in another method)
Comment #2: You can't use the parameters the same way because it's a string. You can't access an array with a name as a string.
Thank you so much!

I think what you will need is a dictionary, mapping the name to the array. I will give a barebones implementation:
#interface YourClass()
{
NSMutableDictionary *_arrayMap;
}
#end
#interface YourClass
- (instancetype)init
{
self = [super init];
if (self) {
// You might do this somewhere else, like viewDidLoad:
_arrayMap = [NSMutableDictionary new];
}
return self;
}
- (void)someMethod
{
// Some functionality to add a new array:
// Note the array contains NSNumber and NSString objects:
_arrayMap[#"sampleName"] = [#[ #(0), #"one", #(2.0), #"three", #(4), #(YES)] mutableCopy];
}
-(BOOL)checkForConditionInArrayNamed:(NSString *)arrayName
{
BOOL retval = NO;
NSMutableArray *array = _arrayMap[arrayName];
if ([array count] > 5) {
id obj = array[5];
if ([obj isKindOfClass:[NSNumber class]])
retval = [obj boolValue];
}
return retval
};
#end
You then call checkForConditionInArrayNamed: to check for the condition of the named array and act accordingly.

Related

NSString, matchig name of an NSArray

I am new to Objective C coming from C# .NET, I have this scenario :
Assume I have 5 NSArrays corresponding to 5 UIButtons. the UIButtons have the exact same name
as the NSArray, so for example one UIButton is called mainScreen, and there is an NSArray called mainScreen.
Those Five buttons are linked to one IBAction where I do the following :
- (IBAction)btnClick:(id)sender {
NSString *category = [(UIButton *)sender currentTitle];
NSLog(category);
//Here I need to call the NSArray which has the same name as category
}
Now I can get the actual name of the UIButton, but how can I get the NSArray same as that title? without getting into a lot of if else or switch statements?
What I would do is store the arrays inside an NSDictionary. You can then set the 'key' as the name of your array and then the value would be the array itself.
That way you could say:
- (IBAction)btnClick:(id)sender {
NSString *category = [(UIButton *)sender currentTitle];
NSLog(category);
//Here I need to call the NSArray which has the same name as category
NSArray *theArray = (NSArray*)[self.myDictionary valueForKey:category];
}
Hope this helps!
The easiest way to associate names with objects is using an NSDictionary (or it's mutable subclass NSMutableDictionary). Dictionaries map a unique key to an object. Keys can be any object (that implements the NSCopying protocol), but are very often NSStrings
Have a look at the NSDictionary Reference and the Programming with Objective-C guide.
Note that if you use the button title this might break if you localise your app.
What you do is not the best way. You should provide tag for each button, say from 1 to 5. Also you should put your five arrays into one array. Now all you need is:
- (IBAction)btnClick:(id)sender
{
NSInteger index = [sender tag] - 1;
NSArray *array = [bigArray objectAtIndex:index];
}
That's it.
Assign different tags to all UIButtons and then access them explicitly using their tags.
- (IBAction)btnClick:(id)sender {
int tagIs = [(UIButton *)sender tag];
switch (tagIs) {
case 1:
// Access first button array
break;
case 2:
// Access second button array
break;
default:
break;
}
}
Or you can use AssociationObjects method for associating data with objects as following:
Firstly import :
#import <objc/runtime.h>
then create keys as :
static char * firstBtnKey = "firstBtnKey";
static char * secondBtnKey = "secondBtnKey";
-- - other keys same way ---
then use :
// Do any additional setup after loading the view, typically from a nib.
NSMutableArray *firstArray = [[NSMutableArray alloc] initWithObjects:#"object1",#"object 2", nil];
objc_setAssociatedObject((UIButton *)[self.view viewWithTag:1],
firstBtnKey,
firstArray,
OBJC_ASSOCIATION_RETAIN);
NSMutableArray *secondArray = [[NSMutableArray alloc] initWithObjects:#"object1",#"object 2", nil];
objc_setAssociatedObject((UIButton *)[self.view viewWithTag:2],
secondBtnKey,
secondArray,
OBJC_ASSOCIATION_RETAIN);
`
and then access these arrays as :
- (IBAction)btnClick:(id)sender {
int tagIs = [(UIButton *)sender tag];
switch (tagIs) {
case 1:
// Access first button array
NSMutableArray *tempArr = (NSMutableArray *)objc_getAssociatedObject((UIButton *)sender, firstBtnKey);
break;
case 2:
// Access second button array
NSMutableArray *tempArr = (NSMutableArray *)objc_getAssociatedObject((UIButton *)sender, secondBtnKey);
break;
default:
break;
}
}
Hope it helps.
In most programming languages objects don't have names.[1] Just because UIButtons have the exact same name as the NSArray(mainScreen), doesn't mean that your object is "called" mainScreen.
Use NSDictionary , array as object and button title as key.
or use button tag
title1= [[NSArray alloc] initWithObjects:#"1",nil];
title2= [[NSArray alloc] initWithObjects:#"2",nil];
title3= [[NSArray alloc] initWithObjects:#"3",nil];
title4= [[NSArray alloc] initWithObjects:#"4",nil];
title5= [[NSArray alloc] initWithObjects:#"5",nil];
dict = [[NSDictionary alloc] initWithObjectsAndKeys:title1,#"title1",title2,#"title2",title3,#"title3",title4,#"title4",title5,#"title5",nil];
- (IBAction)btnClick:(id)sender {
NSString *category = [(UIButton *)sender currentTitle];
NSArray *arr = [dict objectForKey:category];
}

NSMutableArray subclass init

I'm trying to make a function for a NSMutableArray subclass that only uses integer, but I don't want to use "count." How do I do this?
-(NSMutableArrayWithIntegers*)initWithCount:(NSInteger)count numbers:(NSInteger)firstInt, ...
{
self = [super init];
if (self) {
va_list args;
va_start(args, firstInt);
NSInteger arg = firstInt;
for (int i = 0; i < count; i++)
{
arg = va_arg(args, NSInteger);
[self addObject: [NSNumber numberWithInteger:arg]];
}
va_end(args);
}
return self;
}
I know this doesn't answer your question but it's important to let you know. Don't ever subclass NSMutableAnything. Use a category and thank me later:
#interface NSMutableArray (ListOfIntegers)
+(NSMutableArray)mutableArrayWithIntegers:(NSInteger)i, ... {
NSMutableArray *array = [[NSMutableArray alloc] initWithCapacity:whatever];
// do your thing
return array;
}
#end
First of all, the approach you currently have is just fine. Don't try getting rid of the count. There are alternatives, but they are only worse.
For example, you may use a sentinel value (which may not be inserted into the array) as the last argument, but in this case, you will have to make sure that you are not actually trying to insert this value to the array at all:
- (id)initWithIntegers:(NSInteger)first, ...
{
if (!(self = [super init])) return nil;
va_list args;
va_start(args, first);
NSInteger n;
if (first != NSIntegerMax) {
[self addObject:#(first)];
while ((n = va_arg(args, NSInteger)) != NSIntegerMax) {
[self addObject:#(n)];
}
}
va_end(args);
return self;
}
But really, this unnecessarily narrows the range of values that can be added - using that count argument is not a big deal.

What is the most efficient way to generate a sequence of NSNumbers?

It's a fairly simple builtin in python for example: x = range(0,100)
How can I accomplish the same feat using objective-c methods? Surely there is something better than a NSMutableArray and a for-loop:
NSMutableArray *x = [NSMutableArray arrayWithCapacity:100];
for(int n=0; n<100; n++) {
[x addObject:[NSNumber numberWithInt:n]];
}
Yes, I am aware that doing this is most likely not what I actually want to do (ex: xrange in python), but humor my curiosity please. =)
Clarification: I would like a NSArray containing a sequence of NSNumbers, so that the array could be further processed for example by shuffling elements or sorting by an external metric.
If you want such an array, you might want to do your own specific subclass of NSArray.
A very basic implementation example would look like:
#interface MyRangeArray : NSArray
{
#private
NSRange myRange;
}
+ (id)arrayWithRange:(NSRange)aRange;
- (id)initWithRange:(NSRange)aRange;
#end
#implementation MyRangeArray
+ (id)arrayWithRange:(NSRange)aRange
{
return [[[self alloc] initWithRange:aRange] autorelease];
}
- (id)initWithRange:(NSRange)aRange
{
self = [super init];
if (self) {
// TODO: verify aRange limits here
myRange = aRange;
}
return self;
}
- (NSUInteger)count
{
return myRange.length;
}
- (id)objectAtIndex:(NSUInteger)index
{
// TODO: add range check here
return [NSNumber numberWithInteger:(range.location + index)];
}
#end
After that, you can override some other NSArray methods to make your class more efficient.
NSRange range = NSMakeRange(0, 100);
You can iterate this range by:
NSUInteger loc;
for(loc = range.location; loc < range.length; loc++)
{
}

Adding object to NSMutableArray as an object's associative reference

I have the following:
static char associated_obj_key;
id anObj;
NSMutableArray *a = [[NSMutableArray alloc] init];
objc_setAssociatedObject(anObj, &associated_obj_key, a, OBJC_ASSOCIATION_RETAIN);
[a release];
And I'd like to know: how to add objects to the NSMutableArray inside an associative reference for the anObj object? Is it such a thing even possible?
Can I even do something like [objc_getAssociatedObject(anObj, &associated_obj_key) addObject:something];?
Yes, but you would have to have the same key all over the places. As using an address of some static variable is indeed a recommended way, I suggest factoring out the single method for obtaining a reference of an associated object (creating if necessary). I use the following:
- (NSMutableArray*) getOrCreateArray
{
static const char key;
NSMutableArray* arr = objc_getAssociatedObject(self, &key);
if (!arr)
{
arr = [NSMutableArray array];
objc_setAssociatedObject(self, &key, arr, OBJC_ASSOCIATION_RETAIN);
}
return arr;
}
- (void) someMethod
{
id something = // ....
[[self getOrCreateArray] addObject: something];
}

How to parse json specific fields using objective-c

I'm trying to parse a very simple json object with 1 value. (ocUnit test below)
- (void) testHatCartParseWithValidRefId {
NSString* data = #"{\"refid\":999}";
Cart* obj = [HatCartParseJson parseJsonAndReturnObject:data];
STAssertTrue([obj.refid isEqualToString:#"999"], #"fail");
}
In the implementation everything fails when I add the line to pull it from either key or index. How should I pull this from the json input? Please keep in mind I need this json parse (not string) the actual code I'm working with is a large set of JSON data.
+ (Cart *) parseJsonAndReturnObject:(NSString *)json
{
NSArray* cart = [json JSONValue];
for (NSDictionary* item in cart) {
Cart* obj = [[Cart alloc] init];
//NSString* refid = [item objectAtIndex:0];
//NSString* refid = [item objectForKey:#"refid"];
[obj setRefid:#"999"];
return obj;
}
return nil;
}
Thank you in advance
You are expecting that the return value of JSONValue is an NSArray, which in this case it isn't.
So, you must do a check if the return value is actually an NSArray, and if it is, then iterate through the collection, otherwise check if it's an NSDictionary, and if it is, then return the Cart object with the refid from the NSDictionary. If all of this fails, then just return nil.
As a side point, according to Apple's Object Ownership Policy, you should return autorelease-d objects from methods whose names do not contain the words "alloc", "new" or "copy". This would be one such method where you'd return an autorelease-d object.
+ (Cart *) parseJsonAndReturnObject:(NSString *)json
{
id cart = [json JSONValue];
NSString* refid = nil;
if([cart isKindOfClass:[NSArray class]]) {
refid = [[cart objectAtIndex:0] objectForKey:#"refid"];
} else if([cart isKindOfClass:[NSDictionary class]]) {
refid = [cart objectForKey:#"refid"];
}
if(refid) {
Cart* c = [[Cart alloc] init];
[c setRefid:refid];
return [c autorelease];
}
return nil;
}