views:

376

answers:

5

Currently I am making some decisions for my first objective-c API. Nothing big, just a little help for myself to get things done faster in the future.

After reading a few hours about different patterns like making categories, singletons, and so on, I came accross something that I like because it seems easy to maintain for me. I'm making a set of useful functions, that can be useful everywhere.

So what I did is:

1) I created two new files (.h, .m), and gave the "class" a name: SLUtilsMath, SLUtilsGraphics, SLUtilsSound, and so on. I think of that as kind of "namespace", so all those things will always be called SLUtils**. I added all of them into a Group SL, which contains a subgroup SLUtils.

2) Then I just put my functions signatures in the .h file, and the implementations of the functions in the .m file. And guess what: It works!! I'm happy with it, and it's easy to use. The only nasty thing about it is, that I have to include the appropriate header every time I need it. But that's okay, since that's normal. I could include it in the header prefix pch file, though.

But then, I went to toilet and a ghost came out there, saying: "Hey! Isn't it better to make real methods, instead of functions? Shouldn't you make class methods, so that you have to call a method rather than a function? Isn't that much cooler and doesn't it have a better performance?" Well, for readability I prefer the functions. On the other hand they don't have this kind of "named parameters" like methods, a.f.a.i.k..

So what would you prefer in that case?

Of course I dont want to allocate an object before using a useful method or function. That would be harrying.

Maybe the toilet ghost was right. There IS a cooler way. Well, for me, personally, this is great:

MYNAMESPACECoolMath.h

#import <Foundation/Foundation.h>


@interface MYNAMESPACECoolMath : NSObject {
}

+ (float)randomizeValue:(float)value byPercent:(float)percent;

+ (float)calculateHorizontalGravity:(CGPoint)p1 andPoint:(CGPoint)p2;

// and some more
@end

Then in code, I would just import that MYNAMESPACECoolMath.h and just call:

CGFloat myValue = [MYNAMESPACECoolMath randomizeValue:10.0f byPercent:5.0f];

with no nasty instantiation, initialization, allocation, what ever. For me that pattern looks like a static method in java, which is pretty nice and easy to use.

The advantage over a function, is, as far as I noticed, the better readability in code. When looking at a CGRectMake(10.0f, 42.5f, 44.2f, 99.11f) you'll may have to look up what those parameters stand for, if you're not so familiar with it. But when you have a method call with "named" parameters, then you see immediately what the parameter is.

I think I missed the point what makes a big difference to a singleton class when it comes to simple useful methods / functions that can be needed everywhere. Making special kind of random values don't belong to anything, it's global. Like grass. Like trees. Like air. Everyone needs it.

+6  A: 

Performance-wise, a static method in a static class compile to almost the same thing as a function.

Any real performance hits you'd incur would be in object instantiation, which you said you'd want to avoid, so that should not be an issue.

As far as preference or readability, there is a trend to use static methods more than necessary because people are viewing Obj-C is an "OO-only" language, like Java or C#. In that paradigm, (almost) everything must belong to a class, so class methods are the norm. In fact, they may even call them functions. The two terms are interchangeable there. However, this is purely convention. Convention may even be too strong of a word. There is absolutely nothing wrong with using functions in their place and it is probably more appropriate if there are no class members (even static ones) that are needed to assist in the processing of those methods/functions.

JoshJordan
+1  A: 

You can use a singleton instance instead if you want to avoid instantiating a bunch of utility objects.

There's nothing wrong with using plain C functions, though. Just know that you won't be able to pass them around using @selector for things like performSelectorOnMainThread.

Daniel Dickison
+5  A: 

The problem with your approach is the "util" nature of it. Almost anything with the word "util" it in suggests that you have created a dumping ground for things you don't know where to fit into your object model. That probably means that your object model is not in alignment with your problem space.

Rather than working out how to package up utility functions, you should be thinking about what model objects these functions should be acting upon and then put them on those classes (creating the classes if needed).

To Josh's point, while there is nothing wrong with functions in ObjC, it is a very strongly object-oriented language, based directly on the grand-daddy of object-oriented languages, Smalltalk. You should not abandon the OOP patterns lightly; they are the heart of Cocoa.

I create private helper functions all the time, and I create public convenience functions for some objects (NSLocalizedString() is a good example of this). But if you're creating public utility functions that aren't front-ends to methods, you should be rethinking your patterns. And the first warning sign is the desire to put the word "util" in a file name.

EDIT

Based on the particular methods you added to your question, what you should be looking at are Categories. For instance, +randomizeValue:byPercent: is a perfectly good NSNumber category:

// NSNumber+SLExtensions.h
- (double)randomizeByPercent:(CGFloat)percent;
+ (double)randomDoubleNear:(CGFloat)percent byPercent:(double)number;
+ (NSNumber *)randomNumberNear:(CGFloat)percent byPercent:(double)number;

// Some other file that wants to use this
#import "NSNumber+SLExtensions.h"
randomDouble = [aNumber randomizeByPercent:5.0];
randomDouble = [NSNumber randomDoubleNear:5.0 byPercent:7.0];

If you get a lot of these, then you may want to split them up into categories like NSNumber+Random. Doing it with Categories makes it transparently part of the existing object model, though, rather than creating classes whose only purpose is to work on other objects.

Rob Napier
+1  A: 

When it comes to performance of methods vs. functions, Mike Ash has some great numbers in his post "Performance Comparisons of Common Operations". Objective-C message send operations are extremely fast, so much so that you'd have to have a really tight computational loop to even see the difference. I think that using functions vs. methods in your approach will come down to the stylistic design issues that others have described.

Brad Larson
A: 

Optimise the system, not the function calls.

Implement what is easiest to understand and then when the whole system works, profile it and speed up what's slow. I doubt very much that the objective-c runtime overhead of a static class is going to matter one bit to your whole app.

Roger Nolan