I have a synthesized NSMutableArray - theResultArray . I want to insert NSNumber or NSInteger objects at specific indexes (0-49). For some reason I can never get any values to stick in my array. Every index returns nil or 0.
NSInteger timeNum = time;
[theResultArray insertObject:[NSNumber numberWithInt:timeNum] atIndex:rightIndex];
NSLog(#"The right index is :%i", rightIndex);
NSLog(#"The attempted insert time :%i", time);
NSNumber *testNum = [theResultArray objectAtIndex:rightIndex];
NSLog(#"The result of time insert is:%i", [testNum intValue]);
I alloc-init theResultsArray in viewDidLoad. Time is an integer. I have been trying different combinations of the code above to no avail.
The console outputs this:
StateOutlineFlashCards[20389:20b] The right index is :20
StateOutlineFlashCards[20389:20b] The attempted insert time :8
StateOutlineFlashCards[20389:20b] The result of time insert is:0
Unless I'm misreading, aren't you inserting an NSInteger, but then trying to take out an NSNumber? Those are two completely different data types. It doesn't surprise me that you're getting odd results.
Furthermore, NSInteger isn't an object, so you can't stick it into an array. You probably want to be allocating an NSNumber with that integer and putting that in.
Try something like: [theResultArray addObject:[NSNumber numberWithInteger:timeNum] atIndex:rightIndex];
Likewise, when you retrieve the value, you'll need to unbox it:
NSLog(#"The result of time insert is:%i", [testNum integerValue])`;
Likewise, when you retrieve the value, you'll need to unbox it:
Frankly, I'm a little surprised that this even compiles.
You need to allocate memory for the array in your init or viewDidLoad method, otherwise you won't be able to store anything at all.
If you do this:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if ((self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil])) {
// Custom initialization
myMutableArrayName = [[NSMutableArray alloc] init];
}
return self;
}
Or this:
- (void)viewDidLoad {
[super viewDidLoad];
myMutableArrayName = [[NSMutableArray alloc] init];
}
It should work for you.
As for storing integers in an NSMutableArray, I took a simple but somewhat "hackish" approach recently. I store them as strings. When I put them in I use:
[NSString stringWithFormat:#"%d", myInteger];
And when I take them out I convert with:
[[myArray objectAtIndex:2] intValue];
It was really easy to implement but depending on the context you may want to use another way.
NSInteger timeNum = time;
What is that for? What is "time"?
[theResultArray addObject:timeNum atIndex:rightIndex];
There is no method -addObject:atIndex:. It is -insertObject:atIndex:. Why are you inserting at "rightIndex" anyway? Why not just use -addObject:?
//[theResultArray replaceObjectAtIndex:rightIndex withObject:[NSNumber numberWithInt:timeNum]];
What is that and why is it commented out?
NSLog(#"The right index is :%i", rightIndex);
NSLog(#"The attempted insert time :%i", time);
NSNumber *testNum = [theResultArray objectAtIndex:rightIndex];
//int reso = [testNum integerValue];
NSLog(#"The result of time insert is:%i", testNum);
What are you trying to do?
Related
In one class, I define an NSMutableArray with getters and setters:
#interface ArrayClass : NSObject {
NSMutableArray *array;
}
#property (nonatomic, strong) NSMutableArray *array;
#end
Then within the implementation file, I alloc init the mutable array:
#import "ImageUploader.h"
#implementation ArrayClass
#synthesize array;
- (id)init {
self = [super init];
if (self != nil) {
NSLog(#"ArrayClass inited");
array = [[NSMutableArray alloc] init];
}
return self;
}
#end
Then I initialize an instance of this class from another class:
ArrayClass *arrayClass = [[ArrayClass alloc] init];
[arrayClass.array addObject:image];
NSUInteger count = [arrayClass.array count];
NSLog(#"%#", count);
But when I try to add an object to the mutable array, the app crashes and Xcode 4.3 shows:
Removing the addObject call makes the app run fine. What am I doing wrong that would cause the app to crash?
This is wrong:
NSUInteger count = [arrayClass.array count];
NSLog(#"%#", count);
You want:
NSLog(#"%u", count);
%# is used to specify that the argument is an object. However, an NSUInteger is a primitive value, not an object. You use %u for unsigned ints.
try:
NSLog(#"%i", count);
NSUInteger return an INT not an object address
NSLog(#"%#", count);
is wrong, use:
NSLog(#"%i", count);
%# in the format statement expects and must be an object, NSUInteger is in int, not an object.
You are using an %# format specifier, which is for Cocoa objects only, for an NSUInteger, which is a typedef on an ordinary unsigned int. Use %d, %i or %u instead.
It looks to me like it's crashing when trying to print description, which makes sense because you're using %# where an integer is expected in your NSLog().
Separately, using a mutable property is almost always a bad idea. If it's really a property, you probably want to use an immutable array, and set the whole array when you want to change it.
Agree that the logging of count is wrong, but I think the other answers miss a move obvious point: the crash happens on the addObject. This implies that image is nil. NSLog that before the add.
I want to get the index of an object within the NSMutableArray of categories.
The category object has an attribute "category_title" and I want to be able to get the index by passing the value of category_title.
I have looked through the docs and can't find a simple way to go about this.
NSArray does not guarantee that you can only store one copy of a given object, so you have to make sure that you handle that yourself (or use NSOrderedSet).
That said, there are a couple approaches here. If your category objects implement isEqual: to match category_title, then you can just use -indexOfObject:.
If you can't do that (because the category objects use a different definition of equality), use -indexOfObjectPassingTest:. It takes a block in which you can do whatever test you want to define your "test" - in this case, testing category_title string equality.
Note that these are all declared for NSArray, so you won't see them if you are only looking at the NSMutableArray header/documentation.
EDIT: Code sample. This assumes objects of class CASCategory with an NSString property categoryTitle (I can't bring myself to put underscores in an ivar name :-):
CASCategory *cat1 = [[CASCategory alloc] init];
[cat1 setCategoryTitle:#"foo"];
CASCategory *cat2 = [[CASCategory alloc] init];
[cat2 setCategoryTitle:#"bar"];
CASCategory *cat3 = [[CASCategory alloc] init];
[cat3 setCategoryTitle:#"baz"];
NSMutableArray *array = [NSMutableArray arrayWithObjects:cat1, cat2, cat3, nil];
[cat1 release];
[cat2 release];
[cat3 release];
NSUInteger barIndex = [array indexOfObjectPassingTest:^BOOL(id obj, NSUInteger idx, BOOL *stop) {
if ([[(CASCategory *)obj categoryTitle] isEqualToString:#"bar"]) {
*stop = YES;
return YES;
}
return NO;
}];
if (barIndex != NSNotFound) {
NSLog(#"The title of category at index %lu is %#", barIndex, [[array objectAtIndex:barIndex] categoryTitle]);
}
else {
NSLog(#"Not found");
}
Not sure that I understand the question but something like this might work (assuming the Mutable Array contains objects of Class "Category"):
int indx;
bool chk;
for (Category *aCategory in theArray)
{
chk = ([[aCategory category_title] isEqualToString:#"valOfCategoryTitle"])
if ( chk )
indx = [theArray indexOfObject:aCategory];
}
Try this code much more simpler:-
int f = [yourArray indexOfObject:#"yourString"];
When I run this code, the output is some 1084848 to the console. I can't figure out why such odd output... here is the code.
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *array = [[NSMutableArray alloc] init];
int someNumber = 3;
[array addObject:[NSNumber numberWithInt:someNumber]];
NSLog(#"%i" , [array objectAtIndex:0]);
[pool drain];
return 0;
}
the "%i" format specifier expects an integer, not an Object.
Try NSLog(#"%i" , [[array objectAtIndex:0] intValue]);
XCode is probably giving you a warning on this line: something like "Conversion specifies type 'int', but argument has type 'id'".
Here's the pseudocode of your program:
//
// Inside of your main function....
//
// Set up the Autorelease pool and then create an array
//
// Declare an int
//
// Add the int to an array, while wrapping it in an NSNumber
//
// Log the value of the first object in the array, using the int formatter
//
// Clean up and return
//
You are logging the first object in the array, but NSArray cannot hold a primitive that's not wrapped in an Objective-C object.
To better understand your code, try changing these lines of code:
int someNumber = 3;
[array addObject:[NSNumber numberWithInt:someNumber]];
Expand them a little. Try this:
int someNumber = 3;
NSNumber *aNumber = [NSNumber numberWithInt:someNumber];
[array addObject:aNumber];
So, you've correctly wrapped the int in an NSNumber, but you're not unwrapping it. You need to ask your NSNumber for the int that it holds like so:
[[array objectAtIndex:0] intValue];
Or, to do the logging in one line:
NSLog(#"%i" , [[array objectAtIndex:0] intValue]);
The characters "%i" is called a "formatter". Different kinds of values require different formatters. When you are using an Objective-C object, you use "%#". For an NSInteger or int, you'd use %i. For a float, you'd use "%f". The point is that you need to either unwrap that number, or use the Objective-C formatter for strings.
A quick note about that weird value you were getting earlier: That's a memory address in RAM. It's the closest thing you're going to get when you use an incorrect formatter. In some cases, using the wrong formatter will cause an EXC_BAD_ACCESS. You were "lucky" and got a weird value instead of a dead program. I suggest learning about strings and formatters before you move on. It will make your life a lot easier.
When you use %i for integer values then you should give arguments as integer as below
NSLog(#"%i" , [[array objectAtIndex:0] intValue]);
But when you want object to be displayed then you must use %# which identifies object in general case as below:
NSLog(#"%#", array);
Another, probably simple problem that, having tried for a good few hours now I'm pretty stumped on. Simply, I want to set the value of a picker from a NSDictionary, I don't mind! Every way I have tried pretty much gives me the warning Passing argument 1 of selectRow inComponent animated' makes integer from pointer witout a cast. Which makes sense, though I seem to be failing miserable at fixing it! Any help would be greatly appreciated! Snippet of code below...
NSArray *myValue = [parsedJson objectForKey:#"Details"];
NSEnumerator *myEnumerator = [myValue objectEnumerator];
NSDictionary* myItem;
int i = 0;
while (myItem = (NSDictionary*)[myEnumerator nextObject])
{
[myPickerView selectRow:[myItem objectForKey:#"Value"] inComponent:i animated:YES];
i++;
}
Assuming your value responds to intValue message (e.g. number is stored in NSNumber or NSString) then the following should work:
[myPickerView selectRow:[[myItem objectForKey:#"Value"] intValue]
inComponent:i animated:YES];
The selectRow parameter is expecting an integer, try this:
[myPickerView selectRow:[[myItem objectForKey:#"Value"] integerValue] inComponent:i animated:YES];
I have an array, which contains some duplicate entries.
Firstly, is there any way to restrict duplicate entries when data getting inserted?
Secondly, if an array already having duplicate values than in some other way, we can retrieve only unique values from that array, I heard about NSSet about this, but I have no idea how to use it.
Don't use an NSSet.
You can only insert elements upon creation and cannot change the elements contained after you have created it.
If you want to add and remove objects on the fly, you can use an NSMutableSet.
Here is a demo of how to use it both NSSet and NSMutableSet, then converting the NSSet back to an NSArray (incase you want to do that):
- (void) NSMutableSetPrintTest
{
NSMutableSet *mutableSet = [[NSMutableSet alloc] init];
NSLog(#"Adding 5 objects (3 are duplicates) to NSMutableSet");
NSString *firstString = #"Hello World";
[mutableSet addObject:firstString];
[mutableSet addObject:#"Hello World"];
[mutableSet addObject:#"Goodbye World"];
[mutableSet addObject:#"Goodbye World"];
[mutableSet addObject:#"Goodbye World"];
NSLog(#"NSMutableSet now contains %d objects:", [mutableSet count]);
int j = 0;
for (NSString *string in mutableSet) {
NSLog(#"%d: %# <%p>", j, string, string);
j++;
}
NSLog(#"Now, if we are done adding and removing things (and only want to check what is in the Set) we should convert to an NSSet for increased performance.");
NSSet *immutableSet = [NSSet setWithSet:mutableSet];
NSLog(#"NSSet now contains %d objects:", [immutableSet count]);
int i = 0;
for (NSString *string in immutableSet) {
NSLog(#"%d: %# <%p>", i, string, string);
i++;
}
[mutableSet release]; mutableSet = nil;
NSLog(#"Now, if we are done with the sets, we can convert them back to an NSArray:");
NSArray *array = [immutableSet allObjects];
NSLog(#"NSArray contains %d objects", [array count]);
int k = 0;
for (NSString *string in array) {
NSLog(#"%d: %# <%p>", k, string, string);
k++;
}
}
NSMutableSet is probably the most logical thing to use.
However, be warned that a set does not maintain order of its elements (since a set, by definition, is unordered).
If that's a problem for you, then you have a couple of options:
duplicate set functionality with an NSMutableArray by invoking containsObject: before every call to addObject: (doable, but potentially slow, since arrays have O(n) search time)
use another object.
If you go with the second option, I would recommend taking a look at the excellent CHDataStructures framework, which has a subclass of NSMutableSet called CHOrderedSet, which is a set that maintains insertion order. (And since it's a subclass, it has the exact same API as an NSMutableSet)
If you've heard about NSSet, did you read the documentation? The API is similar to NSArray and very straightforward. Just like NSArray vs. NSMutableArray, you would use NSMutableSet if you need on the fly membership tests.