Stanford iPhone App Programming lecture 15

Lecture 15 from the Stanford University iPhone Application Programming class was hosted by Justin Santamaria from Apple. Justin covered the photo picker, Core Location, and accelerometer topics during his presentation, none of which were particularly pertinent to my current projects.

Unfortunately, Justin did not show live demos of these components, which is understandable considering the fact that the simulator has limited support for these components. The code snippets in the slides should be sufficient for getting these things up and running.

At the end of the presentation, Justin also covered some hints on maximizing battery life on the platform.

Subversion operations on Visual Studio 2008 solution take forever

Well, not literally, just a very very long time.

Our Subversion source repository has grown to be quite sizable over the past couple of years. We have always used TortoiseSVN and VisualSVN to tame this beast, and it has usually not let us down.

However, a while back, something bad happened to a VS 2008 solution in the repository. When launching the solution, the refresh of the version control status indicators next to the files in the solution take a very long time to appear and/or refresh, and any kind of operation done on the solution file (such as update, repo browser, etc.) goes back to the root of the whole repository instead of working with the folder where the solution file lives.

Strangely enough, operations done on any of the components inside of the solution does the right thing. In other words, if I update a project in the solution from Visual Studio, it works lightning fast.

I finally got tired of wasting 2 to 10 minutes per operation on the solution and studied this problem by comparing this malfunctioning solution with one that appears to do what you would expect it to. One thing I noticed right away was that the speedy project contained the following lines at the bottom of the solution file (opened in your favorite text editor, of course):

    GlobalSection(ExtensibilityGlobals) = postSolution
        VisualSVNWorkingCopyRoot =
    EndGlobalSection
    GlobalSection(SubversionScc) = preSolution
        Svn-Managed = True
        Manager = AnkhSVN - Subversion Support for Visual Studio
    EndGlobalSection

I added these lines to the bottom of my sluggish solution file and re-opened it, and I now predict explosive advances in my productivity. Or at least more time for tweeting.

Now all I need to do is figure out how to remove these disabled “DSL Tools”, “Text Transformation”, “Workflow”, and “ANTS 4” menu items from my VS 2008. Anyone have any ideas? (EDIT: John Boker has found the solution, see the comments.)

EDIT, PART DEUX: I tried this fix on a different existing Visual Studio project on 9/23/2009, and of course it didn’t work. I studied the problem a bit more, and found that if I added the GlobalSection(SubversionSCC) section that I have already inserted into the code block above, it did the trick for me. (Even though I am not actually using AnkhSVN, I am using TortoiseSVN, so I am guessing the Manager line is not important. However, I have left it in there for completeness.)

Stanford iPhone App Programming lecture 14

Lecture 14 from the Stanford University iPhone Application Programming class was hosted by Steve Demeter from Demiforce and Josh Shaffer from Apple. Steve talked about his experience in putting together Trism, and his ideas on the touch interface on the iPhone. Josh then talked technically about the methods, events, and objects that make up the touch interface on the iPhone, and how to use them.

I probably should have watched this video before trying to do swipe detection (see this blog post) in my application, it probably would have saved me some search time and trial and error. Josh used a CGAffineTransform structure to track changes, which is probably the recommended way of doing this sort of thing. It is a bit of overkill for my particular application, as I don’t need to know about the zooming and rotations, I literally just needed to know if the person’s finger was moving left or right.

Three20 Presentation (CIDUG meeting, July 28, 2009)

Justin Searls gave a very good presentation on the Three20 toolkit for the iPhone SDK. The presentation was given at the Columbus iPhone Developer User Group on July 28, 2009.

The Three20 toolkit has a lot of interesting additions and extensions to the iPhone SDK, the most used of which is a photo and thumbnail browser that is based on the ones written for the Facebook iPhone application.

Here is a link to the Columbus iPhone Developers User Group:

CIDUG

And here is a link to Justin’s posting to the group, which includes instructions on where to find the Three20 code and information on installation and usage:

7/28 CIDUG Meeting on Three20

Stanford iPhone App Programming lecture 13

Lecture 13 from the Stanford University iPhone Application Programming class was hosted by Alan Cannistraro. He covered exceptions and debugging, using the UISearchBar, notifications, and key value coding.

I did not know you could set a breakpoint on objc_exception_throw, this seems like an awesome way to try and track down exactly where exceptions are happening in the code. Also, some of the key value coding and key value observing items he covered were pretty interesting and relevant.

Simple swipe detection in the iPhone SDK

A quick round of hallway usability testing of my iPhone app revealed that apparently, iPhone and iPod Touch users like to swipe and don’t have any idea that the UIPageControl (the bar with the little white dots that show which page of information you are on) can be tapped on to move the page number. Instead, my admittedly small sample size of 2 (thanks John and Ben) were trying to swipe all over the view to move it from one page to another. As a result, I set out to try and find information about detecting the swipe motion in the iPhone SDK.

