Wednesday, October 27, 2010

iPhone Dev Tip - Blocks are great, er.. kind of.

I found myself confronted by this rather vague and unexpected error today when dropping a new build onto a test device.

dyld: Symbol not found: __NSConcreteStackBlock

Vague because the symbol didn't reference any library that I was expecting to have been added and unexpected because the build was working on the other dev and test devices.

The only difference was the test device was running iOS 3.1 rather than the 4.x variants of the others, which was in fact the root of the problem.

In an animation block I had used the nice new method
[UIView transitionWithView:duration:options:animations:completion] 
Which takes a set of animation operations as a block, which is an iOS4 only feature. Thought it worth leaving a reminder as the usual stack overflow/google trawl didn't throw me any bones.

Sunday, October 17, 2010

Freya Gets Milk

Sunday, September 19, 2010

Freya Plus UZU

Friday, September 17, 2010

iPhone Dev Tip: Watching for 404's

Something I have seen a few times when debugging iPhone apps for clients is a misunderstanding of the definition of "Success" when it comes to the NSURLConnection class. In the NSURLConnection delegate  protocol a "successful'" connection is any one that makes a connection to the target host and gets an ACK. This means that when using these methods to get HTTP content (such as JSON and XML, a common pattern) any 404 or 500 errors returned by the target host are treated as a success if not handled correctly.

The way to fix this is to cast the NSURLResponse object to an NSHTTPURLResponse in the didReceiveResponse delegate method. For example set up a connection in the standard way.

 // url for download  
 NSURL *url = [NSURL URLWithString:[self urlString]];  
 // request  
 NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:30;  
 // connect  
 NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];  

Then in your NSURLConnection didReceiveResponse method.

 - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {  
      // cast the response to NSHTTPURLResponse so we can look for 404 etc  
      NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;  
      if ([httpResponse statusCode] >= 400) {  
           NSLog(@"remote URL returned error %d %@: ",[httpResponse statusCode],[NSHTTPURLResponse localizedStringForStatusCode:[httpResponse statusCode]]);  
           .....  
      } else {  
           // start recieving data  
         ...  
      }       
 }  

Monday, September 13, 2010

Rick Has Mostly Been Listening to...


Thursday, August 12, 2010

Baby Bear

Wednesday, August 11, 2010

Compiling CyberLink UPNP for iOS redux

A while back I posted some - admittedly vague - instructions on how to compile the CyberLink UPNP library into a static .lib suitable for use in an iPhone project. The method turned out difficult (if not impossible) to reproduce because a) it had been quite a while since I worked through the steps myself and b) because the files included in the distribution of the CyberLink library had changed subtly so my method wouldn't work any more.

The key to getting the library to compile in the way that I managed it is a set of Objective C wrapper classes that sit between the standard c distribution and your iPhone cocoa project. These wrapper classes were included in the distribution as examples in the first few releases but are missing from later versions. At the time of writing the CyberGarage website is down so I have not been able to check the current status.

As a result I have had several requests to share my Xcode project so that others can also get the UPNP library compiled. I have been a little reticent to do so because although the library was released as an opensource project on sourceforge it is possible that the author Satoshi Konno changed his mind about including the wrappers after he no doubt used them in some commercial products. I sent a couple of emails over to Satoshi San asking if he minded if I share the code or if he could re-include the wrappers in a new release but have not had any response.

So now I have decided to make available my Xcode project with the original wrappers included along with my tweaks to get it to compile for iOS "as is" until such time as I am asked to take it down by the author if he objects to it being available. I hope that it helps you get UPNP working in your projects, of course official UPNP support would be even better.

You may want to update the c portions of this project from the latest sourceforge snapshot to take advantage of any bugfixes or improvements but note that this might break a couple of the wrappers where I have added my own functions to the c library. This will only be minor breakage however and easy to iron out.

To compile and then include it in your project use a shared build location as described by the modular shared library scheme discussed in the Clint Harris tutorial. This is for sure the most important part to getting the library to link into your projects correctly. The problem is that to use the library it must be compiled for the exact configuration you are using it in. Emulator != Device and SDK versions can be significantly different. This means that you need to go back and tweak the build settings for the static library project, rebuild and then redo the link in the parent project each time you switch between emulator and device testing. A real pain. The modular linking method solves this by linking the entire static library project as a sub-project and rebuilding automagically where required. You will struggle to use the library unless you follow those steps. Go read it now, really.

Back? OK now make sure that you have recursive header search paths

[path to]/CyberLink/std/av/include 
[path to]/CyberLink/include
in the build settings for the CyberLink target as the paths are set explicitly in my project and probably get mangled when you use it.
I have updated the project to use ${SOURCE_ROOT} as I should have done from the start.

Make sure that the paths to the local libXML are correct too so that building the release and debug versions work as expected. You will need to update the path to use the SDK version you are building for. Or you could try using this technique to make an SDK agnostic link.

When that's done just import the modules you need as so...

#import <CyberLink/CGUpnpControlPoint.h>
#import <CyberLink/CGUpnpAction.h>
#import <CyberLink/CGUpnpDevice.h>
#import <CyberLink/CGUpnpService.h>
#import <CyberLink/CGUpnpStateVariable.h>


Happy hacking!

Original post
Download Xcode project CyberLink.zip