Migrating to iCloud

To be honest, I maintained my apps data in iOS in SqlLite. The rationale I thought was obvious, that I wanted to have a common database across all three mobile platforms. But, the attraction of iCloud made me use CoreData. And iCloud IS attractive. As long as a user is a melophile (that’s someone who’s turned on by Apple, and in this case probably has an iPhone, iPad and Mac), iCloud is hugely attractive. An application’s data across all devices is shared. As far as I can tell, there’s no ability to share data between users, but that’s a different story.

And CoreData with iCloud is easy. I won’t bore you with the details, but I’ve converted one app which was pure SqlLite, and am now converting another which keeps sound an image files over. Actually, maintaing SqlLite is easier then handling image documents. I find the UIDocument class a little clumsy/untidy but it does the job. In my case, I’ve created a guid string in the table and am copying the string into a file whose filename is the guid.

The code to do that looks something like this.

@implementation SoundDocument

-(id) initWithFileName:(NSString *)fileName
{
    keyFileName = [fileName retain];
    NSURL *ubiq = [[NSFileManager defaultManager]
                   URLForUbiquityContainerIdentifier:UBIQUITY_CONTAINER_URL];

    NSFileManager *fileManager = [NSFileManager defaultManager];
    NSURL *folderURL = [ubiq URLByAppendingPathComponent: @"Sounds"];
    if ([fileManager fileExistsAtPath:[folderURL path]] == NO)
        [fileManager createDirectoryAtURL:folderURL
              withIntermediateDirectories:YES
                               attributes:nil
                                    error:nil];
    
    ubiquityURL  = [folderURL URLByAppendingPathComponent:keyFileName];
    self = [super initWithFileURL:ubiquityURL];
    return self;
}

- (BOOL)loadFromContents:(id)contents ofType:(NSString *)typeName error:(NSError **)outError
{
    data = contents;
    [[NSNotificationCenter defaultCenter] postNotificationName:@"SoundLoaded" object:self];
    return YES;
}

-(NSData *)contents
{
    return data;
}

-(id)contentsForType:(NSString *)typeName
               error:(NSError *__autoreleasing *)outError
{
    return data;
}

-(void) saveDocument:(NSData *)savedata
{
    data = [savedata retain];
    [self saveToURL:ubiquityURL
        forSaveOperation:UIDocumentSaveForCreating
        completionHandler:^(BOOL success) {
         if (success) {
             [self openWithCompletionHandler:^(BOOL success) {
                 NSLog(@"new document opened from iCloud");
             }];
         }
        else
        {
            NSLog(@"failed to opened new document from iCloud");
        }
 }];
}

- (void)loadData:(NSMetadataQuery *)query
{
    
    if ([query resultCount] == 1)
    {
        NSMetadataItem *item = [query resultAtIndex:0];
        NSURL *url = [item valueForAttribute:NSMetadataItemURLKey];
        data = [[NSData alloc] initWithContentsOfURL:url];
        [self openWithCompletionHandler:^(BOOL success) {
            if (success) {
                NSLog(@"iCloud document opened");
            } else {
                NSLog(@"failed opening document from iCloud");
            }
        }];
	}
}

- (void)queryDidFinishGathering:(NSNotification *)notification {
    
    NSMetadataQuery *query = [notification object];
    [query disableUpdates];
    [query stopQuery];
    
    [[NSNotificationCenter defaultCenter] removeObserver:self name:NSMetadataQueryDidFinishGatheringNotification object:query];
    
    _query = nil;
    
	[self loadData:query];
    
}

- (void)loadDocument
{
    NSMetadataQuery *query = [[NSMetadataQuery alloc] init];
    _query = query;
    [query setSearchScopes:[NSArray arrayWithObject:
                            NSMetadataQueryUbiquitousDocumentsScope]];
    
    NSPredicate *pred = [NSPredicate predicateWithFormat:
                         @"%K == %@", NSMetadataItemFSNameKey, keyFileName];
    [query setPredicate:pred];
    
    [[NSNotificationCenter defaultCenter]
     addObserver:self
     selector:@selector(queryDidFinishGathering:)
     name:NSMetadataQueryDidFinishGatheringNotification
     object:query];
    
    [query startQuery];
}


@end

Posted in Uncategorized | Leave a comment

Managing data in Android

This is really a note to self for when I need to write this code in a hurry.

First create a class which extends, SqlLiteHelper like so. This code assumes that we have a database in the package that we want to extend.

public class LeitnerOpenHelper extends SQLiteOpenHelper {
    LeitnerOpenHelper(Context context) 
    {
        super(context, DATABASE_NAME, null, DATABASE_VERSION);

        // checking database and open it if exists 
        java.io.File databaseFile = context.getDatabasePath(DATABASE_NAME);
        if(  ! databaseFile.exists() )
        {
	        try 
	        {
	            this.getReadableDatabase();
	            copyDatabase(context);
	
	        } catch (java.io.IOException e) 
	        {
	            throw new Error("Error copying database");
	        }
        }
    }

    private void copyDatabase(Context context) throws java.io.IOException 
    {
        java.io.InputStream myInput = context.getAssets().open(ASSET_NAME);

        java.io.File databaseFile = context.getDatabasePath(DATABASE_NAME);        
        java.io.OutputStream myOutput;
        try {
        	databaseFile.createNewFile();
        	myOutput = new java.io.FileOutputStream(databaseFile);

	        byte[] buffer = new byte[1024];
	        int length;
	        while ((length = myInput.read(buffer)) > 0) {
	            myOutput.write(buffer, 0, length);
	        }
	
	        myOutput.flush();
	        myOutput.close();
	        myInput.close();
        }
        catch (Exception e)
        {
        	Log.v("copyDatabase",e.getMessage());
        }
    }
}


Now you need to set up a cursor, and reading and writing for each table.  This sets up a cursor for each a table called statistic.

    public void writeStatistic( Statistic statistic )
    {
		ContentValues map = new ContentValues();
		map.put( "count", statistic.getCount() );
		if( statistic.getDate() != null )
		{
			DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
			String date = dateFormat.format(statistic.getDate());
			map.put( "date", date ); 
		}
		else
			map.put( "date", "NULL");
		if( statistic.getDictionary() != null )
			map.put( "dictionaryid", statistic.getDictionary().key );
		else
			map.put( "dictionaryid", 0 );
		
    	if( statistic.key == 0 )
    	{
    		statistic.key = getWritableDatabase().insert(STATISTICS_TABLE, null, map); 
    	}
    	else
    	{
    		String[] whereArgs = new String[]{Long.toString(statistic.key)};
    		getWritableDatabase().update(STATISTICS_TABLE,map,"id=?",whereArgs);
    	}
    }
    
    public void deleteStatistic( Statistic statistic )
    {
		String[] whereArgs = new String[]{Long.toString(statistic.key)};
		getWritableDatabase().delete(STATISTICS_TABLE,"id=?",whereArgs);    	
    }
    
    public void readStatistics( List statistics, Dictionary dictionary )
    {
    	SQLiteDatabase db = getWritableDatabase();
    	StatisticsCursor cursor = (StatisticsCursor) db.rawQueryWithFactory(new StatisticsCursor.Factory(), StatisticsCursor.QUERY+" WHERE dictionaryid="+dictionary.key, null, null); 	

    	// check whether there's anything in the table and initialise it if there isn't  	
    	
    	statistics.clear();
    	cursor.moveToFirst();
    	while( !cursor.isAfterLast() )
    	{
    		Statistic statistic = new Statistic();
    		statistic.updating = false;
    		statistic.key = cursor.getId();
    		statistic.setCount( cursor.getCounter() );
    		statistic.setDictionary( dictionary );
    		statistic.setDate( cursor.getDate() );
    		statistic.updating = true;
    		statistics.add(statistic);
    		cursor.moveToNext();
    	}
    	cursor.close();
    }
    
    public static class StatisticsCursor extends SQLiteCursor 
    {
    	private static final String QUERY = "SELECT id,date,dictionaryid,count FROM "+STATISTICS_TABLE;
    	
    	private StatisticsCursor( SQLiteDatabase db, SQLiteCursorDriver driver, String editTable, SQLiteQuery query )
    	{
    		super( db, driver, editTable, query );
    	}
    
	    private static class Factory implements SQLiteDatabase.CursorFactory
	    {
	    	public Cursor newCursor( SQLiteDatabase db, SQLiteCursorDriver driver, String editTable, SQLiteQuery query)
	    	{
	    		return new StatisticsCursor( db, driver, editTable, query );
	    	}
	    }
	    
	    public long getId()
	    {
	    	return getLong(0);
	    }
	    
	    public Date getDate()
	    {
	    	Date date = null;
	    	String dateString = getString(1);
	    	if( dateString != null && dateString != "NULL" && dateString != "" )
	    	{
				DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
				try {
					date =  (Date) dateFormat.parse(dateString);
				}
				catch( ParseException exception)
				{
					date = null;
				}
	    	}
	    	return date;
	    }
	    
	    public long getDictionaryId()
	    {
	    	return getLong(2);
	    }
	    
	    public long getCounter()
	    {
	    	return getLong(3);
	    }
    }

