Showing posts with label Programming. Show all posts
Showing posts with label Programming. Show all posts

Sunday, July 27, 2014

Demystifying bridged cast in Objective-C

Recently as I was developing my 2D game engine on iOS, there was a need to use STL as I didn't really want to reinvent the wheel in Objective-C, especially since it's going to be phased out by Apple in favor of Swift. Inevitably I had to do some sort of casting between both worlds. The best description I came across was this one : Here , which is quite close but not very comprehensive. Now, if you don't believe me, test your knowledge by answering the questions
    id obj = [[NSObject alloc] init];
    CFTypeRef ref = (__bridge_retained CFTypeRef) obj;
    NSLog(@"CF Retain Count %ld", CFGetRetainCount(ref)); //Q1
    CFRetain(ref);
    id obj2 = (__bridge_transfer id)ref;
    ref = (__bridge_retained CFTypeRef)obj2;
    NSLog(@"CF Retain Count %ld", CFGetRetainCount(ref)); //Q2
    id obj3 = obj;
    NSLog(@"CF Retain Count %ld", CFGetRetainCount(ref)); //Q3
    id obj4 = (__bridge id)ref;
    NSLog(@"CF Retain Count %ld", CFGetRetainCount(ref)); //Q4
    //Q5 : How many CFRelease/CFBridgingRelease do we need here to release the object when it goes out of scope?
If you can't answer those, my hint is, there is indeed only 1 reference count in ObjC, whether you use the bridged cast or not.
See the cheat sheet below:
__bridge_retained = CFBridgingRetain = CFRetain + casting
__bridge_transfer = CFBridgingRelease = CFRelease + casting
__bridge : Does nothing other than casting

Saturday, March 12, 2011

Handwriting Recognition API

A while ago I was thinking of an iOS project that would utilize handwriting recognition elegantly, and thus better interacts with the user just like Professor Layton series. Then as I looked for robust algorithms that tackle this particular problem I came across this awesome open source library called Zinnia, which not only makes good use of SVM but also provides some ready-to-use training sets including Japanese. Using the library is as straightforward as follows:
recognizer = zinnia.Recognizer()
recognizer.open("C:\Python26\handwriting-ja.model")
character = zinnia.Character()
character.clear()
character.set_width(self.width)
character.set_height(self.height)
counter = 0
for curve in self.curves:
   for x, y in curve:
      character.add(counter, x, y)
   counter+=1
result = recognizer.classify(character, 10)
print unicode(result.value(0), "utf-8")
Where recognizer.open() opens the training module to compare the user mouse strokes against. Then we use set_width(), set_height() to set the canvas size, add() to add the mouse strokes as (x,y) positions. Finally we can pass the character along with the desired number of potential matches to classify(), and print out the most possible UTF-8 string with result.value(0).

Tuesday, February 15, 2011

Break the Language Barrier Series - Chapter Java

Recently I was asked to do some work on JNI for Java programmers to have low-level access
to the underlying systems, such as Win32 API and Cocoa Framework.
Then I ran into some interesting technologies called JNA and JInvoke, both of which claim to provide dll import for Java. However, on the official website of JInvoke they claim to be 10X faster than JNA. According to them, it compares to the performance of JNI, and even native C code's LoadLibrary from Win32 API.
Since I've been so curious about their statement, I decided to run a benchmark on all 3 approaches. To achieve this, we would create a very simple function that takes 5 input parameters and returns a sum of 5 numbers. The reason behind this is that the performance is only measurable from invoking the function and observing its overhead. So now let's take a look at all 3 implementations:

