Archive

Archive for the ‘Tutorials’ Category

How to write a generic delegate class with C++ and Templates. (Tutorial)

Delegate Tutorial C++

Good morning, it is a cold but beautiful Saturday right now in Amsterdam and I decided to write a new tutorial for my blog. This time not about Objective C but about the world’s sexiest things after microchips: C++, templates and function pointers to methods.
During the last week I was improving code in my game engine and while implementing a messaging system for my objects I stumbled over the problem that function pointers are actually great but don’t work fine with class methods.
C++11 has this great template std::function which I adore and that can handle class methods with std::bind as well. But in my situation it was not suitable and so I had to think of my own solution.

The problem:
The problem I had to solve was to implement an EventHandler system which can take any arbitrary function or class method. In ActionScript, the coder can call the method stage.addEventListener (MOUSE_EVENT.click, …) to add listeners to certain objects which will than receive events, like in this case mouse clicks. I adored the idea behind it and wanted to implement something like this as well.

REResponder -> Callback to Class Methods:
Our function will have to overloads. One will take a lambda function and the other one will take a class method which gets called when it receives an event. The lambda overload will take a std::function argument while the class method overload will take our own class. In this tutorial I will only write about the Responder method as the lambda method is actually pretty easy to implement.

So let’s see what we have:

typedef void* id;			// thanks to apple for that typedef

template <class T>
class RESelector: {
public:
     RESelector(T* _target, void (T::*_func)(id, RE_MSG_CODE), id _msgObj,  RE_MSG_CATEGORY _category){
         this->target = _target;
         this->category = _category;
         this->msgObj = _msgObj;
         this->actionFunc = _func;
    };

    void fire (RE_MSG_CODE code){
         (this->target->*actionFunc)(this->msgObj, code);
    };

    Inline RE_MSG_CATEGORY getCategory() const {
         return this->category;
    }

private:
    T* target;
    id msgObj;
    RE_MSG_CATEGORY category;
    void (T::*actionFunc)(id, RE_MSG_CODE);
};

typedef std::vector<id> SelectorCache;
typedef std::vector<RE_MSG_CODE> Messages;

class REMessageHandler {
    private:
	Messages *msgCache;
	SelectorCache *selectorCache;
	public:
	template<class T>
	void addEventListener(REResponder<T> *responder) {
	    selectorCache->push_back((id)responder);
        };

        Inline void postEvent(RE_MSG_CODE code){
            this->msgCache->push_back(code);
        };
	void evaluateMessages();
};

First of all, don’t worry about RE_MSG_CODE and RE_MSG_CATEGORY. It is just my way of decoding messages but doesn’t actually influence how the code works. RE_MSG_CODE is actually the code itself like KEY_A or MOUSE_LEFT while RE_MSG_CATEGORY is the category the object has to listen to like RE_MSG_CATEGORY_TOUCH or RE_MSG_CATEGORY_RUNLOOP.

So what is happening here? We have a template class called RESelector which consists of not much but 2 methods and a constructor.
The field variables are a pointer to a target which is the template type. An enum category which is the category the object will listen to, a pointer to a member method from a class of T and an id (or void*) to an object which gets send with the message.
Than we have a std::vector that takes id’s and finally the class REMessageHandler. This class is by no means complete but it will do the job for this tutorial.
We have 2 pointers to vectors in this class. One takes MSG_CODES while the other one is id vector. You will ask, why do we store raw pointers in a vector that should store objects from RESelector? Well, we only need the addresses stored  and because what we will store is actually a template class, we are not able to do: std::vector . We would have to define a std::vector FOR EACH template and this would suck.
The two corresponding messages are straightforward. Both push back stuff on the right vector.
Let’s move on to the most interesting method of this class.
Receiving Messages