Posted in Uncategorized | Leave a comment

Leitner and iOS vs Android vs Windows Phone

I have a human language learning tool for smart phones called Leitner. Right now, I’m using it to help me learn Spanish. I like languages, computer and human languages, so I put it together many moons ago and it’s evolved from a VB app in Microsoft Access, to a C# app using WPF, to a C# in Linux using GTK, and now to iOS, Android and Windows Phone smart phones.

Leitner uses a number of the features like accessing internet files, SQLite, JSON encoding, the audio player, recording, handling the accelerometer, graph drawing, sending and receiving email attachments. So, it’s a good way to evaluate the differences between iOS, Android and Windows Phone, and the differences between Objective-C, Java and C#.

I’m not a huge fan of Objective-C. I guess what I really don’t like is that inbuilt classes like NSMutableArray’s lack of extensibility mean that you forego type-checking. Java and C#’s equivalent is List, which is totally type-checked. But on the other hand, iOS is well thought through and dishes up its goodies with ease. At 5.1 it has all the features I need to put the app together well, which means I can give the app out to people with slightly ealrier versions of the OS. And we all know that Apple fans like to stay up to date. Apple makes navigation easy. What I really like is that data can be easily passed from screen to screen. What I mostly dislike is that you still feel compelled to manually handle memory management. But one of the best things is what you see is what you get when you’re designing a screen.

Java is an improvement over Objective-C, but Android is clumsy and there’s a lack of integration between the View and Controller that Apple and Microsoft are so good at. When it comes to managing navigation, for apps in Android I use a combination of my own back key handling along with the Sherlock Tab Bar to simulate iOS’s navigation. To handle persistent data you firstly set up things in the application activity and then pass data to fragments. Much the same as iOS. Forget trying to pass data between activities. Getting that going was a little tricky, but it seems to work. One thing I really like is the menu key. On the other hand you have to think about multiple size screens and laying them out can be quite tricky. There is a lot to be said for iOS’s 3 screen sizes. It strikes me that Google is new to operating systems and it shows because the UI is undergoing radical changes with each version and because there are so many users out there with older versions it means things get quite involved to give a modern look and feel and still work on older versions of Android.

When it comes to SQLite, Android is by far the best. For both iOS and Android, it’s near native. But Android make using SQLite actually pleasurable by introducing a Cursor class. For me this is important as I use the same database between all three operating systems. Yes, Apple’s NSCoreData is very nice if you’re doing an iOS only app, and one of the things I love about CoreData is that you can keep the data in the cloud and use the same data on the iPad and iPhone versions of your app, and maybe even OSX. Perhaps Microsoft has achieved this with Azure, I’m not sure.

