0

I am quite confused on doing fast enumeration with array filled with similar objects

Suppose :

I have 1 class (Stock Class), it has 1 subClass ForeignStock.

Properties of Stock Class :

@property float purchaseSharePrice,currentSharePrice;
@property int numberOfShares;

Properties of ForeignStock

@property float conversionRate;

I put instances from those 2 above into a MutableArray. How do I display(NSLog) those 2 different Objects with Fast Enumeration?

 int i = 1;
    for (StockHolding *iterate in shelf) {

        if ([iterate isMemberOfClass:[StockHolding class]])
        {

            NSLog(@"============ Properties of Stock Value %i ============",i);
            NSLog(@"purchase price is  %f",iterate.purchaseSharePrice);
            NSLog(@"current price is %f",iterate.currentSharePrice);
            NSLog(@"number of shares bought is %i",iterate.numberOfShares);

            NSLog(@"--------------Total Value & Cost--------------");
            NSLog(@"Value in dollar for this stock is %f",iterate.valueInDollars);
            NSLog(@"Cost in dollar for this stock is %f",iterate.costInDollars);


            i++;
        }
        else{
            for (ForeignStockHolding *iterate1 in shelf) {
                if ([iterate1 isMemberOfClass:[ForeignStockHolding class]]) {
                    NSLog(@"============ Properties of Stock Value %i  ============",i);
                    NSLog(@"purchase price is  %f",iterate1.purchaseSharePrice);
                    NSLog(@"current price is %f",iterate1.currentSharePrice);
                    NSLog(@"number of shares bought is %i",iterate1.numberOfShares);

                    NSLog(@"--------------Total Value, Cost, & Conversion Rate --------------");
                    NSLog(@"Value in dollar for this stock is %f",iterate1.valueInDollars);
                    NSLog(@"Cost in dollar for this stock is %f",iterate1.costInDollars);
                    NSLog(@"Conversion rate for this stock is %f",iterate1.conversionRate);

                    i++;
                }
            }
        }
    }

Those code above didn't work out, the output for ForeignStock NSLogged 2 times for each ForeignStock instance (I know, for method at second fast enumeration is wrong).

How do I build fast enumeration which it could differ each object's class inside array with different treatment for each class-subclass objects?

3
  • Your question talks about the Stock and ForeignStock classes but your code references StockHolding and ForeignStockHolding. It would help if you made them match up. Commented Aug 3, 2014 at 0:22
  • 1
    You can do it with isKindOfClass but the better approach would be to put a method into both the parent and the subclass that does whatever you need and simply invoke it in your loop...let the object figure out the right behavior. Polymorphism...it works! :) Commented Aug 3, 2014 at 0:25
  • Poor design. Make ForeignStockHolding a subclass of StockHolding. Implement a -printInfo method (or similar). StockHolding shows as above, ForeignStockHolding call [super printInfo], then prints the conversion rate. In general you never want to implement complex knowledge of classes into other classes, that is not what object oriented programming is about. Commented Aug 3, 2014 at 0:28

3 Answers 3

1

If the problem you're trying to solve it to get a good representation of an object for debugging, then consider overriding the -description method in your class. Here's an example of that for both these classes:

@implementation StockHolding

- (NSString *)description
{
    NSString *objectDescriptionFormat = 
    @"============ Properties of Stock Value %@ ============\n"
    "purchase price is  %f\n"
    "current price is %f\n"
    "number of shares bought is %i\n"
    "\n"
    "--------------Total Value & Cost--------------\n"
    "Value in dollar for this stock is %f\n"
    "Cost in dollar for this stock is %f\n";

    return [NSString stringWithFormat:objectDescriptionFormat, 
        [super description],
        self.purchaseSharePrice,
        self.currentSharePrice,
        self.numberOfShares,
        self.valueInDollars,
        self.costInDollars];
}

@end


@implementation ForeignStockHolding

- (NSString *)description
{
    NSString *objectDescriptionFormat = 
    @"%@"
    "Conversion rate for this stock is %f\n";

    return [NSString stringWithFormat:objectDescriptionFormat, 
        [super description],
        self.conversionRate];
}

@end

Logging the object becomes easy because you can just log the object and the description will get printed on the console.

for (StockHolding *stockHolding in shelf)
{
    NSLog(@"%@", stockHolding);
}
Sign up to request clarification or add additional context in comments.

2 Comments

[super description] on your code is displaying object's address, is it possible to make it to display object's name? for instance I create instance of StockHolding, called StockHolding1, StockHolding2,... then it will display StockHolding1, StockHolding2, not its address.
Is StockHolding1 the name of the variable, or a property of the object?
1

Deciding what to do based on the result of the isMemberOfClass: call is usually a good indication that you have missed an opportunity for inheritance: in most cases, a proper solution is to add a method to the base class, and override it in the derived class.

In this specific case, consider overriding an existing method called description, inherited from NSObject. Both StockHolding and ForeignStockHolding should provide an implementation:

// This implementation goes in StockHolding
-(NSString*)description {
    return [NSString stringWithFormat:@"purchase price is  %f\n"
        "current price is %f\n"
        "number of shares bought is %i\n"
        "--------------Total Value & Cost--------------\n"
        "Value in dollar for this stock is %f\n"
        "Cost in dollar for this stock is %f"
    ,   _purchaseSharePrice
    ,   _currentSharePrice
    ,   _numberOfShares
    ,   _valueInDollars
    ,   _costInDollars
    ];
}
// This implementation goes into ForeignStockHolding
-(NSString*)description {
    return [NSString stringWithFormat:@"%@\n"
        "Conversion rate for this stock is %f"
    ,   [super description]
    ,   _ conversionRate
    ];
}

With these two implementations in place, you can log all your data uniformly, like this:

for (StockHolding *item in shelf) {
    NSLog(@"%@", item);
}

2 Comments

You might want to rename -display to -description. It's mentioned correctly in your answer but not in the code snippet.
@Anurag You're right, I talk about overriding description in the body, and then call it display in the example! Thanks!
1

Here's one approach:

int i = 1;
for (StockHolding *iterate in shelf) {

    NSLog(@"============ Properties of Stock Value %i ============",i);
    NSLog(@"purchase price is  %f",iterate.purchaseSharePrice);
    NSLog(@"current price is %f",iterate.currentSharePrice);
    NSLog(@"number of shares bought is %i",iterate.numberOfShares);

    if ([iterate isKindOfClass:[ForeignStockHolding class]])
        NSLog(@"--------------Total Value, Cost, & Conversion Rate --------------");
    else
        NSLog(@"--------------Total Value & Cost--------------");

    NSLog(@"Value in dollar for this stock is %f",iterate.valueInDollars);
    NSLog(@"Cost in dollar for this stock is %f",iterate.costInDollars);

    if ([iterate isKindOfClass:[ForeignStockHolding class]])
        NSLog(@"Conversion rate for this stock is %f", ((ForeignStockHolding*)iterate).conversionRate);

    i++;
}

You don't want a second for loop, you just want to tweak the behavior based on the class. When you test the class, I recommend that you test for the object being an instance of the specialized subclass rather than being it being of exactly the base class.

However, testing for the class of an object is often a code smell. It is usually better to have a class define its own behavior and then have client code simply ask the object to perform the behavior. So, for example, the object could be asked to describe itself. The StockHolding class would generate a description string including its properties. The ForeignStockHolding class would call super to get the base description and then add to it using the properties which it adds.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.