Quick searches of the internet and documentation did not reveal any immediate solutions, so I set about on the task of trying to figure out how to do it on my own. The first thing I noticed is that you can hook into the touchesBegan event for the view, so I created this code:

- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
	CGPoint pt;
	NSSet *allTouches = [event allTouches];
	if ([allTouches count] == 1)
	{
		UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
		if ([touch tapCount] == 1)
		{
			pt = [touch locationInView:self.view];
			touchBeganX = pt.x;
			touchBeganY = pt.y;
		}
	}
}

(After adding the following variable definitions at the top of my view controller implementation file, of course.)

int touchBeganX, touchBeganY;

So now I have the position where a single touch began. The next thing I thought I would do would be to subclass the touchesEnded event, but for some reason, the tapCount of the touch that I read in touchesEnded would be zero, and that seemed a little confusing to me as to why that would be. I then turned to the touchesMoved event:

- (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event {
	CGPoint pt;
	NSSet *allTouches = [event allTouches];
	if ([allTouches count] == 1)
	{
		UITouch *touch = [[allTouches allObjects] objectAtIndex:0];
		if ([touch tapCount] == 1)
		{
			pt = [touch locationInView:self.view];
			touchMovedX = pt.x;
			touchMovedY = pt.y;
		}
	}
}

Yes, this looks shockingly similar to the code for touchesBegan. By the way, don’t forget more variable definitions:

int touchMovedX, touchMovedY;

I can now track where the touch began and the last place it moved to. I then swing back around to the touchesEnded event to do the actual swipe detection, as even though the tapCount is zero, I think I can safely determine that a single touch and drag event occurred and then test it to see if it is a swipe.

- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event {
	NSSet *allTouches = [event allTouches];
	if ([allTouches count] == 1)
	{
		int diffX = touchMovedX - touchBeganX;
		int diffY = touchMovedY - touchBeganY;
		if (diffY >= -20 && diffY <= 20) 		
		{
 			if (diffX > 20)
			{
				NSLog(@"swipe right");
				// do something here
			}
			else if (diffX < -20)
			{
				NSLog(@"swipe left");
				// do something else here
			}
		}
	}
}

Perhaps reading swipes is so simple to do in the iPhone SDK that I missed it in the docs or online. If anyone has any better ways to do this, or a web site or blog post that explains it better, please let me know.


Somewhat related, somewhat unrelated tangent alert:

My father used to have this bag that said “I Like Swipe”, I think he said that he used to sell the product when he was a boy back in the 1940s, it was some kind of cleaning chemical. I wish he still had that bag, it was pretty retro looking and a picture of it would have fit in perfectly with this posting. I guess I will just have to settle with this:
&quot;I Like Swipe&quot;

Friends don’t let friends reinvent System.Security.Cryptography

A fellow coworker is upgrading one of our long time customer’s ASP.NET web site that was originally created in 2003, and all is going swimmingly. Alas, this project could not go gently into that good night.

He makes the web page and code changes, modifies the database, pushes all the changes up to the web site, and the site is working well. Customers are placing orders on the web site, order e-mails are being sent to the site owners with encrypted credit card information, and all are happy.

But there is always a fly in the ointment. All of a sudden, an order is placed on the web site, but when the site owner tries to run a decrypt on the credit card information in the e-mail, the decryption routine is reporting a failure. So naturally, we assume that we broke the code somehow, so we started to dive into the project to see what we did to destabilize it.

He asked for my opinions on this problem, so I came over and we started to go through the VB.NET Framework v2.0 project. While investigating the area of the code containing the exact message that the customer was getting, my blood pressure started to go up right away as we started to see code that looked like this:

If intNumberLength = 16 Then
    'go through each of the 16 numbers and
    'add the code for them into the return string
    intNumber(0) = CType(Mid(strNumber, 1, 1), Integer)
    intNumber(1) = CType(Mid(strNumber, 2, 1), Integer)
    intNumber(2) = CType(Mid(strNumber, 3, 1), Integer)
    intNumber(3) = CType(Mid(strNumber, 4, 1), Integer)
    intNumber(4) = CType(Mid(strNumber, 5, 1), Integer)
    intNumber(5) = CType(Mid(strNumber, 6, 1), Integer)
    intNumber(6) = CType(Mid(strNumber, 7, 1), Integer)
    intNumber(7) = CType(Mid(strNumber, 8, 1), Integer)
    intNumber(8) = CType(Mid(strNumber, 9, 1), Integer)
    intNumber(9) = CType(Mid(strNumber, 10, 1), Integer)
    intNumber(10) = CType(Mid(strNumber, 11, 1), Integer)
    intNumber(11) = CType(Mid(strNumber, 12, 1), Integer)
    intNumber(12) = CType(Mid(strNumber, 13, 1), Integer)
    intNumber(13) = CType(Mid(strNumber, 14, 1), Integer)
    intNumber(14) = CType(Mid(strNumber, 15, 1), Integer)
    intNumber(15) = CType(Mid(strNumber, 16, 1), Integer)
 
    strCharCodes(0) = encrypt_Char1(intNumber(0), intIndexCode)
    strCharCodes(1) = encrypt_Char2(intNumber(1), intIndexCode)
    strCharCodes(2) = encrypt_Char3(intNumber(2), intIndexCode)
    strCharCodes(3) = encrypt_Char4(intNumber(3), intIndexCode)
    strCharCodes(4) = encrypt_Char5(intNumber(4), intIndexCode)
    strCharCodes(5) = encrypt_Char6(intNumber(5), intIndexCode)
    strCharCodes(6) = encrypt_Char7(intNumber(6), intIndexCode)
    strCharCodes(7) = encrypt_Char8(intNumber(7), intIndexCode)
    strCharCodes(8) = encrypt_Char9(intNumber(8), intIndexCode)
    strCharCodes(9) = encrypt_Char10(intNumber(9), intIndexCode)
    strCharCodes(10) = encrypt_Char11(intNumber(10), intIndexCode)
    strCharCodes(11) = encrypt_Char12(intNumber(11), intIndexCode)
    strCharCodes(12) = encrypt_Char13(intNumber(12), intIndexCode)
    strCharCodes(13) = encrypt_Char14(intNumber(13), intIndexCode)
    strCharCodes(14) = encrypt_Char15(intNumber(14), intIndexCode)
    strCharCodes(15) = encrypt_Char16(intNumber(15), intIndexCode)
 
    'strReturnValue = strCharCodes.ToString
ElseIf intNumberLength = 15 Then
    ' you get the idea

And this…

'first char
Select Case Left(strEncodeCard, 1)
    Case "X"    ' these character constants were originally all different
        strCardNumber(0) = "0"
    Case "X"    ' I have masked them out for this blog posting
        strCardNumber(0) = "1"
    Case "X"
        strCardNumber(0) = "2"
    Case "X"
        strCardNumber(0) = "3"
    Case "X"
        strCardNumber(0) = "4"
    Case "X"
        strCardNumber(0) = "5"
    Case "X"
        strCardNumber(0) = "6"
    Case "X"
        strCardNumber(0) = "7"
    Case "X"
        strCardNumber(0) = "8"
    Case "X"
        strCardNumber(0) = "9"
    Case Else
        blnSuccess = False
End Select

(The above code was repeated 32 times, once for each digit of a potential 16 digit credit card number, and there were two sets of these that were switched if the digit position was odd or even. There was definitely some thought put into this. I’m not saying it was good thought, just thought. Perhaps they were paid by the lines of code written?)

OK, I have done things like this from time to time, usually not to this extent, but the original designers and coders of this project at least had the good sense to encrypt the credit card information that was being e-mailed, so maybe it will get better.

Yeah, I was wrong about that, I should remember a tenet of code maintenance that I learned a long time ago: TWGW. (This stands for Things Will Get Worse.) As we stepped through the order that was confusing the system, we came upon this nugget.

'second, select the expiration year code
Select Case intExpYear
    Case 2003
        cryptoExp_Year = "X"    ' these character constants were originally all different
    Case 2004
        cryptoExp_Year = "X"    ' I have masked them out for this blog posting
    Case 2005
        cryptoExp_Year = "X"
    Case 2006
        cryptoExp_Year = "X"
    Case 2007
        cryptoExp_Year = "X"
    Case 2008
        cryptoExp_Year = "X"
    Case 2009
        cryptoExp_Year = "X"
    Case 2010
        cryptoExp_Year = "X"
    Case 2011
        cryptoExp_Year = "X"
    Case 2012
        cryptoExp_Year = "X"
End Select

Of course, the customer had a credit card that expired in 2013, and as such, no character was begin inserted into the encrypted string for the expiration year, and that was causing the problem.

I don’t even know where to begin, except to say that eventually this code was going to break, and that was the day. (System.Security.Cryptography was in .NET Framework v1.1, so they can’t use that as an excuse.) So the moral of the story is, if you are going to reinvent a Microsoft namespace, at least make it work more than six years.

Setting up an Objective-C delegate for the iPhone SDK

Once Ben Gottlieb of Standalone helped me get past the problem of creating and displaying my main view controller class, I set out to figure out how to do an Objective-C delegate. Unfortunately, none of the examples or tutorials I could find on the internet had a simple, straightforward explanation of what I needed to do to get it working.

After much trial and error, and reading up on as many descriptions on delegates that I could find, I got it working. Here are the steps that I had to go through in my code to get it working:

In my view subclass header file, this line was added to the top:

@protocol KeyboardViewDelegate;

This line was added to the class definition in the subclass header file:

id <KeyboardViewDelegate> delegate;

This line was added to the property definitions in the subclass header file:

@property (nonatomic, assign) id delegate;

And this section was added to the bottom of the subclass header file:

@protocol KeyboardViewDelegate<NSObject>
- (void) keyPressHandler:(int)keyPress;
@end

In my view subclass implementation file, this synthesize was added near the top:

@synthesize delegate;

And this section was added to the method in the subclass view that is wired up (via Interface Builder) to be called when a button is pressed on the view:

if(delegate && [delegate respondsToSelector:@selector(keyPressHandler:)]) {
    [delegate keyPressHandler:key];
}

In the view controller header file, of course the view subclass header needs to be included:

#import "KeyboardView.h"

I had to add the delegate name as part of the interface definition in the view controller header, adding the delegate name in angle brackets, changing it to look like this:

@interface MainViewController : UIViewController <KeyboardViewDelegate> {

And at the bottom of the view controller header file, I added a definition for the method that matches up with the one from the keyboard view:

- (void) keyPressHandler:(int)keyPress;

In the view controller implementation file, again the view header subclass needs to be included:

#import "KeyboardView.h"

In the viewDidLoad method of the view controller, during the creation of the view subclass, I had to set the subclass delegate to be the view controller:

CGRect sizeRect = CGRectMake(0, 225, 320, 190);
KeyboardView *view = [[KeyboardView alloc] init];
view.view.frame = sizeRect;
[view setDelegate:self];  // this line is pretty important !!!
[self.view addSubview:view.view];

And at the bottom of the view controller implementation file, thie method defined above is added:

- (void) keyPressHandler:(int)keyPress;
{
    NSLog(@"keyPressHandler just fired");
    // do something here
}

And that is it! When running in the simulator, the method in the view controller is fired whenever the method in the view subclass is fired.

Oh, and by the way, I am using a UIPageControl on my view controller, and I found out that, for some reason, I had to go into the viewDidLoad method and add the following line:

pageControl.backgroundColor = [UIColor grayColor];

If I did not add this line, the page control would never be visible, even though it was working, as when I tapped on either side of it, the code associated with it fired correctly. The background color of the page control was set to gray in Interface Builder. Anyone have any ideas why that would be?

System.MissingMethodException error in System.Data.SqlServerCe

After getting the new development machine up and running for the most part, I started once again to work on the web and client projects that we are going balls to the wall to get finished.

And of course, a roadblock was hit. On the Windows Mobile client, I got through most of the requisite re-referencing and compile errors that inevitably pop up when doing something like this. This client uses the Microsoft Synchronization Services to sync it’s local SQL Server Compact Edition database to our central SQL Server database.

When trying to create a new ServerSyncProviderProxy, the following error is being thrown:

System.MissingMethodException: File or assembly name 'System.Data.SqlServerCe,
Version=3.5.1.0, Culture=neutral, PublicKeyToken=3BE235DF1C8D2AD3', or one of
its dependencies, was not found.

After much headbanging, trial and error on both the 5.0 and 6.0 emulator and on an actual device, Google and Server Overflow searching, and staring at the code, we finally figured out what the problem was. As it turns out, I must have installed the SQL Server Compact Edition Service Pack 1 on my previous machine, and those references were saved and somehow survived in the project. On my new machine, there was a version of SQL Server Compact Edition that was installed by some component (Visual Studio 2008, Windows Mobile SDK, etc.), so to me everything looked OK. However, after installing the SQL Server Compact Edition SP1 on the computer, the error magically went away on the emulator.

As an aside, I tried to put the code on the handheld that it had not worked on previously, and it still did not work. After inspecting the error output, which was different, I found that I needed to redeploy the new SQL Server Compact Edition SP1 Windows Mobile sqlce.ppc.wce5.armv4i.CAB file on the device, unpack it (which overwrote the previous SQL Server CE files on the device), and then all was well.

Stanford iPhone App Programming lecture 12

Lecture 12 from the Stanford University iPhone Application Programming class was hosted by Alex Aybes. Alex covered using the address book functionality provided in the iPhone SDK.

His talk included several demonstrations of the C-based Address Book API, along with some of the ins and outs of Core Foundation, which shares many of the same concepts of the Objective-C based Foundation framework. His demos showed how to use the various person view controllers, getting person entries from the user’s Contacts applications, and diving into these entries to read and update the values existing in the person entry.

This does not directly apply to any of the applications I am currently working on, but no doubt it eventually will be useful in my development efforts. If you have a need to access the address book entries in the iPhone Contacts application, this is the presentation you want to check out.