Now to Microsoft, who is not new to operating systems, and I can understand why they went down the SilverLight path when developing Windows Phone 7. The first point though is that on the surface they took the best of both iOS and Android. A single screen size, plus Android’s equivalent of XML called XAML gives you simple yet granular control of the layout. And like iOS you link from the View straight into the Controller unlike in Android where you have to manually create the linkages between them. This is where Microsoft gets things so right.

I also love the way that Microsoft forces programmers on Windows Phone to handle http requests asynchronously. Lambda expressions make this as elegant as can be. While we’re on that note, Android is particulary elegant at background processes. The whole android.os.AsyncTask technique is delightful to use. This is important because slow processes like accessing large database requests can take up a bit of time. And android.os.AsyncTask pre and post execute make it easy to update the UI, whereas in iOS and Windows Phone you have to fudge any calls back to the UI. Microsoft doesn’t make its equivalent Task available until Windows Phone 8.

When it comes to passing data between screens things get a little tricky. I get the feeling that SilverLight is a religion at Microsoft. At least you can keep global data in the App class. Like Android I write my own navigation handler for the back key, but Windows Phone was much less tricky than Android. However, passing data between screens is more tricky due to the whole XAML navigation thing. In simple cases I pass keys to records in the database between screens, and in more complex cases I maintain a stack which contains data for that screen, which is part of my purpose built navigation class. But the thing I found most frustrating so far, is that you can’t handle email attachments until Windows Phone 8. To me it’s a big part of the app. It makes you think that Microsoft were in far too much of a hurry to do the job properly when they dished out Windows Phone 7. The best thing is that C# is such an expressive and beautiful language that when it comes down to straight coding, it’s pure joy. I also love WPF and was hoping for the same experience on Windows Phone. It’s a such shame they handcuffed the OS on Windows Phone 7.

If you’re wondering why there are so many iOS apps out there? While C# is programmer friendly, iOS is developer friendly. End of story. Still I love the look and feel of Windows Phone, it’s the most elegant UI in my humble opinion.

Posted in Uncategorized | Leave a comment

PL1

Gosh, I was reading how C# stores strings some time ago and it’s reminiscent of PL1, or at least Prime’s version PLP. A PLP string was stored with length first followed by the string itself. Strings are immutable in C# and what’s nice about that is that they’re thread safe.

I read someone’s SQLite3 blog the other day about the evils of threading. I wonder how they handle updates from the internet. This little piece of software I wrote collects information in a shop and then when the machine is connected to the internet it uploads the information that it’s been collecting while continuing to collect its information.

I’ve got another app that integrates with Google Contacts. Without threading the user can wait a very long time to refresh all the contacts. Best it happens in the background. Our user has other things to do than wait for a refresh.

I’m thinking that that author doesn’t live in the real world.

Posted in Uncategorized | Leave a comment

Dynamic Types in C# 4.0

Seems like building a bit more reflection into the language to me. I sure could have used it on OpenTrader when I was writing the code to handle scripting. Here’s an example I pinched from Microsoft


static void Main(string[] args)
{
    ExampleClass ec = new ExampleClass();
    // The following call to exampleMethod1 causes a compiler error 
    // if exampleMethod1 has only one parameter. Uncomment the line
    // to see the error.
    //ec.exampleMethod1(10, 4);

    dynamic dynamic_ec = new ExampleClass();
    // The following line is not identified as an error by the
    // compiler, but it causes a run-time exception.
    dynamic_ec.exampleMethod1(10, 4);

    // The following calls also do not cause compiler errors, whether 
    // appropriate methods exist or not.
    dynamic_ec.someMethod("some argument", 7, null);
    dynamic_ec.nonexistentMethod();
}

Cool, eh. Problem is I might have waited for the feature and then Open Trader wouldn’t have got written. How scripting in Open Trader works, is that the user who happens to be writing a script writes a class inheriting from a class provided by the app. I compile the user’s script by calling the built-in compiler. Then I create an instance of the class. The class has a method called Run, which is then called. So many calls. I must say the Type keyword became my friend.