1. JNA
package com.talent;
import com.sun.jna.Library;
import com.sun.jna.Native;
public class MyJNA {
 public static int nLoops = 5000000;
 public interface CLibrary extends Library{
  int fnSpeedtest(int a, int b, int c, int d, int e);
 }
 public static void main(String[] args)
 {
  CLibrary clib = (CLibrary) Native.loadLibrary("C:/jni/Speedtest.dll", CLibrary.class);
  long startTime = System.currentTimeMillis();
  for(int i = 0 ; i < nLoops; i ++)
  {
   int sum = clib.fnSpeedtest(1, 2, 3, 4, 5);
  }
  long timeElapsed = System.currentTimeMillis() - startTime;
  System.out.println(nLoops + " Loops took JNA " + timeElapsed + " milliseconds to complete.");
 }
}
2. JInvoke
package com.talent;
import com.jinvoke.CallingConvention;
import com.jinvoke.JInvoke;
import com.jinvoke.NativeImport;
public class MyJInvoke {
 public static int nLoops = 5000000;
 @NativeImport(library="C:/jni/Speedtest.dll", convention=CallingConvention.CDECL)
 public static native int fnSpeedtest(int a, int b, int c, int d, int e);
 public static void main(String[] args)
 {
  JInvoke.initialize();
  long startTime = System.currentTimeMillis();
  for(int i = 0 ; i < nLoops; i ++)
  {
   int sum = fnSpeedtest(1,2,3,4,5);
  }
  long timeElapsed = System.currentTimeMillis() - startTime;
  System.out.println(nLoops + " Loops took JInvoke " + timeElapsed + " milliseconds to complete.");
 }
}

3. JNI
package com.talent;
import java.io.*;

class SpeedtestJNI{
 public static int nLoops = 5000000;
 static {
  try{
   System.loadLibrary("Speedtest");
                }
                catch(UnsatisfiedLinkError e){       
                 System.out.println(e.getMessage());
                 e.printStackTrace();   
                }
        }
        public static native int fnSpeedtest(int a, int b, int c, int d, int e);
        
        public static void main(String s[]){
         long startTime = System.currentTimeMillis();
         for(int i = 0 ; i < nLoops; i++)
         {
          int sum = fnSpeedtest(1,2,3,4,5);
         }
         long timeElapsed = System.currentTimeMillis() - startTime;
  System.out.println(nLoops + " Loops took JNI " + timeElapsed + " milliseconds to complete.");
        }
}

Finally the chart that compares the 3 of them:

5000000 Loops took JNA 43656 milliseconds to complete.
5000000 Loops took JInvoke 5615 milliseconds to complete.
5000000 Loops took JNI 297 milliseconds to complete.

I don't understand the nature of this performance discrepancy, but it still holds true that JInvoke is about 8 times faster than JNA. Although it's nowhere comparable to JNI, let alone pure C code. Interested readers can get the dll file here.
In the following weeks(hopefully) I will also explore the differences between C++ Interop, PInvoke, and COM Interop, when it comes to .NET calling C libraries.

Thursday, January 13, 2011

I'm Not Very "Objective"

Some time ago I was asked to implement a javascript interpreter for iOS,
 so some people could write javascript instead of Objective-C if they are
afraid of learning a new language. Of course we could build from ground
up with a parser generator such as Antlr, which I found to be very fascinating.
However given the deadline of a couple of weeks this is a little too challenging,
 thus I had been googling for a quick solution like crazy. Well, there were
indeed some open source libraries like SpiderMonkey, JSCocoa and JavascriptCore,
which I tried to port to iOS but I wasn't very successful in the end. Just as I was
about to throw in the white towel I came to a site which explained how
one can just expose the hidden JavascriptCore framework from Apple and use
them! The steps one has to take is roughly:
1. Include "dlfcn.h", which defines the dynamic library loading functions.
2. Since the libraries are loaded by default, we can simply use dlsym to get
    a pointer to the function of interest, like below:
    _JSEvaluateScript = dlsym(RTLD_DEFAULT, "JSEvaluateScript");

3. Include JSBase.h, JSContextRef.h, JSObjectRef.h, JSStringRef.h, JSStringRefCF.h, JSValueRef.h in the project.
And here is the video which shows the results from user input, function 1 and function 2: