Apptico: Be Aware of Not Getting Paid
Apptico, a small company headed by Paul Grossi is behind the iPhone App **Stadiyum**. The App is nice but the business practice of Apptico / Paul Grossi is to use developers / creative artists work and when they finally have to pay the just look for new people without paying for work already delivered.
If we would be the only one I wouldn’t mention this here but I knew a few people with even bigger outstanding invoices than me and so I want to help others to avoid this trap. Every start-up will deal with financial hardship one way or the other but Apptico / Paul Grossi did not even try to find a compromise and just did not respond at all. Looking at all these cases I left wondering if this isn’t just Apptico’s business model to get cheap labour.
For me I am done with them but I want to spread the word what anyone can expect with them. They might pay an few invoices just to give you a sense of security but so far I don’t know anyone getting paid in full.
Cheers – Andy
Unit Tests with iOS and XCode4
Since nearly 1 year I am developing iPhone applications but until last week I never found time to write and run unit tests even though in XCode4 it asks you if one want to include unit tests into the App. But it was just a question of time until I have to start using it. So one of my Apps started to fail over and over again because the web service calls either changed or just did not work. This became very tedious because I had to go through a ton of log files to figure out what didn’t work. Thus it finally was time to invest the time to create the unit tests so that the API is tested with little effort and I have a quick result on what is broken.
As usual the road to bliss was plastered with stepping stones, pitfalls and some frustrations which made it more difficult that expected but it did not prevent me from reaching my goal. These are the steps I had to take to make it work:
- If not already done create a new file of type Object-C test case class
- To begin with write a simple no-op test method with a NSLog statement so that you know when it is executed
- Go to the Project Configuration, select the test target, select all on the top and look for the group Unit Testing. There you set Test after Build to Yes.
- On the top left select the XXXTest schema and click on run
- To check the log please go to the log navigator (command-7) and select the top most log entry
- Inside there you look for Run custom shell script, select that row and hit the staple icon on the right. This will open the log view below.
- Now you can see if the test was executed
So far we made the test execute but if we try to test any of our classes we probably fail with a linker error. This is because XCode4 per se does not add any regular classes into the test environment except we already did that when adding the class to XCode. That said we can do that easily:
- Go back to the project configuration
- Select the test target
- Click on Build Phases
- Select Compile Sources
- Now we can add any implementation class file that we need to run the test. Please don’t add headers to this list (.h files)
- We might to repeat this a few times until we get all the necessary classes in
Now we can start writing tests that uses the classes we have. For now I only tested non-UI classes and I had to go ahead and use a switch in some of the classes to not use UI components otherwise the test would fail. I am not sure if there is a way to test UI components in the unit tests. On the bright side this forces developers to separate UI and service code more thoroughly which is not a bad thing either.
Cheers – Andy
iOS, Blocking User Input and CFRunLoopRun()
Yesterday I worked on new a Lab for my upcoming iPhone course and the topic was how to prevent user input while the application is gathering data from a server. Normally that is not a big issue when you just obtain data but that can be a big issue when you send data because then it could corrupt the server side.
So far I just created an UIView that was semi-transparent on top of the entire view preventing the user to click on anything below. But that did not work properly in every case because as it turned out the user input is not consumed but queued and handled as soon as the main thread becomes available. Therefore if I don’t disable the button or alike the code is executed again. This is the original code:
self.connection = [[[NSURLConnection alloc]
initWithRequest:request delegate:self] autorelease];
// Now show an animation
UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
UIView *window = [[UIApplication sharedApplication] keyWindow];
UIView *shield = [[UIView alloc] initWithFrame:window.bounds];
shield.backgroundColor = [UIColor blackColor];
shield.alpha = 0.5f;
[window addSubview:shield];
spinner.center = shield.center;
[shield addSubview:spinner];
spinner.hidden = NO;
[spinner startAnimating];
// Block the further execution until all data is received
CFRunLoopRun();
[spinner stopAnimating];
[spinner removeFromSuperview];
[spinner release];
[shield removeFromSuperview];
[shield release];
Soon I got the feeling that I block the main UI thread and so the input is not consumed until the system can execute it. After looking for a good solution I was more or less told that I should not use CFRunLoopRun() but let the main thread run its course and deal with the result when it comes in.
That said the transition was not easy but eventually I got all the callbacks in place and the thing worked fine except that the call was to short to test is properly. Thus I added a sleep inside the callback to give myself time to click multiple times but that did not solve the issue. Through debugging I then saw that when data are returned back from the server that it is still done in the main thread and so preventing the view to consume the user input.
This is the code afterwards:
// 1. When the call comes in and we start the loading
self.spinner = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
[self.spinner release];
UIView *window = [[UIApplication sharedApplication] keyWindow];
self.shield = [[UIView alloc] initWithFrame:window.bounds];
[self.shield release];
shield.backgroundColor = [UIColor blackColor];
shield.alpha = 0.5f;
[window addSubview:shield];
spinner.center = shield.center;
[shield addSubview:spinner];
spinner.hidden = NO;
[spinner startAnimating];
// Now execute the call to the web service
self.connection = [[[NSURLConnection alloc]
initWithRequest:request delegate:self] autorelease];
// 2. When the all the data is received we do:
[spinner stopAnimating];
[spinner removeFromSuperview];
[shield removeFromSuperview];
// Call back to the service that we received the data
[self.depotService handleResult:root];
Finally I went to the backend web service and made sure that handling of the call is delayed. Then I was able to test it and voila it worked like a charm. I could click multiple times on the button and when the shielding view went away the user input was consumed and did not cause more calls to the server.
There is still some stuff I have to learn how things are done in iOS in contrast to backend Java as I am used to. On the other hand it forces me to understand the underlying concept in details which will be a great asset when given the class.
– Andy
iOS can be a Bitch
Today I battled an issue with iOS that nearly drove me crazy. What I wanted to do is to call a Apache Sling WebService and retrieve a list of data. I tested it with Curl do make sure it works before dealing with the iOS.
Because I am lazy I did copy some existing code that I knew was working into my project, adjust it and started to test it. But whatever I did I got this error:
Error Domain=kCFErrorDomainCFNetwork Code=303 “The operation couldn’t be completed. (kCFErrorDomainCFNetwork error 303.)”
Can you guess what caused it?
Well, when I ran out of options I just started to take out code until I either ran into other issues or until it fixes it. Eventually I got it working and it turned out that there was a slight change between Sling (very RESTful centric) and the way we did the project which I borrowed the code from. In Sling you need a GET in order to obtain data and in the previous project everything was a POST. But that wasn’t the issue. What was is that I by default gave a payload to the request even if that one was empty. And that is what caused the error. As soon as I took out the payload everything was back to normal. I have to admit that this error code / description was very helpful.
So with Sling I have to make sure that I pay more attention to what HTTP method is used and make the appropriate checks on when certain features can be used.
– Andy
XCode4: a Big Step in iOS Development
Yesterday Apple released XCode4, the IDE (integrated development environment) to develop iOS and Mac OS X Applications. After more than 1 year (as far as I can remember) this finally will make developing iOS apps much easier and I think much faster and definitively more fun.
Beforehand in XCode3 the Interface Builder was separated from XCode and created many windows which were hard to track and especially harder to close. Just opening a few XIBs and the screen was cluttered with windows all over the place. The only way to managed them was to close the IB from time to time. Now in XCode4 the IB is integrated into XCode and is part of its UI. Due to the fact that XCode is now a single window application there are no more floating windows around. The only other windows one might see are other applications or the Organizer window which contains the help pages, source control systems, devices, projects and archives.
But that is not everything. Because IB is part of it one can have the UI on the left hand editor and display the related View Controller header class file on the right hand editor. This way it is easy to add new IBOutlet properties and IBAction methods without having to leave the UI editor. This works the same way as when I open the implementation class (.m) and have set the right editor to be on counterpart then it will display the header class (.h) or vice versa. The right window can also be used to display the differences in the versions of one file.
The right sidebar is used to display the File Inspector and Quick Help and if an XIB is opened it displays the Identity, Attribute, Size and Connection Inspectors as well.
Beside that the Editor itself has improved dramatically with better code completion, error highlighting as well as code snippets. This improves the overall quality of the code written.
The bottom bar is used to display the log files when the app is running as well as the debugger controls. This way I don’t have to search for the Output and it can be easily viewed while the app is running.
Having used IntelliJ IDEA for a long time the XCode is coming close to it making developing Apps much easier and prevents me from juggling a million windows. I have used XCode4 since more than half a year and so I am very happy to see it get publicly released.
That said there is a ton of more functionality that I did not encountered yet or have not used it so I am looking forward to use it even more and share my thoughts with others.
-Andy
XCode4, iPhone Class and iOS Recipies
This week was pretty exciting even though I am not going to buy an iPad2 or join into the frenzies.
First Apple release XCode4 which is really great news because now I can develop iPhone Apps on it without having to worry about issues or that it is not fully supported by Apple. This also makes it possible to talk about it publicly and I can use screenshots to discuss issues.
Then I started to work on my iPhone class that I intend to give this year if I find people willing to listen to me. My class is different in many ways but foremost I will use a single example throughout the class. On one hand this is a challenge because there is more to code or to fill in to make it a smooth progress but it also means that I have to develop the class around the labs.
Finally there is another book out there from Matt Drance and Paul Warren from the Pragmatic Bookshelf called iOS Recipes. From the few pages I read so far this books is quite nice and gives beginners and intermediate iOS developers a way to see how other developers do it.
– Andy
Hooray: Stadiyum iOS App Released Today
In less than 10 days the iPhone app I developed the last 4 weeks was released to iTunes today. You can check it out on iTunes. The app was slated to go live before the end of the month but now it is already available.
As hard and exhausting the project was this fast approval is a great satisfaction.
Cheers – Andy
First iOS App Submitted
Finally after 4 long weeks with long hours the iPhone App I was coding is submitted for reviewing on the App Store.
At the very end we not only had to fix last minute issues which are always very dangerous but I also ran into an issue where I could not build and archive my app and then symbolicate a crash log afterwards. This was very bad considering the fact that when users would send in Crash Logs we would have no way to figure out what went wrong. Eventually I had a hunch that having XCode 3 and 4 installed could be the culprit. So I went ahead and installed XCode 3.2.5 onto a Mac that had not prior installation and after resolving all the issues like missing Certificates I was finally able to create an archive and symbolicate a crash log.
Now for the App it means we have to wait for Apple’s verdict but for me it means that I start on another project today but in contrast that is a project with normal hours and no hard deadline.
-Andy
Animate a Blocking Dialog in iOS
Today I was faced with a little challenge when I discovered that a blocking Help Dialog which should slide on and off does not animate after the user clicks OK.
It turns out that the UIView animation is executed in a background thread and so the method that is executed when the user clicks OK is processing further without waiting for the animation to finish. Within there I will yank the view from its parent and so the animation is not shown.
The solution to this is to register an Animation Delegate as well as the method that is called when the animation is done. This is done this way:
[UIView beginAnimations:@"hideView" context:NULL];
...
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@selector
(animationDidStop:finished:context:)];
ATTENTION: Please note that these settings must be done within the animation block. Setting them outside means nothing is going to be happening.
This informs the given delegate when the animation is done and there is where I can release the block:
- (void)animationDidStop:(NSString*)animationID
finished:(BOOL)finished
context:(void *)context
{
CFRunLoopStop( CFRunLoopGetCurrent() );
}
This will do the trick and allow me to clean up the dialog meaning removing it from the super view so that it will eventually released and not become a memory leak.
This little challenge also means that I finally become some sort of a iOS crack delving deeper and deeper into regions of iOS is never dared before to even have a look at it.
Cheers – Andy