The user uses the same method to create their own data file types. With their own methods for reading data. In this case the code looks through a particular assembly for all classes with a given sub class, then offers them up to the user as a choice of file type. I kinda like it.

In fact it’s such a nice technique, I use it to get properties for in the built Neural Networking and Genetic Algorithms.

That’s why I like dynamic typing. I was thinking the language needed something like that myself. Sorta like id in Objective C.

Posted in Uncategorized | 1 Comment

Frustrations

I had fun yesteray with a small application for a client, developed in Gtk#. It worked perfectly well on the Mac and on Linux, but fell over terribly on Windows. With all of the catches I had, I didn’t have one that caught this problem.

The problem was that Gtk.Pixbuf under Windows doesn’t load JPEGs, at least not the one I was loading. I converted the JPEG to a PNG file and it all worked. I’d say it was a bug in Gtk for Windows, but what do I know?

Posted in Uncategorized | Leave a comment

Next: Platform independence

The last post wasn’t really platform independent. Not at runtime anyway. I discovered that the technique is to create a class that delivers the operating system.


public class OperatingSystem
{

   [DllImport ("libc")]
   static extern int uname (IntPtr buf);

   public static string DetectOS ()
   {
      string style;
      if( !IsUnix ) 
      {
         style = "Windows";
	 return style;
      }

      IntPtr buf = UnixMarshal.AllocHeap(8192);
      if( uname (buf) != 0 )
      {
         style = "Unix";
         return style;
      }
			
      style = UnixMarshal.PtrToStringUnix (buf);
      UnixMarshal.FreeHeap(buf);
      return style;
   }

   static bool IsUnix 
   {
      get {
         int p = (int) Environment.OSVersion.Platform;
         return ((p == 4) || (p == 128));
      }
   }
}

Now all you have to do is use refelction. So substituting yesterday’s first technique for MacOS in the static Main method


if( OperatingSystem.DetectOS() == "Darwin" )
{
   System.Reflection.Assembly assemblyMonoMac = System.Reflection.Assembly.Load("MonoMac");
   Type nsapplication = assemblyMonoMac.GetType("MonoMac.AppKit.NSApplication");
   nsapplication.GetMethod("Init").Invoke( null, new object[] {});				
}

The following code fragment creates a sound buffer and then plays it. You could equally apply the same technique to yesterday’s example of turning an icon into a pixbuf.


object sndPlayer;
string OS = OperatingSystem.DetectOS();
if( OS == "Darwin" )
{			
   System.Reflection.Assembly assemblyMonoMac = System.Reflection.Assembly.Load("MonoMac");
   Type nsdata = assemblyMonoMac.GetType("MonoMac.Foundation.NSData");
   object sounddata = nsdata.GetMethod("FromStream").Invoke( null, new object[] { s });
   sndPlayer = assemblyMonoMac.CreateInstance("MonoMac.AppKit.NSSound",false,System.Reflection.BindingFlags.  CreateInstance,null,new object[] { sounddata }, null, null );
   StartReminders();
}
else
{
   sndPlayer = new SoundPlayer(s);
   (sndPlayer as SoundPlayer).LoadCompleted += Handle_sndPlayer_LoadCompleted;
   (sndPlayer as SoundPlayer).LoadAsync();
}	

if( OS == "Darwin" )
{
   System.Reflection.Assembly assemblyMonoMac = System.Reflection.Assembly.Load("MonoMac");
   Type nssound = assemblyMonoMac.GetType("MonoMac.AppKit.NSSound");
   System.Reflection.MethodInfo methodInfo = nssound.GetMethod("Play");
   methodInfo.Invoke( sndPlayer, new object[] {});
}
else
   (sndPlayer as SoundPlayer).Play();

What’s left to explore is displaying unicode strings, but that’s another topic.

Posted in Uncategorized | Leave a comment

Gtk and MonoMac

I think I discovered a couple of secrets to making MonoMac work with Gtk today. They’re mindbogglingly simple.

