Returning an NSMutableArray in objective C - ios

I have been trying to work out how to return an MSMutableArray in objective c, I have this code here.
- (NSMutableArray*)generateRandomNumber{
NSMutableArray *unqArray=[[NSMutableArray alloc]init];
int randNum;
int counter = 0;
while (counter< 6) {
randNum = arc4random_uniform(40.0);
if (![unqArray containsObject:[NSNumber numberWithInt:randNum]]) {
[unqArray addObject:[NSNumber numberWithInt:randNum]];
counter++;
}
}
return unqArray;
}
- (IBAction)button:(id)sender {
NSMutableArray *results = [[NSMutableArray alloc]init];
*results = generateRandomNumber();
}
This is my code at the moment, where it says,
NSMutableArray *results = [[NSMutableArray alloc]init];
I get the following errors...
Implicit declaration of function 'generateRandomNumber' is invalid in C99
Assigning to 'NSMutableArray' from incompatible type 'int'
If anybody is willing to show me my mistake and help me out as well as many others I will appreciate it as much as possible.
Thanks to all who help me out!!!

generateRandomNumber is a method, not a C function, so use [self generateRandomNumber] to call it, and you are assigning results incorrectly, so:
results = [self generateRandomNumber];
Alternatively if you want to define it as a C function, use:
NSMutableArray *generateRandomNumber() {
...
}
Also, as pointed-out by #Larme, there is no need to allocate results before assigning it from generateRandomNumber.

- (IBAction)button:(id)sender {
NSMutableArray *results = [[NSMutableArray alloc]init];
results = [self generateRandomNumber];
}
Or more simply:
- (IBAction)button:(id)sender {
NSMutableArray *results = [self generateRandomNumber];
// Do something with this Array
}
Though you should consider a different name for that method as currently it sounds like it is returning one number, not an array of random numbers.

When calling/using a function in Objective-C
it's [self generateRandomNumber]
When you declare a variables it's NSMutableArray *results = [[NSMutableArray alloc]init]; and use if like results = mutableArry, * before it is not needed..
about your problem, you better do it like this:
- (IBAction)button:(id)sender
{
NSMutableArray *results = [self generateRandomNumber];
}
you dont need to allocate anymore, because you are passing an mutable array that is already allocated..

Your method generateRandomNumbers should work as expect the problem is here:
- (IBAction)button:(id)sender {
NSMutableArray *results = [[NSMutableArray alloc]init];
*results = generateRandomNumber();
}
The first thing is that you are creating an unneeded mutable array, second your are trying to substitute the value of the pointer that points to result array, third generateRandonNumber is a method not a function you should call it like [self generateRandomNumber].
Also I would implement a optimization since I'm pretty sure that you are not going to modify the random number array, the returned instance should be an immutable copy.
Here the final code:
- (NSArray*)generateRandomNumber{
NSMutableArray *unqArray=[[NSMutableArray alloc]init];
int randNum;
int counter = 0;
while (counter< 6) {
randNum = arc4random_uniform(40.0);
if (![unqArray containsObject:[NSNumber numberWithInt:randNum]]) {
[unqArray addObject:[NSNumber numberWithInt:randNum]];
counter++;
}
}
return unqArray.copy;
}
- (IBAction)button:(id)sender {
NSArray *results = nil;
results = [self generateRandomNumber];
}

Your generateRandomNumbers method should work with no problem, but in the IBAction there you try to put an INT directly into the array, you need to wrap it in an NSNumber like you have in the other method there

Your method is correct.
What you are doing wrong is here: *results = generateRandomNumber();
There is no need of an * here,because in this way you are trying to assign the pointer address of your array to results object.
Secondly you are trying to call an Objective-C method in C syntax.
So the correct syntax would be: results = [self generateRandomNumber];

Related

Obj C - NSMutableArray containsObject return true

