问题描述:

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?

网友答案:

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);
}
网友答案:

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);
}
网友答案:

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.

相关阅读:
Top