3

I'm writing an objective-C game and I'm at the stage where i should start optimising some of my code in the game loops.
I have an extensive amount of class compare methods used,

if ([obj isMemberOfClass:[SomeClass class]])

etc.
I heard this sort of checking is quite expensive, because I choose only to have 1 array populated with multiple classes, I need some sort of class check.
I was thinking perhaps that adding a property to NSObject subclassing NSObject to contain a string property, that during initialisation i would make equal to the class name of that particular subclass. Then simply doing a

if ([obj.klass isEqualTo:@"SomeClass"])

Would this be beneficial?
I'm trying to keep as much dynamic coding out of the game loops as possible.

Thanks!

4

2 回答 2

10

Short answer: no. String comparison is prohibitively more expensive compared to other methods of comparing (or: classifying, categorizing) objects.

Long answer: don't optimize what you haven't analyzed, measured and compared. What you really want to do before you start optimizing is to get a clear picture of how your app behaves and what its performance bottlenecks are. The change you're attempting is unlikely to lead to any noticeable change in performance, so I suggest to first find the real bottlenecks.

In this particular case, sending isEqual to an NSString is 4 times slower than isMemberOfClass if the test fails. And such conditional tests fail most of the time, which is why you should ignore the results of the test succeeding.

The successful string comparison is fast because it's a simple pointer comparison, if two strings are equal it is likely that they point to the same memory address. If they're not equal, then each character in the string will be compared for equality, probably by using the hash method.

Here are the results of the Object Comparison tests that I added to my performance test project. You can use that project to make further tests.

enter image description here

于 2011-11-24T11:59:40.390 回答
2

This is not really a direct answer to your question but is an answer in a broader sense.

In Objective-C the philosophy is more like that of Smalltalk in which you send the message and let the object decide what to do with it. If you find yourself having to do lots of tests to see what class an object is, you need to rethink your design.

For instance, if you have an array of objects and you want to convert each one to an integer to do some maths on it, you can do something like this:

for (id anObj in array)
{
    int anInt = [anObj intValue];
    // do something with anInt
}

It doesn't matter what the class of each anObj is, you can send -intValue to it. If your array is full of NSStrings and NSNumbers, for example, it doesn't matter, the code above will do what you expect.

Many classes do not define a method for the selector -intValue. For example, if you send that message to an instance of NSData it will respond by throwing an exception. There are a couple of ways to resolve this depending on circumstances.

  1. ignore objects that don't respond to the selector by testing to see if the object knows about the selector

    for (id anObj in array)
    {
        if ([anObject respondsToSelector: @selector(intValue)])
        {
            int anInt = [anObj intValue];
            // do something with anInt
        }
    }  
    
  2. Define the selector for all classes you know will be put in the array. This is done by declaring a category. This way you can extend any Objective-C class without subclassing. For instance, you can define an intValue method for NSData that returns its length, or the sum of its bytes or some other appropriate value.

  3. Formalise the requirement by declaring a protocol. You can then test for conformance to the protocol, or rely on compile time checks to make sure the objects you put in the array conform to the protocol.

There are lots of things you can do, but you need to get away a bit from the C++/Java model of class hierarchies. Objective-C is much more flexible in that respect.

于 2011-11-29T14:08:27.400 回答