NSMutableArray containsObject returns true even the address and data is different.
I've seen this post NSMutableArray containsObject returns true, but it shouldnt
already but still I'm not finding my solution:
Below is my scenario:
NSMutableArray *destClasses = [NSMutableArray array];
id sourceClasses = [dict objectForKey:#"Classes"];
if ([sourceClasses isKindOfClass:[NSArray class]]) {
for (NSDictionary *class in sourceClasses) {
MyClass *a = [[MyClass alloc] init];
[a arrangeClassWithDictionary:classDict]; //this methods assigns value to a from classDict
if (![destClasses containsObject:a]) {
[destClasses addObject:a];
}
}
}
In the first iteration destClasses adds an MyClass object and on the second iteration [destClasses containsObject:a] returns true even though the a has different address and different values assigned.
What I'm doing wrong here. Please help.
I got the answer.
containsObject: which sends the isEqual: message to every object it
contains with your object as the argument. It does not use == unless
the implementation of isEqual: relies on ==.
I've to override the isEqual: method to provide equality checking for my object fields like below,
- (BOOL)isEqual:(id)object
{
BOOL result = NO;
if ([class isKindOfClass:[self class]]) {
MyClass *otherObject = object;
result = [self.name isEqualToString:[otherObject name]];
}
return result;
}

NSMutableArray not populating

I have a simple NSMutableArray which I am trying to store a few objects in. However in NSLog, the contents of the array always comes as null... I just dont understand why. Here is my code:
In my header file:
NSMutableArray *dataFiles;
In viewDidLoad:
dataFiles = [[NSMutableArray alloc] init];
Later on in my code in a method which is trying to add a string to my NSMutableArray:
[dataFiles insertObject:url atIndex:0]; // 'url' is an an NSURL.
What am I doing wrong? This is always how I have used NSMutableArray's, why are they all of a sudden not working?
UPDATE
I did indeed do an NSLog on the "url" (NSURL) before its being added to the array and it is not null at all. Here is the output:
THE URL: file:///var/mobile/Containers/Data/Application/E991FAFC-80DB-437B-B214-96720B1AA7AF/Documents/19Feb15_072308am.aif
UPDATE 2
I just tried #Dheeraj Singh solution and it did not work:
if ([dataFiles count] == 0) {
[dataFiles addObject:url];
}
else {
[dataFiles insertObject:url atIndex:0];
}
NSLog(#"data in: %#", dataFiles);
Thanks for your time, Dan.
Not sure what is wrong, but below (your) code is working fine with me.
NSMutableArray * arr = [[NSMutableArray alloc]init];
NSString *murl = #"file:///var/mobile/Containers/Data/Application/E991FAFC-80DB-437B-B214-96720B1AA7AF/Documents/19Feb15_072308am.aif";
NSURL *url = [NSURL URLWithString:murl];
[arr insertObject:url atIndex:0];
NSLog(#"Array is %#",arr);
Output
Array is (
"file:///var/mobile/Containers/Data/Application/E991FAFC-80DB-437B-B214-96720B1AA7AF/Documents/19Feb15_072308am.aif"
)
What I strongly feel is you are using NSArray against NSMutableArray. Please confirm the same.
Could you post the actual code so that we can tell you what is going on?
Ok after a bit of playing around I found out what was "wrong" or at least what is stopping my code from working. It is because before I was initialising the NSMutableArray in the viewDidLoad method. As soon as I moved the NSMutableArray initialisation code to method where I wanted to write the data to it, it started working. Anyone know why?? Here is my code now:
// Initialise the audio arrays.
// Originally this line was in the viewDidLoad.
dataFiles = [[NSMutableArray alloc] init];
if ([dataFiles count] == 0) {
[dataFiles addObject:url];
}
else {
[dataFiles insertObject:url atIndex:0];
}
You can do in Following way :
NSMutableArray * arr = [[NSMutableArray alloc]init];
NSString *url = #"www.test.com";
[arr addObject:url];
NSLog(#"Count of Array is %i",[arr count]);
*** if you want to add multiple items then you can do by following way
for (int i =0; i < 5; i++) {
[arr addObject:#"Hello"];
}
NSLog(#"Count of array is %i",[arr count]);

Create NSMutableArray with NSDictionary elements slow

This chunk of code is a method that creates an array for use by multiple other classes. Input is an array from a CoreData fetch, of type NSDictionaryResultType.
3 of the fields are strings that I need to break into arrays, thus the componentsSeparatedByString.
The resulting array, _dataProductionArray, works great --- BUT --- this chunk of code takes a FULL 5 SECONDS to process for about 32,000 records.
Any help pointing out glaring mistakes that are causing this slow performance would be greatly appreciated!!
NSMutableArray *dataArray = [NSMutableArray array];
int j = 0;
int maxNumMonths = 0;
for (id obj in _dictionaries) {
if ([_dictionaries[j] [#"month"] length] >0 ) {
// get production values
NSArray *aItems = [_dictionaries[j] [#"prodA"] componentsSeparatedByString:#","];
NSArray *bItems = [_dictionaries[j] [#"prodB"] componentsSeparatedByString:#","];
NSArray *monthItems = [_dictionaries[j] [#"month"] componentsSeparatedByString:#","];
NSMutableArray *productionAArray = [NSMutableArray array];
NSMutableArray *productionBArray = [NSMutableArray array];
int monthLoop = 1;
for (NSNumber *month in monthItems) {
if (monthLoop <= MONTHS_OF_PRODUCTION) {
if ([month intValue] == monthLoop) {
[productionAArray addObject:[aItems objectAtIndex:monthLoop-1]];
[productionBArray addObject:[bItems objectAtIndex:monthLoop-1]];
productionCount ++;
if (monthLoop > maxNumMonths)
maxNumMonths = monthLoop;
}
}
monthLoop++;
}
NSDictionary *arrayItem = #{#"name":_dictionaries[j] [#"name"],
#"type":[NSString stringWithFormat:#"%#",_dictionaries[j] [#"type"]],
#"height":[NSString stringWithFormat:#"%#",_dictionaries[j] [#"height"]],
#"aArray":productionAArray,
#"bArray":productionBArray,
};
[dataArray addObject:arrayItem];
}
j++;
}
_dataProductionArray = [NSArray arrayWithArray:dataArray];
I can see a few optimizations you could do in the loop, but I'm not sure how much these would help (especially if the compiler is doing them anyway). The root problem is that 32k is a lot of iterations.
Do you need all 32k results at once? You could get a dramatic improvement in user experience by doing this work lazily, as the UI demands the transformed record.
This approach would be to make dataProductionArray a mutable dictionary, indexed by an NSNumber index. Then, instead of ...
// replace this
self.dataProductionArray[128];
// with this
[self dataProductionAtIndex:#128];
That new getter method calls the code you wrote lazily, like this ...
- (id)dataProductionAtIndex:(NSNumber *)index {
// replace dataProductionArray with dataProductionDictionary
id result = self.dataProductionDictionary[index];
if (!result) {
result = [self getDataAt:index];
self.dataProductionDictionary[index] = result;
}
return result;
}
Then getDataAt: is a simple refactor of the code you posted, except instead of looping 32k elements, it does the work for just one index that gets passed in....
- (id)getDataAt:(NSNumber *)index {
int j = [index intValue];
// no loop, just skip to iteration j
NSArray *aItems = [_dictionaries[j] [#"prodA"] componentsSeparatedByString:#","];
NSArray *bItems = [_dictionaries[j] [#"prodB"] componentsSeparatedByString:#","];
// and so on, then at the end, don't save arrayItem, just return it
NSDictionary *arrayItem = #{#"name":_dictionaries[j] [#"name"],
#"type":[NSString stringWithFormat:#"%#",_dictionaries[j] [#"type"]],
#"height":[NSString stringWithFormat:#"%#",_dictionaries[j] [#"height"]],
#"aArray":productionAArray,
#"bArray":productionBArray,
};
return arrayItem;
}
PS - A mutable dictionary is a good data structure for lazy evaluation. The next level of sophistication is NSCache, which acts like a mutable dictionary and also manages memory (class ref here).
Your for loop is daft. Just write
for (NSDictionary* dict in _dictionaries)...
and use dict instead of _dictionaries [j]. One method call saved each time.
stringWithFormat: creates a new string each time. Can't you just add the item itself instead of turning it into a string?
Instead of extracting all the items into productionAArray and productionBArray, create an NSIndexSet, fill it in the loop -- or better yet using a block -- and create the arrays in one go.

EXC_BAD_ACCES in NSArray

getting a "Thread 1: EXC_BAD_ACCES(code=2, adress=0xbf7fffffc)" error at
NSArray *tempArray ] [lijstString componentsSeperatedByString:#","];
What can i do about this?
This is the whole codepart:
-(NSMutableArray *)lijstArray{
NSString *lijstString = self.details[#"lijst"];
NSArray *tempArray = [lijstString componentsSeparatedByString:#", "];
self.lijstArray = [NSMutableArray array];
for (NSString *lijstValue in tempArray) {
[self.lijstArray addObject:[lijstValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
return self.lijstArray;
}
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 2;
}
Your lijstArray getter function is infinitely recursive. Assuming lijstArray is an #property, every time you use self.lijstArray you are calling the instance method lijstArray if used as a getter or setLijstArray if used as a setter.
You are using self.lijstArray three times. The first use on the left part of the assignment operator is only calling [self setLijstArray: ... ] so while that will trample the _lijstArray iVar, it will not cause recursion.
You cause recursion in two places, though once is enough. First is with [self.lijstArray addObject: ... ] which is the same as [[self lijstArray] addObject: ... ]. This causes infinite recursion.
And then with return self.lijstArray which is the same as return [self lijstArray] -- again the lijstArray instance method is calling itself. This also causes infinite recursion.
Incidentally the stack trace would be informative-- you'd have a very deep stack.
try this:
-(NSMutableArray *)lijstArray{
if(!_lijstArray){ //If you need get new lijstArray always, comment this line, and below "}"
NSString *lijstString = self.details[#"lijst"];
NSArray *tempArray = [lijstString componentsSeparatedByString:#", "];
_lijstArray = [NSMutableArray array];
for (NSString *lijstValue in tempArray) {
[_lijstArray addObject:[lijstValue stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]];
}
}
return _lijstArray;
}
Check to make sure the line:
self.details[#"list"];
Is not null. Also check to make sure tempArray and lijstString are being allocated and initialized.

Initialize Array of Objects using NSArray

I'm pretty new to Objective-C and iOS so I've been playing around with the Picker View. I've defined a Person Class so that when you create a new Person it automatically gives that person a name and age.
#import "Person.h"
#implementation Person
#synthesize personName, age;
-(id)init
{
self = [super init];
if(self)
{
personName = [self randomName];
age = [self randomAge];
}
return self;
}
-(NSString *) randomName
{
NSString* name;
NSArray* nameArr = [NSArray arrayWithObjects: #"Jill Valentine", #"Peter Griffin", #"Meg Griffin", #"Jack Lolwut",
#"Mike Roflcoptor", #"Cindy Woods", #"Jessica Windmill", #"Alexander The Great",
#"Sarah Peterson", #"Scott Scottland", #"Geoff Fanta", #"Amanda Pope", #"Michael Meyers",
#"Richard Biggus", #"Montey Python", #"Mike Wut", #"Fake Person", #"Chair",
nil];
NSUInteger randomIndex = arc4random() % [nameArr count];
name = [nameArr objectAtIndex: randomIndex];
return name;
}
-(NSInteger *) randomAge
{
//lowerBound + arc4random() % (upperBound - lowerBound);
NSInteger* num = (NSInteger*)(1 + arc4random() % (99 - 1));
return num;
}
#end
Now I want to make an array of Persons so I can throw a bunch into the picker, pick one Person and show their age. First though I need to make an array of Persons. How do I make an array of objects, initialize and allocate them?
There is also a shorthand of doing this:
NSArray *persons = #[person1, person2, person3];
It's equivalent to
NSArray *persons = [NSArray arrayWithObjects:person1, person2, person3, nil];
As iiFreeman said, you still need to do proper memory management if you're not using ARC.
NSMutableArray *persons = [NSMutableArray array];
for (int i = 0; i < myPersonsCount; i++) {
[persons addObject:[[Person alloc] init]];
}
NSArray *arrayOfPersons = [NSArray arrayWithArray:persons]; // if you want immutable array
also you can reach this without using NSMutableArray:
NSArray *persons = [NSArray array];
for (int i = 0; i < myPersonsCount; i++) {
persons = [persons arrayByAddingObject:[[Person alloc] init]];
}
One more thing - it's valid for ARC enabled environment, if you going to use it without ARC don't forget to add autoreleased objects into array!
[persons addObject:[[[Person alloc] init] autorelease];
No one commenting on the randomAge method?
This is so awfully wrong, it couldn't be any wronger.
NSInteger is a primitive type - it is most likely typedef'd as int or long.
In the randomAge method, you calculate a number from about 1 to 98.
Then you can cast that number to an NSNumber. You had to add a cast because the compiler gave you a warning that you didn't understand. That made the warning go away, but left you with an awful bug: That number was forced to be a pointer, so now you have a pointer to an integer somewhere in the first 100 bytes of memory.
If you access an NSInteger through the pointer, your program will crash. If you write through the pointer, your program will crash. If you put it into an array or dictionary, your program will crash.
Change it either to NSInteger or int, which is probably the best, or to NSNumber if you need an object for some reason. Then create the object by calling [NSNumber numberWithInteger:99] or whatever number you want.
This might not really answer the question, but just in case someone just need to quickly send a string value to a function that require a NSArray parameter.
NSArray *data = #[#"The String Value"];
if you need to send more than just 1 string value, you could also use
NSArray *data = #[#"The String Value", #"Second String", #"Third etc"];
then you can send it to the function like below
theFunction(data);
This way you can Create NSArray, NSMutableArray.
NSArray keys =[NSArray arrayWithObjects:#"key1",#"key2",#"key3",nil];
NSArray objects =[NSArray arrayWithObjects:#"value1",#"value2",#"value3",nil];

Resources