Is this possible to call variable dynamically in Objective C? - objective-c

Here is the object, and have following attribute:
NSString attri1;
NSString attri2;
NSString attri3;
NSString attri4;
If I want to list these attri, I can call
NSLog(aObj.attri1);
But can I make the 1 as a variable to call it from a loop? Is this possible to do so in objective-c?
for(int i = 0; i < [array count]; i++)
{
NSLog(aObj.attri1); //is this possible to become one line, dynamic generated variable
}
Thank you. btw, What is this feature called? Thanks.

If you want to dynamically access a property of an object, that can be done with Key Value Coding.
If the class is KVC-compliant, as most NS classes are, you can use valueForKey: or valueForKeyPath: to access a property with a string:
for(int i = 0; i < [array count]; i++) {
    NSLog([[aObj valueForKey:[NSString stringWithFormat:#"attrib%d", i]]);
}

The feature you're looking for is generally called "variable variables." Objective-C does not have this feature. Actually, most languages don't.
The good news is that you don't actually need this feature. Four variables named the same thing with a number at the end is basically equivalent to an array, only with the structure being implicit rather than explicit. Just make attri an array and then you can ask it for a numbered item.

Related

Objective-C create dynamic array names based on 1 piece of info in the array or add to that array if it already exists

Ok here is a challenge before me I am having trouble with:
I need to create multiple arrays in a custom object dynamically
heres the idea a student enters their assignments including class name I want to add it to an array dependent on the class name. This is dynamic so i need to create an array of arrays the main array named for the class name. This allows for unlimited number of classes.
I know how to do this with arrays pre named in my object and to load to these array. I am having trouble figuring out the dynamic creation of these array names.
Any ideas I am stuck.
Like I said, just stuck on where to go next so that it can be assigned to an array of ADP1 or ADP2 and if I add an English assignment it load into an array for English and then if I take Calculus I can add that assignment and it will create a new array to load my calculus assignments into.
solved with this:
for (int i =0; i < [classList.classesArray count]; i++)
{
NSString *classy = [classList.classesArray objectAtIndex:i];
NSMutableArray *classless = [classList.classesArray objectAtIndex:i];
classless = [[NSMutableArray alloc] initWithObjects: nil];
for (int a =0; a < [assignmentList.assignmentsArray count]; a++)
{
if ([educate containsObject:classless])
{
if (classy == [[assignmentList.assignmentsArray objectAtIndex:a] classSched])
{
Assigned *assignments = [assignmentList.assignmentsArray objectAtIndex:a];
[classless addObject: assignments];
}
}
else
{
[educate addObject:classless];
if (classy == [[assignmentList.assignmentsArray objectAtIndex:a] classSched])
{
Assigned *assignments = [assignmentList.assignmentsArray objectAtIndex:a];
[classless addObject: assignments];
}
}
}
}
It sounds like what you want is an NSDictionary. Arrays don't have names, but dictionaries can have arbitrary keys that correspond to objects, which is basically a "name" for the object (since you can ask the dictionary for an object by "name").

With NSPointerArray, how to iterate over opaque pointers?

I recently discovering these classes like NSMapTable and NSPointerArray, which work like the traditional collections, but also let you store weak references or plain old C pointers. Unfortunately it looks like you can't use the for...in syntax to iterate over non-NSObject pointers. For example:
typedef struct Segment {
CGPoint bottom, top;
} Segment;
...
NSPointerArray *segments = [[NSPointerArray alloc]
initWithOptions:NSPointerFunctionsOpaqueMemory];
...
Segment *s = malloc(sizeof(Segment));
[segments addPointer: s];
...
for (Segment *s in segments) { // nope...
The compiler does not like that last line. The error:
Selector element type 'Segment *' (aka 'struct Segment *') is not a valid object
So, do I need to do this?
for (int i=0, len=segments.count; i<len; i++) {
Segment *seg = [segments pointerAtIndex:i];
...
That's not the end of the world, but I just want to make sure.
(This might be more of theoretical interest.)
NSPointerArray does conform to the NSFastEnumeration protocol, it is only the
for (id object in collection) language construct that cannot be used with arbitrary pointers which
are not Objective-C pointers.
But you can get a whole bunch of pointers from the array by calling the NSFastEnumeration
method countByEnumeratingWithState:objects:count: directly. This is a bit tricky because
that method need not fill the supplied buffer (as explained here: How for in loop works internally - Objective C - Foundation).
Here is a simple example how this would work:
__unsafe_unretained id objs[10];
NSUInteger count = [segments countByEnumeratingWithState:&state
objects:objs count:10];
// Now state.itemsPtr points to an array of pointers:
for (NSUInteger i = 0; i < count; i++) {
Segment *s = (__bridge Segment *)state.itemsPtr[i];
NSLog(#"%p", s);
}
So this does not help to make the code simpler and you probably want to stick with
your explicit loop.
But for large arrays it might improve the performance because the pointers are "fetched"
in batches from the array instead of each pointer separately.
the for (... in ...) syntax won't work in this case because Segment is a struct, not an Objective C object. Your second for loop should work.

CLISTs in Objective C

I have cpp code where the struct objects are put into the CLISTS. I am porting this code into Objective C.
CLIST is similar to a doubly linked list with .RemoveAt , .GetAt , .InsertBefore , .GetNext , .GetHeadPosition functions.
How to implement the same in Objective C.
Do I need to implement doubly linked list in Objective C.Is there any other predefined methods to use it.
A CLIST is presumably circular? Hence the GetHeadPosition?
In any case, NSArray (or, NSMutableArray in this case, since you want to be inserting) is the normal way to keep ordered lists in Objective-C.
For RemoveAt, use removeObjectAtIndex:. For GetAt, use objectAtIndex:. For InsertBefore you're probably going to want to write a little something like:
- (void)insert:(id)objectToInsert before:(id)referenceObject
{
int index = [array indexOfObject:referenceObject];
if(index == NSNotFound) return; // or whatever you'd expect.
// Maybe object is just inserted at the end?
index = index - 1;
if(index < 0) index = [array count];
[array insertObject:objectToInsert atIndex:index];
}
(which would probably go better in an NSArray category, but you get the point)
For GetNext and GetHeadPosition you probably want to keep your array position in a separate variable. So for GetNext:
arrayPosition = (arrayPosition + 1)%[array count];
return [array objectAtIndex:arrayPosition];
And for GetHeadPosition, just:
return arrayPosition;
EDIT: for iterating through an NSArray, the easiest way is actually to ignore anything explicit and just use:
for(ObjectType *object in array)
{
/* do something with object */
}
That generally means you don't really need an analogue of GetNext, but you can't mutate the array while in that loop so it's not always usable.

Removing object from NSMutableArray

I stumbled across the following shortcut in setting up a for loop (shortcut compared to the textbook examples I have been using):
for (Item *i in items){ ... }
As opposed to the longer format:
for (NSInteger i = 0; i < [items count]; i++){ ... } //think that's right
If I'm using the shorter version, is there a way to remove the item currently being iterated over (ie 'i')? Or do I need to use the longer format?
You cannot remove objects from array while fast-enumerating it:
numeration is “safe”—the enumerator
has a mutation guard so that if you
attempt to modify the collection
during enumeration, an exception is
raised.
Anyway why do you need to change you container while enumerating it? Consider storing elements that need to be deleted and remove them from your container using removeObjectsInArray: or removeObjectsAtIndexes: method.
Just add keyword break; after removing the item...
for(id item in items) {
if([item isEqual:itemToDelete]) {
[items removeObject:item];
break; // A very important line 🛑
}
}
An Objective-C collection must not be modified during enumeration.
You may use this variant to delete objects from collection:
for (NSInteger i = items.count - 1; i >= 0 ; i--) {
[items removeObjectAtIndex:i];
}
The former loop is a "for-each" loop in Objective C.
*i is a pointer to the direct item in the items-Array (most of the time this will be NSMutableArray).
This way you can operate directly on the item:
[items removeObject: i];
This (should) work - I am currently not working on my Mac and can't check it.
However it might be that Objective-C Prevents removing objects while iterating over the collection (that is quite common in most languages).
I use this code for this:
for (NSUInteger i = [items count] - 1; ; i--) {
[items removeObjectAtIndex:i];
}

Does fast enumeration in Objective-C guarantee the order of iteration?

Can I expect it to go from the start of an array to the end in order? Can't find anything in the docs about this.
i.e. is
for (id val in array)
{
NSLog(#"%#", val);
}
always going to print out the same as
for (int i = 0; i < [array count]; ++i)
{
NSLog(#"%#", [array objectAtIndex:i]);
}
From Apples' Objective-C documentation on fast enumeration:
For collections or enumerators that have a well-defined order—such as NSArray or NSEnumerator instance derived from an array—the enumeration proceeds in that order, so simply counting iterations will give you the proper index into the collection if you need it.
Once again I've found the answer right after posting. My old reference didn't mention the order of iteration, but the online one did. The array is indeed iterated in order.