The first looks like this:


public static void Main( string[] args )
{
   Application.Init();
#if MAC
   MonoMac.AppKit.NSApplication.Init();
#endif
   new MainWindow();
   Application.Run();
}

The second was to make NSImages turn into Pixbufs. Here’s how:


string fileType = MonoMac.AppKit.NSFileTypeForHFSTypeCode.FinderIcon;
MonoMac.AppKit.NSWorkspace workspace = MonoMac.AppKit.NSWorkspace.SharedWorkspace;
MonoMac.AppKit.NSImage folderNSImage = workspace.IconForFileType( fileType );
MonoMac.CoreGraphics.CGImage folderCGImage = folderNSImage.AsCGImage( System.Drawing.RectangleF.Empty, null, null );
MonoMac.AppKit.NSBitmapImageRep folderImageRep = new MonoMac.AppKit.NSBitmapImageRep(folderCGImage );
MonoMac.Foundation.NSData folderData = folderImageRep.TiffRepresentation;
Gdk.PixbufLoader loader = new Gdk.PixbufLoader( folderData.AsStream() );
pixbuf = loader.Pixbuf;

Easy when you know how.

Posted in Uncategorized | Leave a comment

Learning Cocoa coming from GTK# and WPF

In case you’re wondering why there’s no trading information lately, I’ve been doing work on some of my other applications. All in Gtk#.

Well, I decided to bite the bullet and learn MonoMac. The reason’s somewhat commercial and I’d like to convert some of my applications to work on the iPad and maybe even the iPhone. So I got a Mac. For the second time. And the lovely thing is that my Gtk# applications are running just fine. Mostly.

But when it came to Cocoa, things were a little different. The trouble was that my brand new MiniMac comes with Lion and installs XCode 4. Ouch. That means I can’t easily build nib files, if you know what they are. They connect the visual interface to the classes. And unlike Gtk# or even WPF for that matter you can’t, for all intensive purposes, do the job programmatically. When I asked Kangaroo why? He told me that well, Cocoa on the Mac is 15 years old. Aaah.

So, I spoke to more of the lovely people at Xamarin. They really are lovely. And their advice was to compile the latest master of MonoDevelop. So while I gather my forces to download the latest Master and compile it on my machine I’m going to dig into Objective C a little. The general advice is that you have to at least be able to read Objective C, even if you’re programming in C#.

Then when it’s all going. I’m off to rewrite the UI on one or two of my smaller apps. Maybe I’ll even do OpenTrader for Cocoa, but that ain’t small.

Posted in Uncategorized | Leave a comment

WPF vs Gtk#

A few years ago, I had a large project which I developed using WPF (Windows Presentation Foundation). It’s a great development environment. It’s tidy, development is fast and its flexible. And the ability to design visually is extremely good. Why people develop only for Windows stick to Windows Forms, I don’t know.

OpenTrader, however, I’m developing for Linux and am using Gtk#. It’s got a lovely architecture, but development time is slower, at least for the presentation elements because you’re working at a lower level. And the visual design studio is crap which means that you have to develop the design in code. The advantage is that Gtk# is for Mono which is a cross-platform architecture and thus I can run software in Linux, which I use as a preference over Windows.

I can see the difficulty in developing WPF for Mono and can’t be bothered learning Moonlight – Silverlight’s equivalent in Mono. And quite frankly I can develop a visual interface reasonably rapidly in Gtk#. So, I probably won’t go back.

Another thing I like about WPF is that it does enforce you to separate data and visual design. I particularly liked its use of Observable Collections, to the point where I now separate out the database handling completely from the internal data and from the presentation elements. Should I want to change a database handler I can easily.

C# manages this all very, very well. I like C#, I think Microsoft did a great job. Sun’s bitchiness with Microsoft over Java meant a much better language in C# and IMHO Python is just a mess. The Mono boys have done a great job translating .Net. WPF? Well I learned from it and moved on. Though I won’t be leaving C# any time soon.

Posted in Uncategorized | 3 Comments