Values of array not calculating in subclass when called - objective-c

Just doing some of the Gold challenges in the BNR iOS book and Chapter 2's challenge has got me stumped.
This is my BNRContainer.m class file that is a subclass of BNRItem. The object of the challenge is to override the object's description and print out some of it's attributes. The one that isn't calculating correctly is the BNRContainer's containerValue.
#import "BNRContainer.h"
...
-(int)containerValue{
int total = 0;
for (BNRItem *item in self.subItems) {
total += item.valueInDollars;
}
return total;
}
-(NSString *)description{
NSString *descriptionstr = [NSString stringWithFormat:#"I'm a container named %#! My total value is %d and my items are %#",self.itemName, containerValue, self.subItems];
return descriptionstr;
}
Here's the Main.m:
#import <Foundation/Foundation.h>
#import "BNRItem.h"
#import "BNRContainer.h"
int main(int argc, const char * argv[])
{
#autoreleasepool {
NSMutableArray *items = [[NSMutableArray alloc] init];
BNRItem *item = [[BNRItem alloc] initWithItemName:#"Red Sofa" valueInDollars:100 serialNumber:#"A1B2C"];
BNRItem *itemWithName = [[BNRItem alloc] initWithItemName:#"Blue Sofa" valueInDollars:45 serialNumber:NULL];
BNRItem *itemWithNoName = [[BNRItem alloc]init];
[items addObject:item];
[items addObject:itemWithName];
[items addObject:itemWithNoName];
BNRContainer *container = [[BNRContainer alloc]init];
container.itemName = #"TheMainContainer";
container.subItems = items;
NSLog(#"%#",container);
items = nil;
}
return 0;
}
my results:
2014-04-08 23:38:58.395 RandomItems[83205:303] I'm a container named TheMainContainer! My total value is 0 and my items are (
"Red Sofa (A1B2C): Worth 100, Recorded on 2014-04-09 03:38:58 +0000",
"Blue Sofa ((null)): Worth 45, Recorded on 2014-04-09 03:38:58 +0000",
"Item (): Worth 0, Recorded on 2014-04-09 03:38:58 +0000"

well there it is... good old exclusion of self
NSString *descriptionstr = [NSString
stringWithFormat:#"I'm a container named %#! My total value is %d and my items are %#",
self.itemName,
self.containerValue, //self was missing
self.subItems];

Related

Objective-C method_exchangeImplementations result is not as expected

I'm learning Objective-C runtime, and try to use method_exchangeImplementations to exchange addObject: method and removeObject: method of NSMutableArray.
My code like this:
int main(int argc, const char * argv[]) {
#autoreleasepool {
Method removeMethod = class_getInstanceMethod(NSMutableArray.class, #selector(removeObject:));
Method addMethod = class_getInstanceMethod(NSMutableArray.class, #selector(addObject:));
method_exchangeImplementations(addMethod, removeMethod);
NSMutableArray *array = [[NSMutableArray alloc] init];
NSObject *obj = [[NSObject alloc] init];
[array removeObject:obj];
NSLog(#"%lu", (unsigned long)array.count); // expect print 1, actual print 1
[array addObject:obj];
NSLog(#"%lu", (unsigned long)array.count); // expect print 0, actual print 2
}
return 0;
}
I expect exchange add/remove function, but seems like only removeObject: has been exchange to addObject: , addObject: still is addObject to array, now I have two addObject method of NSMutableArray
I'm not sure the reason. I try to exchange other method like uppercaseString/lowercaseString of NSString, that work correct.
OK, I solved problem. Thanks #Willeke for the tip.
The real class of my array is not NSMutableArray, so use NSMutableArray.class in class_getInstanceMethod can't get correct method. Use [array class] is the answer.
int main(int argc, const char * argv[]) {
#autoreleasepool {
NSMutableArray *array = [[NSMutableArray alloc] init];
Method removeMethod = class_getInstanceMethod([array class], #selector(removeObject:));
Method addMethod = class_getInstanceMethod([array class], #selector(addObject:));
method_exchangeImplementations(addMethod, removeMethod);
NSObject *obj = [[NSObject alloc] init];
[array removeObject:obj];
NSLog(#"%lu", (unsigned long)array.count); // expect print 1, actual print 1
[array addObject:obj];
NSLog(#"%lu", (unsigned long)array.count); // expect print 0, actual print 0
}
return 0;
}

ObjC : NSLog a pointer name

I filled a NSMutableArray with 3 class instances I created. Now I want to iterate this array to get some variable values. I'm able to do so, but not able to print my instance name (bread, water, ...) Instead, I get their addresses.
I guess it's simple but I'm struggling a bit, so if someone knows how to ...
Thank you
#import <Foundation/Foundation.h>
#import "StockHolding.h";
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
StockHolding *bread = [[StockHolding alloc] init];
[bread setPurchaseSharePrice:100];
[bread setCurrentSharePrice:120];
[bread setNumberOfShares:100];
StockHolding *water = [[StockHolding alloc] init];
[water setPurchaseSharePrice:100];
[water setCurrentSharePrice:80];
[water setNumberOfShares:10];
StockHolding *tomatoes = [[StockHolding alloc] init];
[tomatoes setPurchaseSharePrice:100];
[tomatoes setCurrentSharePrice:50];
[tomatoes setNumberOfShares:1];
NSMutableArray *myStock = [NSMutableArray arrayWithObjects:bread, water, tomatoes, nil];
for (StockHolding *s in myStock)
{
NSLog(#"Here is what I paid for my %p : %f", s, [s costInDollars]);
NSLog(#"Here is what I earn for my %p : %f", s, [s valueInDollars]);
}
[pool drain];
return 0;
}
Why not implement the -(NSString *)description method on your StockHolding class? Then you can use %# in string formats and it will output the description there.
Alternatively you can also output any other string property of StockHolding instances with %#.
If you want to NSLog an object and it's pointer name you can add this #define in your preprocessor macro #define OLog(x) NSLog(#"%s = %#",#x, x);

First try at sorting an array

I am trying to sort an array by the highest number that I assigned to each entry in the array.
However i don't think it's doing anything.
Any suggestions on where the error may be?
Thanks!
- (NSArray*)sortByPercentage:(NSArray*)array {
NSArray *inputArray = array;
NSSortDescriptor *sortDescriptor = [[ NSSortDescriptor alloc] initWithKey:#"percentMatched" ascending:YES];
//nov 8
NSArray *sortDescriptors = [NSArray arrayWithObject:sortDescriptor];
NSArray *finalResult = [inputArray sortedArrayUsingDescriptors:sortDescriptors];
[sortDescriptor release];
return [NSArray arrayWithArray:finalResult];
}
I'm intrigued by why your sort doesn't work. This does:
#import <Foundation/Foundation.h>
#interface FooObject : NSObject
#property (nonatomic, assign) NSInteger value;
#property (readonly) NSInteger percentMatched;
#end
#implementation FooObject
#synthesize value;
// compute percentMatched as an elementary function of value
- (NSInteger)percentMatched {
return value * 2;
}
#end
int main(int argc, char *argv[]) {
NSAutoreleasePool *p = [[NSAutoreleasePool alloc] init];
FooObject *foo1 = [[FooObject alloc] init];
foo1.value = 50;
FooObject *foo2 = [[FooObject alloc] init];
foo2.value = 5;
FooObject *foo3 = [[FooObject alloc] init];
foo3.value = 10;
NSArray *myFoos = [NSArray arrayWithObjects:foo1,foo2,foo3,nil];
NSArray *sorters = [NSArray arrayWithObject:[NSSortDescriptor sortDescriptorWithKey:#"percentMatched" ascending:YES]];
NSArray *mySortedFoos = [myFoos sortedArrayUsingDescriptors:sorters];
for(FooObject *foo in mySortedFoos ) {
printf("%ld ",foo.percentMatched);
}
}
Prints 10 20 100 to the console as expected.

How to release object of another class in our class?

I have created two classes (FirstClass and SecondClass) in command line application. I created an object of SecondClass in FirstClass method. Now I want to call that method in main and release the memory allocated to that object. My code is as follows..
#implementation FirstClass
+(NSMutableArray *) addObject{
NSMutableArray *namesArray = [[[NSMutableArray alloc]init] autorelease];
SecondClass *second = [[SecondClass alloc]init];
NSLog(#"Before adding object, count = %ld ",[second retainCount]); //RC = 1
[second setName:#"Mobicule"];
[namesArray addObject:second];
NSLog(#"First object addeded, count = %ld ",[second retainCount]); //RC = 2
[second release];
NSLog(#"After release, count = %ld",[second retainCount]); //RC = 1
return namesArray;
}
#end
I want to make retain count to zero..
And main function is as follows..
int main (int argc, const char * argv[]) {
#autoreleasepool {
// insert code here...
// NSLog(#"Hello, World!");
NSMutableArray *arrayMain = [[NSMutableArray alloc]init];
arrayMain = [FirstClass addObject];
for (int i = 0; i<[arrayMain count]; i++) {
NSLog(#"%#",[[arrayMain objectAtIndex:i] name]);
}
NSLog(#"%ld",[arrayMain retainCount]);
}
return 0;
}
I am assuming your synthesised property for name is retain.
+(NSMutableArray *) addObject{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *namesArray = [[NSMutableArray alloc]init];
SecondClass *second = [[[SecondClass alloc]init]autorelease];
NSLog(#"Before adding object, count = %ld ",[second retainCount]); //RC = 1
[second setName:#"Mobicule"]; //implementation will handle the release for you
[namesArray addObject:second];
NSLog(#"First object addeded, count = %ld ",[second retainCount]); //RC = 2
[pool release];
NSLog(#"After pool release, count = %ld",[second retainCount]); //RC=1
return [namesArray autorelease];
}
You should never use -retainCount, because it never tells you anything
useful.
Take a look at When to use -retainCount?

printing an array of arrays in objective C

Sorry for the simple question, but I am self taught and know that there are gaps in my education.
To print an array in objective C, I believe is:
NSLog(#"My array: %#", myArray);
How can I print an array of arrays?
Thanks
You want this:
for(NSArray *subArray in myArray) {
NSLog(#"Array in myArray: %#",subArray);
}
This will work for an array that has arrays nested one level deep.
You don't need to do anything different to log an array of arrays; the code exactly as you've written it will already show the contents of the sub-arrays.
That is, the following program:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
NSMutableArray *array = [NSMutableArray array];
for (int i=0; i<5; ++i) {
NSMutableArray *sub = [NSMutableArray array];
for (int j=0; j<=i; ++j) {
[sub addObject:[NSString stringWithFormat:#"%d", j]];
}
[array addObject:sub];
}
NSLog(#"Array: %#", array);
[pool drain];
return 0;
}
Produces the following output:
Array: (
(
0
),
(
0,
1
),
(
0,
1,
2
),
(
0,
1,
2,
3
),
(
0,
1,
2,
3,
4
)
)
Clearly, it's already logging the sub-arrays just fine. If you want to control the formatting differently, you'd have to manually iterate them, but by default, the -description of an NSArray is little more than the -description of every object in that array, which includes all sub-arrays.
So I was embarrassed by the recursiveDescription thing, so I wrote my own as a category on NSArray. Note that this code will print out a description for an array of arrays to any depth. The description itself could probably use a bit more formatting than commas and newlines. Here you go:
#interface NSArray (RecursiveDescription)
- (NSString *)recursiveDescription;
#end
#implementation NSArray (RecursiveDescription)
- (NSString *)recursiveDescription {
NSMutableString *description = [[NSMutableString alloc] initWithString:#"Array (\n"];
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
for (NSObject *child in self) {
if ([child respondsToSelector:#selector(recursiveDescription)]) {
[description appendFormat:#"%#,\n", [child recursiveDescription]];
}
else {
[description appendFormat:#"%#,\n", [child description]];
}
}
[pool drain];
[description appendString:#"\n)"];
return [description autorelease];
}
#end
Try logging the return value from NSArray's -description method.
NSLog(#"My array: %#", [myArray description]);
Moreover, for print all of elements
int i = 0;
int j = 0;
for(NSArray *subArray in myArray) {
NSLog(#"[%d] %#",i, subArray);
j =0;
for(NSObject *element in subArray) {
NSLog(#"[%d:%d] %#", i,j,element);
++j;
}
++i;
}
As much as I like how easy it is to log out an object in Objective-C, I didn't like seeing a 2D array as a very long list. I created a category on NSArray that prints out 2D arrays. It's not perfect and can be improved, but it has worked for me.
Header:
#interface NSArray (Logging)
- (void)log2DArray;
#end
Implementation:
#import "NSArray+Logging.h"
#implementation NSArray (Logging)
- (void)log2DArray {
NSMutableString *formattedString = [[NSMutableString alloc] init];
NSInteger longestSubarrayLength = 0;
for (NSArray *subarray in self) {
if (subarray.count > longestSubarrayLength) {
longestSubarrayLength = subarray.count;
}
}
for (int i = 0; i < longestSubarrayLength; i++) {
[formattedString appendFormat:#"\n"];
for (int j = 0; j < self.count; j++) {
NSArray *tempArray = [self objectAtIndex:j];
if (tempArray.count <= longestSubarrayLength) {
[formattedString appendFormat:#"%#\t", [tempArray objectAtIndex:i]];
} else {
[formattedString appendFormat:#"\t"];
}
}
}
NSLog(#"%#", formattedString);
}
#end
Usage:
[myArray log2DArray];
Or use recursiveDescription :)
NSLog(#"my arrays: %#", [myArray recursiveDescription]);