void REMessageHandler::evaluateMessages() {
    for (auto it = this->selectorCache->begin(); it != this->selectorCache->end(); ++it){
	RESelector<__tPlaceholder> *selector = (RESelector<__tPlaceholder>*)*it;
	If (selector->getCategory() & RE_MSG_CATEGORY_INPUT) {
            for (auto sec_it = this->msgCache->begin(); sec_it != this->msgCache->end(); ++sec_it) {
	        if (*set_it & RE_MSG_CATEGORY_INPUT) {
		     RE_MSG_CODE code = (RE_MSG_CODE) ((*sec_it) & (~RE_MSG_CATEGORY_INPUT));
		     selector->fire (code);
                }
            }
         …..
    }	
    this->msgCache->clear();
}

Wow.. Looks kinda weird right? I try to explain. We first iterate through the selectorCache which contains all the objects which are registered to listen for events.
As the selectorCache stores only addresses, we need to cast the object to the right type. RESelector is a template class so can’t create a pointer without a type. Of course we want it as generic as possible, so making the method itself a template message is absolutely no option. I came up with the idea to define a struct __tPlaceholder which is just empty. The typedef looks like this

typedef struct __tPlaceholder {} __tPlaceholder

and it’s only purpose is to act as a placeholder. So we create a pointer to an RESelector of type placeholder and assign the value of the iterator to it. Nice!
The next step to check is to what category the selector is listening to. In this example I only implemented RE_MSG_CATEGORY Input so we check if it does and if yes we iterate through all the messages. For each message we check if it is a message for the input category and if yes we fire.
For completeness, this is how a message gets encoded and decoded:

RE_MSG_CODE encoded=(RE_MSG_CODE)(category|code);
#define RE_MSG_INPUT_CODE(__X__) ((__X__)&(~RE_MSG_CATEGORY_INPUT))

With this bunch of code we can now easily make stuff like this


class Foo {
	void mouseCallback(id obj, RE_MSG_CODE msg) {

	     dbgPrint(“I received msg %x from %p”, msg, obj); 
             switch(RE_MSG_INPUT_CODE(msg)){
                 case RE_MSG_MOUSE_INPUT_KEY_UP: {
                     // do s.th.
                     break;
                 }
                 default: break;
             }
        };
}

void Runloop::Init(){
	Foo *foo = new Foo();
        RESelector<Foo> selector = new RESelector<Foo>(foo, &Foo::mouseCallback, this, RE_MSG_CATEGORY_INPUT);
        REMessageHandler::SharedMessageHandler().addEventListener(selector);
}

bool Runloop::Run() {
	REMessageHandler::SharedMessageHandler().evaluateMessages();
        return this->goOn();
}

And every time somewhere gets a input message posted the mouseCallback function in Foo gets called.

Cool? Isn’t it? There are still areas to improve of course but I will leave this to you to figure out what the best approach for your problem is.

Well. That was a huge tutorial and I hope I did an ok job. If you like it I would appreciate a small comment or s.th. 

Greetings
Markus

Adding Swiping to UIWebView using JavaScript (iOS4/iOS5) and custom URL scheme

December 25, 2011 2 comments

Hey folks, welcome to my new Tutorial, which will cover the topic of how to implement swiping in a UIWebView using JavaScript and will explain how to send variables back to our UIWebView using Custom URL Schemes.

The code itself is straightforward but will cover a lot of cool things.

To load the JavaScript code we call in our webViewHasFinishedLoading Delegate method the following code:


#define DEVICE_IOS5()   (([[[UIDevice currentDevice] systemVersion] floatValue]>=5.0))

if (DEVICE_IOS5()){

     [self.webView stringByEvaluatingJavaScriptFromString:@"loadListenerIOS5()"];

} else {

     [self.webView stringByEvaluatingJavaScriptFromString:@"loadListenerIOS4()"];

}

This is the JavaScript code:

File: SwipeEvent.js

Use your local html to let the browser know about it. I showed how to do that in my last tutorial.

         EDIT: One more thing. When copying JavaScript files from the Finder to XCode, it will not treat it as an added resource but as a file to compile. Of course that is not possible so it will give you warnings back and the file will not be copied to the resource folder on your device / simulator. To fix that problem, go to target->build settings and than drag and drop the file from Compile Sources to Copy Bundle Resources.


var startX;

var startY;

var diffX;

var diffY;

var hypo;

var isIOS5;

function loadListenerIOS4(){

    var body = document.getElementsByTagName("body")[0];

    body.addEventListener("touchstart", touchStart, false);

    body.addEventListener("touchend", touchEnd, false);

    body.addEventListener("touchmove", touchMove, false);

    isIOS5=0;

    return "JS Listener iOS4 loaded";

}

function loadListenerIOS5(){

    var body = document.getElementsByTagName("body")[0];

    body.addEventListener("touchstart", touchStart, false);

    body.addEventListener("touchend", touchEnd, false);

    body.addEventListener("touchmove", touchMove, false);

    isIOS5=1;

    return "JS Listener iOS5 loaded";

}

function fireSwipeScheme(a,b,c){

    var scheme="swipe:" + a + ":" + b + ":" + c;

    document.location=scheme;

}

function touchStart(event){

    diffX=0;

    diffY=0;

    if (isIOS5){

        startX=event.pageX;

        startY=event.pageY;

    } else {

        startX=event.touches[0].pageX;

        startY=event.touches[0].pageY;

    }

}

function touchEnd(event){

    if (diffX>50||diffX<-50){

        fireSwipeScheme(diffX,diffY,hypo);

    }

}

function touchMove(event) {

    var a;

    var b;

    if (isIOS5){

        a = event.pageX - startX;

        b = event.pageY - startY;

    } else {

        a = event.touches[0].pageX - startX;

        b = event.touches[0].pageY - startY;

    }

    var c = calcHypotenuse(a,b);

    diffX=a;

    diffY=b;

    hypo=c;

}

function calcHypotenuse(a,b){

    return Math.sqrt(a*a,b*b);

}

LoadListenerIOS4 and LoadListeneriOS5 are there to attach an event listener to the body object of our DOM. The first is a constant which can be either “touchstart”, “touchend”, “touchmove” or “touchcancel” and the second determines the function we are about to call. So in this case, “touchstart” calls touchStart( … ).

Both loaders are the same, only that one sets the variable isIOS5 to 1 and the other sets it to 0. This is important if you look into the touchStart function.

On iOS5, to get the current x/y coordinates of a touch, some must call event.pageX and event.pageY, while on iOS4, its event.touches[0].pageX and event.touches[0].pageY.

The same goes for all the other touch function.

So what we do here is, we register the touch coordinates on touch start, calculate all the way through touchmove the current distance and fire immediately an url scheme to the UIWebView if the touches ended.

fireSwipeScheme is also pretty interesting.

The variable “scheme” is a combination about the keyword “swipe” and a, b, c which are actually the variables diff x, diff y and the hypotenuse.

So, how do we now get these variables into our objective C Code?

In the delegate method webViewShouldStartLoadOnRequest: withNavigationType:  we add the following code

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType{

    NSString*scheme=[[request URL]absoluteString];

    //NSLog(@"received scheme: %@", scheme);

    NSArray *components=[scheme componentsSeparatedByString:@":"];

    if ([[components objectAtIndex:0]isEqualToString:@"swipe"]){
        [self handleSwipeInWebView:components];
        return NO;
     }

     return YES;

}

And to our class we add the following method:


#define kMinSwipeDistanceHorizontalInWebView 100.0f

#define kMaxSwipeDistanceVerticalInWebView 50.0f

-(void)handleSwipeInWebView: (NSArray*)code{

    @autoreleasepool {

        NSInteger swipeDistX=[[NSNumber numberFromString:]intValue];

        NSInteger swipeDistY=abs([[NSNumber numberFromString:]intValue]);

        NSLog(@"swipeDistY: %d", swipeDistY);

        NSLog(@"swipeDistX: %d", swipeDistX);

        if ((swipeDistX>kMinSwipeDistanceHorizontalInWebView||swipeDistX<-kMinSwipeDistanceHorizontalInWebView)&&swipeDistY>kMaxSwipeDistanceVerticalInWebView){

            MasterViewController*ptr=(MasterViewController*)self.masterViewController;

            if (ptr){

                 if (swipeDistX<-kMinSwipeDistanceHorizontalInWebView){

                     [ptr moveDownInTreeHierarchy];

                 } else if (swipeDistX&gt;kMinSwipeDistanceHorizontalInWebView){

                     [ptr moveUpInTreeHierarchy];

                 }

           }

     }

}

In the delegate method, the UIWebView catches all clicked links events or all document.location events from JavaScript. By sending a custom URL script we can first return NO, to make sure that no new page will get loaded and we can use it actually as an encoder for our variables. The url scheme in this example looks something like this

 

Swipe:-40:30:-50.

In the delegate method, I break the array into components by separating them by the ASCII character ‘:’. In the handleSwipeInWebView method, I can easily use the components than to let my code do what I want him to do.

In my case, I am firing the swipe Event from the DetailViewController in my SplitViewController and notify the MasterViewController about it.

 

UIWebView – Calling Javascript from iOS with passing parameters … Tutorial

Right now I am working on a project for my company which has to display a lot of content, that is delivered in the XML format and consists of small chunks of HTML formatted text-code.

The only way on iOS to display HTML is to use the UIWebView and so I had to write some small Javascript code which can be called to display the content. It has to be dynamic, as the content is sorted by chapters and the user can navigate through a tree structure to display only relevant content.

So what I did was, parsing the XML and than writing everything into Core Data (btw. Core Data is AWSOME!… the speed, the usability.. incredible). With Core Data I do the sorting and when the user opens content, I load my local HTML, which does actually nothing but tell the browser where the .JS files are.

The reason why I write this tutorial is because I couldn’t find a good one on the web that covers that topic which my requirements (.JS files, parameter passing from Objective C to JS)

Btw: this is not finished code , it works but is rough to get the basic system to work.

<html>

<head>

<meta http-equiv=“content-type”content=“text/html;charset=utf-8” />

<title>DisplayContent</title>

<style>

</– th, td { vertical-align: top; } –>

</style>

<script src=“displayContent.js”></script>

</head>

<body>

</body>

</html>

The JS File looks like this:

function textNodeWithColorAndSize(text, rgb, size, font){

    var textNode=document.createTextNode(text);

    var font=document.createElement(“font”);

    font.style.color=rgb;

    font.style.fontSize=size;

    font.appendChild(textNode);

    return font;

}

function printHeadOfTable(code, headline) {

    var body = document.getElementsByTagName(“body”)[0];

    var table     = document.createElement(“table”);

    var tableBody = document.createElement(“tbody”);

    var row = document.createElement(“tr”);

    for (var i = 0; i < 3; i++) {

        var cell = document.createElement(“td”);

        var cellText;

        if (i==0){

            cell.width=40;

            cellText=textNodeWithColorAndSize(code, “#FF3344”, “12px”, “font”);

        } else if (i==1) {

            cellText=textNodeWithColorAndSize(headline, “#000000”, “18px”, “font”);

        } else {

            cellText=textNodeWithColorAndSize(“[E-Mail Button]”, “#555555”, “12px”, “font”);

        }

        cell.appendChild(cellText);

        row.appendChild(cell);

    }

    tableBody.appendChild(row);

    table.appendChild(tableBody);

    table.style.marginLeft=20;

    body.appendChild(table);

}

function resize(){

    var frames=document.getElementsByTagName(“div”);

    for (var i=0;i<frames.length;i++){

        frames[i].style.width=“94%”;

    }

}

function printBodyOfTable(bodyString){

    var body = document.getElementsByTagName(“body”)[0];

    var frame=document.createElement(“div”);

    frame.innerHTML=bodyString;

    frame.style.width=“94%”;

    frame.style.marginLeft=20;

    body.appendChild(frame);

}

So, fine enough. Resize does resize all elements <div> to 94% of the web view browser. This is important because of rotation.

printBodyToTable( … ) and printHeadToTable ( … ) are functions to print content.

So, when you load up now the webpage nothing appears of course. Thats why we have to call the JS from our Objective C code. This looks like this:

The array assets is passed from the fetchedResults.

-(void)loadWebViewWithAssets: (NSArray **const)assets{

    [self setWebViewFrame:CURRENT_ORIENTATION()];

    @autoreleasepool {

        _assetArray=[[NSArray alloc]initWithArray:*assets];

        NSURL *file = [NSURLfileURLWithPath:[[NSBundle mainBundle]pathForResource:@”contentView”ofType:@”html”]];

        NSURLRequest *urlRequest=[[NSURLRequest alloc]initWithURL:file];

        [self.webView loadRequest:urlRequest];

        [urlRequest release];

    }

}

So this loads our basic html. Now when the webView is done loading, we are free to call our Javascript functions.

I think it is a bit a pity, that the JS Script methods ONLY work AFTER the web view finished its loading. It would be cool to do that beforehand but well.. lives a b**** sometimes 🙂

Code:

(Asset and Content are Core Data entities.)

The abort calls are there for debugging purposes.

-(void)webViewDidFinishLoad:(UIWebView *)webView{

     for (int i=0;i<[_assetArray count];i++){

         Asset*asset=[_assetArray objectAtIndex:i];

         Content*content=asset.content;

         if (!content){

             dbgAbort();

         }

         NSString *jsPrintHeadOfTable=[[NSString alloc]initWithFormat:@”printHeadOfTable(\”%@\”, \”%@\”)”, asset.at_code, asset.at_title];

         NSString *jsPrintBodyOfTable=[[NSString alloc]initWithFormat:@”printBodyOfTable((\”%@\”))”, content.at_content];

         if (!jsPrintBodyOfTable){

             dbgAbort();

         }

         [self.webView stringByEvaluatingJavaScriptFromString:jsPrintHeadOfTable];

         [self.webView stringByEvaluatingJavaScriptFromString:jsPrintBodyOfTable];

         [jsPrintHeadOfTable release];

         [jsPrintBodyOfTable release];

     }

     [_assetArray release];

}

So, you see, we are even able to pass parameters to our Javascript which is incredible awesome. The same webView method is able as well to retrieve values from the javascript by capturing the NSString return value. But there a lot of tutorials out there for this.

Ah yeah, and is very important that you prepare your parameters. content.at_content for example is a complete HTML formatted text. Before you pass it you have to make sure that there are no _ ” _ characters in it (replace them with _ ‘ _  . Now newline characters, no carriage return etc.. Just to tell you 🙂 Took me some while to get the idea. 😉

From this point on we can now call the stringByEvaluatingJavaScriptFromString method wherever and whenever we like.. Cool huh?

Yeah, this was my first tutorial and I hope it helped ..

Greetings

Markus