Archive

Archive for May, 2012

Simple GCD Timer (RNTimer)

May 29th, 2012 8 comments

I know this exists out there somewhere already, but I couldn’t find it anywhere and I was sick of writing it over and over again…. If someone knows of previous art, please point me in the right direction. I know Fiery Robot’s and Mike Ash’s, but they solve different problems.

Have you ever noticed how hard it is to write a repeating NSTimer that doesn’t create a retain loop? Almost always you wind up with something like this:

[NSTimer scheduledTimerWithTimeInterval:1
                                 target:self
                               selector:@selector(something)
                               userInfo:nil 
                                repeats:YES];

Seems easy enough, except it’s a retain loop. Mike Ash does a nice job of explaining it and walking you through the hoops you need to avoid it. For such a common thing, you’d think this would be easy. And it should be, so I fixed it. I just still can’t quite believe I’m the first to do so.

Anyway, for your consideration I present a very simple class called RNTimer. Right now it just handles the most common case: a repeating timer that does not generate a retain loop and automatically invalidates when it is released. It could of course be expanded to handle more NSTimer functionality if there is interest. Let me know if you have a use case that the current implementation doesn’t address.

You may find it along with further information at GitHub.

Categories: cocoa, iphone Tags:

Wrapping C++ Final Edition

May 12th, 2012 15 comments

I have always strong recommended segregating Objective-C and C++ code with a thin Objective-C++ wrapper. I do not like Objective-C++. It is useful for what it does, but it is a mess of a “language.” It has many downsides, for slower compiles and poor debugging facilities, to confusing code and inefficient ARC code. .mm is a blight on your code. Never let it spread.

That said, Objective-C++ is invaluable for integrating C++ into Objective-C. And while I am not a great lover of C++, it is a very useful language and there is a great deal of excellent code written in it that is well-worth reusing in your Cocoa projects. Many of Apple’s frameworks are implemented in C++.

So my recommendation for those who have existing C++ logic code has always been thus: write your UI in pure Objective-C (.m). Write your “middleware” in pure C++ (.cpp). And have a thin Objective-C++ (.mm) wrapper layer to glue them together. Your ObjC++ API should ideally exactly match your C++ API, just converting types (for instance converting std::string to and from NSString).

(As a side note, I also recommend that OS-related things like file management, network management, and threading all be handled natively. GCD is much better than pthreads. NSURLConnection is much better than writing your own C++ networking layer in BSD sockets. But this is tangental to the main point.)

Saying all that, how do you wrap a C++ object so that Objective-C can read it? This used to be a question that required some significant thought. See Wrapping C++, Take 2 Part 1 and Part 2 for my previous thinking on the subject.

Improvements in Objective-C have made all of the previous hoop-jumping irrelevant. The problem all my previous solutions was trying to solve was that you had to declare ivars in the header. Your ivar was a C++ class (which might be in a namespace or might be a template), and that made it difficult to declare in the header without forcing all the importers to be ObjC++. So to solve this generally you needed opaque types, or at the very least forward declared structs, etc. And it was all a big pain.

But that’s over. You can now declare all your ivars in the implementation file. So everything’s easy. Your wrapper class can have C++ ivars without having any impact on users of the wrapper class.

Consider a simple C++ class (but throwing in the headache of a namespace):

namespace MY {
class Cpp {
  public:
    std::string getName() { return _name; };
    void setName(std::string aName) { _name = aName; };
  private:
    std::string _name;
};
}

The wrapper for this is trivial:

@interface CPPWrapper : NSObject
@property (nonatomic, readwrite, copy) NSString *name;
@end

@interface CPPWrapper ()
@property (nonatomic, readwrite, assign) MY::Cpp *cpp;
@end

@implementation CPPWrapper
@synthesize cpp = _cpp;

- (id)init {
  self = [super init];
  if (self) {
    _cpp = new MY::Cpp();
  }
  return self;
}

- (void)dealloc {
  delete _cpp;
}

- (NSString *)name {
  return [NSString stringWithUTF8String:self.cpp->getName().c_str()];
}

- (void)setName:(NSString *)aName {
  self.cpp->setName([aName UTF8String]);
}
@end

Couldn’t be easier really. The one headache that really remains in my experience is enums inside of a namespace (or more generally enums declared in a C++ header). The best solution is to use #if __cplusplus blocks to strip away the namespace and still declare the enum in pure C. Do this if at all possible. Otherwise you’ll wind up with an C enum that mirrors the C++ enum. This is a maintenance nightmare, since changes to the C++ enum will often be missed in the ObjC enum, and you’ll get very difficult-to-debug errors with enum mismatches.

Just to ask and answer a possible question: why *Cpp and not just Cpp? The reason is that in almost all cases the C++ object will be created outside of your wrappers. So in almost all cases, there’s going to be a method like initWithCpp:(Cpp *)cpp. How does that work? Easy, wrap it in #if __cplusplus:

#if __cplusplus
#include "Cpp.h"
...
- (CppWrapper *)initWithCpp:(Cpp *)cpp;
#endif

Anyway, most of my research into opaque types and generally how to manage C++ wrappers has now become trivial. I’m just giving one more post to let you all know that. (And because Orpheus asked.) Post comments if there are more questions.

Categories: cocoa Tags: