As long as the requirement for a block is yours as opposed to system.
Like I said, there are several approaches. The function pointers require the least boilerplate, but they need an extra argument to pass the context from the caller (the self
stuff in your case). Functors and pointer-to-members typically require template machinery to work, let's not go there. So with a function pointer, here's how it would go:
//Let's define a callback datatype
typedef void (*ResourceLoadObjFuncPtr)(void *, void*);
//argument 1 is ptr to ResourceLoadDescriptor, argument 2 is iconSlot, whatever it is
//Function that implements that type:
void MyLoad(void *img, void *iconSlot)
{
UIImage* img2 = (UIImage*)img;
UIImageView* iv = [[UIImageView alloc] initWithImage:img2];
iv.backgroundColor = [UIColor clearColor];
[(TheTypeOfIconslot*)iconSlot addSubview:iv];
iconLoaded(iv);
[iv release];
}
And you'd have to modify the prototype of queueLoadImageWithBlock
to accept a ResourceLoadObjFuncPtr
parameter instead of ResourceLoadObjCBlockCB
, and another parameter for the context (just the iconSlot
in our case).
And invoke:
[[GameViewController getInstance] getResourceLoadMediator]->
queueLoadImageWithFunction([self.url UTF8String], MyLoad, self.iconSlot);
Blocks are closures - they capture the variables of the function where they're declared. C++ provides no closures that GCC on iOS supports (other than, well, blocks). So you'd have to pass the variables from the function scope to the function parameter by hand. In our case, if my assumptions are right, there's just one variable; in a more complex case, you'd have to wrap them in a structure and pass a pointer to one.
An alternative to that would be using an abstract base class and a concrete implementation that captures the context via its constructor. This would go like this:
//Callback type
class ResourceLoader
{
public:
virtual void Load(void *) = 0;
};
//A callback implementation - not a function, but a class
class MyResourceLoader : public ResourceLoader
{
IconSlotType *iconSlot;
void Load(void *img)
{
//Same loader stuff as above
}
public:
MyResourceLoader(IconSlotType *isl)
:iconSlot(isl)
{}
};
The queueLoadImageWithBlock
equivalent would now take a second parameter of type ResourceLoader*
and no third parameter. As for the invokation, there's the issue of callback object lifetime. Is queueLoadImageWithBlock
asynchronous - that is, does it return before invoking the callback? If so, then a local instance of MyResourceLoader won't do, you'd have to create one dynamically and somehow dispose it. Assuming it's synchronous (i. e. does not invoke the callback after it returns):
MyResourceLoader ResLoader(self.iconSlot);
[[GameViewController getInstance] getResourceLoadMediator]->
queueLoadImageWithLoader([self.url UTF8String], &ResLoader);
If it's not:
[[GameViewController getInstance] getResourceLoadMediator]->
queueLoadImageWithLoader([self.url UTF8String], new MyResourceLoader(self.iconSlot));