Passing an array between classes - strange error? - iphone

So I am creating and populating an array in Class A - then in Class B I call a method of class A to get the array
ClassA.h
-(NSMutableArray*)getArray
ClassA.m
-(NSMutableArray* )getFeedsArray
{
NSMutableArray *myArray;
if (!myArray)
{
myArray = [[NSMutableArray alloc]init];
[myArray addObject: #"hello"];
}
NSLog (#"Feeds array: %d", [myArray count ]);
return myArray;
}
}
Then in Class B - I do this:
ClassB.m
-(void)loadData
{
ClassA *classA = [[ClassA alloc]init];
NSMutableArray *mutableArray = [classA getFeedsArray];
NSLog (#"Items in Array: %d", [mutableArray count]);
}
The above works perfectly - array counts show 1, which is what the test should do.
However, when I do this:
in classA.m
-(NSMutableArray* )getFeedsArray
{
NSLog (#"Feeds array: %d", [feedsDownload count ]);
return feedsDownload;
}
The count is zero.
So I checked the feedDownload array in another method inside of ClassA.m that gets called before the getFeedsArray method does and it returns the correct value from that method.
However, when getFeedsArray is called from ClassB.m - the array count is zero. But it is only zero with the second version of the getFeedsArray code:
So if I do this and don't touch any other code:
-(NSMutableArray* )getFeedsArray
{
NSMutableArray *myArray;
if (!myArray)
{
myArray = [[NSMutableArray alloc]init];
[myArray addObject: #"hello"];
}
NSLog (#"Feeds array: %d", [myArray count ]);
return myArray;
}
Results:
Feeds array: 1 (from ClassA.m otherMethod) - otherMethod calls getFeedsArray method.
Feeds array:1
Items in Array: 1 (Inside ClassB.m)
If I then change the code like this:
-(NSMutableArray* )getFeedsArray
{
NSLog (#"Feeds array: %d", [feedsDownload count ]);
return feedsDownload;
}
Results:
Feeds array:1 (from ClassA.m otherMethod) - otherMethod calls getFeedsArray method.
Feeds array:0
Items in Array: 0 (Inside ClassB.m)
So it seems the second call to getFeedsArray gives me a zero count of my array.
Sorry but, WTH is happening here and what am I missing??
Thanks!

Related

How is the code for separation of single array into two arrays?

I am getting below response into the nsarray when I used the JSON parsing from my required URL but here I don't like to get 2,1,4,4,6,5,8,7,10,9,12 and 11 in single array I have to get total response into two arrays I mean one array set will consists 2,4,6,8,10 and other array set must be 3,5,7,9 and 11.
So how is the code for separation of single array response into two arrays in iPhone?
"(\n 2,\n 1\n)",
"(\n 4,\n 3\n)",
"(\n 6,\n 5\n)",
"(\n 8,\n 7\n)",
"(\n 10,\n 9\n)",
"(\n 12,\n 11\n)"
If you combine every number into one large array, you could feasibly test if each number is even or odd with a simple if-else in a for-in loop. Maybe like this:
-(NSArray*)parseJSONIntoArrays:(NSArray*)array {
NSMutableArray *evenNumbers = [[NSMutableArray alloc]init];
NSMutableArray *oddNumbers = [[NSMutableArray alloc]init];
for (NSNumber *number in array) {
if (([number intValue] %2) == 0) {
//even
[evenNumbers addObject:number];
}
else {
//odd
[oddNumbers addObject:number];
}
}
return [[NSArray alloc]initWithObjects:evenNumbers, oddNumbers, nil];
}
To split an array, you usually need to loop through all of the values and use an IF ELSE structure to decide which array to put the values in. Also, you need to use NSMutableArray instead of NSArray. Something like this:
NSMutableArray *evenNumbers = [NSMutableArray new];
NSMutableArray *oddNumbers = [NSMutableArray new];
for (NSNumber *value in myArray) {
if ([value intValue] % 2 == 0) {
[evenNumbers addObject:value];
} else {
[oddNumbers addObject:value];
}
}

Getting Null array

I have following code :
- (IBAction)goButton:(id)sender
{
if(buttonCount==0)
{
previousStateArray=setUpArray;
NSLog(#"previous array count=%d",[previousStateArray count]);
[setUpArray removeAllObjects];
for(Node *n in nodeArray)
{
if(![temp isEqualToString:n.strName])
{
[setUpArray addObject:n.strName];
}
temp=n.strName;
}
}
}
- (IBAction)backButton:(id)sender
{
[setUpArray removeAllObjects];
setUpArray=previousStateArray;
NSLog(#"previous array count=%d",[previousStateArray count]);
buttonCount--;
}
Both setUpArray and previousStateArray are declared in the -viewDidLoad method.My view is loading only once.In first NSLog i am getting 1 as a output but in second NSLog i am getting
0 as a output while none of my array initialize again . so why this is happening???
Your problem is with your array pointers.
In goButton :
previousStateArray=setUpArray;
Now previousStateArray points to the same array setUpArray is pointing to.
[setUpArray removeAllObjects];
This removes all objects and now both pointers point to an empty array.
In backButton:
setUpArray=previousStateArray;
They both point to the same empty array so this line is redundant.
You should keep a temporary pointer if you want to swap the pointers.
In your code
`previousStateArray=setUpArray;` //previousStateArray pointing to same memory location of setUpArray.
Use - (void)setArray:(NSArray *)otherArray method of NSMutableArray class.
[previousStateArray setArray: setUpArray];
[setUpArray setArray:previousStateArray];
- (IBAction)goButton:(id)sender
{
if(buttonCount==0)
{
[previousStateArray setArray: setUpArray];
NSLog(#"previous array count=%d",[previousStateArray count]);
[setUpArray removeAllObjects];
for(Node *n in nodeArray)
{
if(![temp isEqualToString:n.strName])
{
[setUpArray addObject:n.strName];
}
temp=n.strName;
}
}
}
- (IBAction)backButton:(id)sender
{
[setUpArray removeAllObjects];
[setUpArray setArray:previousStateArray];
NSLog(#"previous array count=%d",[previousStateArray count]);
buttonCount--;
}
Initialize the array
setUpArray = [[NSMuatableArray alloc] init];
I think giorashc's answer is correct.
Your problem is using "=" for Array only makes the new one previousStateArray points to the same memory of setUpArray. In other words, previousStateArray is the same as setUpArray .
For more detail information , you should search deep & shallow copy.
You should also use if(0 == buttonCount) rather than if(buttonCount==0).

NSArray of united Arrays

I have an NSArray of objects called MMPlace, which has NSArray of MMProduct objects.
How do I get a united NSArray of all MMProduct objects that my Array of MMPlace object contains? Something like NSArray *arr = [array valueForKeyPath:#"#unionOfObjects.products"]; would be nice, though this specific example doesn't work.
You can do this with #unionOfArrays. The bit you were missing is that because the arrays are directly nested, the key on the right of the collection operator must be self:
NSArray *nestedValues = #[#[#1, #2, #3], #[#4, #5, #6]]
NSArray *flattenedValues = [nestedValues valueForKeyPath:#"#unionOfArrays.self"];
// flattenedValues contains #[#1, #2, #3, #4, #5, #6]
Create an NSMutableArray, loop through your original array and call addObjectsFromArray: with each subarray.
I don't think there is an off-the-shelf method that does what you need, but you can easily "flatten" your array in a for loop, and hide the method in a category:
Edit: added a category.
#interface NSArray (flatten)
-(NSArray*) flattenArray;
#end
#implementation NSArray (flatten)
-(NSArray*) flattenArray {
// If inner array has N objects on average, multiply count by N
NSMutableArray *res = [NSMutableArray arrayWithCapacity:self.count];
for (NSArray *element in self) {
[res addObjectsFromArray:element];
}
return res;
}
#end
For this task there is the #unionOfArrays collection operator.
http://developer.apple.com/library/ios/#documentation/cocoa/conceptual/KeyValueCoding/Articles/CollectionOperators.html#//apple_ref/doc/uid/20002176-BAJEAIEE
Here is how I implemented a "flatten" category method that will work on any tree structure. It will take a tree of arbitrary depth and merge it into one long array in order.
- (NSArray *) flattenWithBlock:(NSArray *(^)(id obj))block {
NSMutableArray *newItems = [NSMutableArray array];
for(id subObject in self)
{
if([subObject isKindOfClass:[NSArray class]])
{
[newItems addObjectsFromArray:[subObject flatten:block]];
}
else
[newItems addObject:subObject];
}
return newItems;
}
You could then write a convenience category method which handles the case you described above. This wrapper method will flatten a nd array into a 1d array.
- (NSArray *) flattenArray {
NSArray *newItems = [self flattenWithBlock:^NSArray *(id obj) {
return obj;
}];
return newItems;
}
#interface NSArray (Flatten)
-(NSArray*)flattenedArray;
#end
#implementation NSArray (Flatten)
-(NSArray*)flattenedArray {
NSMutableArray *result = [NSMutableArray arrayWithCapacity:self.count];
for (id thing in self) {
if ([thing isKindOfClass:[NSArray class]]) {
[result addObjectsFromArray:[(NSArray*)thing flattenedArray]];
} else {
[result addObject:thing];
}
}
return [NSArray arrayWithArray:result];
}
#end

NSMutable Array: Getting "out of scope" Status After Mutable Copying

I have a SOAP service and I generated classes and functions on SudzC.com.
So I'm using the soap functions they generated, it returns an NSMutableArray with objects that are inherited by my custom class(which is generated by them, too).
So far everything's good. My values are getting into the array and I could see any property of any object with one condition: Only inside of the function that's handling the service.
Just to make it clear, here is the code:
- (void)viewDidLoad
{
SDZGeneratedWebService* service = [SDZGeneratedWebService service];
service.logging = YES;
[service callMyData:self action:#selector(callMyDataHandler:) dataId: 1];
[super viewDidLoad];
}
- (void) callMyDataHandler: (id) value {
// Handle errors
if([value isKindOfClass:[NSError class]]) {
NSLog(#"%#", value);
return;
}
// Handle faults
if([value isKindOfClass:[SoapFault class]]) {
NSLog(#"%#", value);
return;
}
// Do something with the NSMutableArray* result
NSMutableArray *result = (NSMutableArray *)value;
MyCustomClass *myObject = [result objectAtIndex:0];
NSLog(#"%#", myObject.myProperty); //Works Great
}
Like I said, so far everything's perfect. But I need to use the data outside of this function.
So in my .h file, I created an array like NSMutableArray *myDataArray;
When I intend to copy the result array to myDataArray, it copies the objects(I can see that the myDataArray.count value is equal to result array's) but all the objects are "out of scope". So I cannot use them.
I also tried to copy all objects by indexes in a for loop, nope, the objects are getting their values, but when I "addObject" to myDataArray, same, out of scope.
What is wrong here? Can't I generate an array of a custom class this way?
Edit: The code I'm generating myDataArray:
myDataArray = [[NSMutableArray alloc] init];
[myDataArray removeAllObjects];
for (int i=0; i<((NSMutableArray *)result).count; i++) {
MyCustomClass *myObject = [result objectAtIndex:i];
[myDataArray addObject:myObject];
[myObject release];
}
[self.tableView reloadData];
} //(End of callMyDataHandler function)
I before tried this way, too:
[myDataArray removeAllObjects];
duyurular = [result mutableCopy];
} //(End of callMyDataHandler function)
You can copy objects from one array to another using this method:
NSArray *source;
NSArray *dst = [[NSArray alloc] initWithArray:source];
In your code you should remove line: [myObject release]; and I would better call [((NSMutableArray *)result) count] rather then using dot notation.

How to prevent leak on array with dictionaries used by CorePlot

This is a common case:
In code below (simplified), number of the dictionaries added to the array varies depending on size of data set (as usual).
So it is impossible to match each dictionary with a corresponding 'release' statement.
I assume releasing the array (in dealloc) would release all its enclosed dictionaries?
Nevertheless, it produces a leak. How to eliminate it?
// -----myController.h----
#interface ExerciseGraphController : UIViewController <CPPlotDataSource>{
NSMutableArray *plotDataForBar;
}
#property(readwrite, retain, nonatomic)NSMutableArray *plotDataForBar;
// -----myController.m----
- ...getPlotData... {
//Solution
if (plotDataForBar){
[plotDataForBar release];
}
plotDataForBar = [[NSMutableArray array] init];
//for each item in plotDataForBar {
... //Populates plotDataForBar with dictionaries.
[plotDataForBar addObject: [NSDictionary dictionaryWithObjectsAndKeys: // **LEAK** ( on __NSCFDictionary, __NSArrayM, and _GeneralBlock16)
[NSDecimalNumber numberWithFloat:xF], [NSNumber numberWithInt:CPBarPlotFieldBarLocation],
[NSDecimalNumber numberWithFloat:yF], [NSNumber numberWithInt:CPBarPlotFieldBarLength],
nil]];
}
} //Reads plotDataForBar in:
- ...numberOfRecordsForPlot...{ // Method required by CorePlot
return [plotDataForBar count];
}
- ...numberForPlot... { // " " " "
...
NSDecimalNumber *num = [[plotDataForBar objectAtIndex:index] objectForKey:[NSNumber numberWithInt:fieldEnum]];
...
}
- ...dealloc {
[plotDataForBar release];
[super dealloc];
}
As much code is missing, only a guess:
Shouldn't you test in "...getPlotData..." if that property is already set, or release the old instance? This would be leaking every time this method gets called.