Thursday, May 14, 2015

I ripped out RestKit and replaced it NSURLSession and Mantle

When I started at my current job I knew I would be doing a lot of REST interaction with the server. I decided to use RestKit as I had seen it mentioned a number of times in various developer forums.

It worked for some time but I finally hit the breaking point and ripped it all out changing 265 to convert them to NSURLSession and Mantle. Was I insane? Pretty much as in the end it did not solve the problem I was originally attempting to address but I am happy with the change.

First off Mantle makes it much easier and cleaner to handle JSON. It is not as easy as GSON on the Android side but it is not too bad. That was a lot of my file conversions and I do find it easier to add a new JSON object due to a new REST call to the server. The one downfall is each of your JSON receiving objects has to be derived from a Mantle class. Objective C does not support multiple inheritance which could make this a very limiting factor for you.

The other area I am not too happy about with Mantle is it handles converting NSDictionary and NSArray to JSON. That means I get a big JSON string from REST and then I use NSJSONSerialization to convert it into a NSDictionary and then convert that via Mantle to Objective C objects. Waste of memory and processing to double convert things. Good thing the JSON data is reasonably small.

The other side was getting rid of RestKit calls. This helped the code a lot. I had one REST call manager class that tried to handle all the server calls with delegate callbacks. Now all the calls are inline where they are called in the code and that code has block processing to handle the results. This lets you see what is going on easier. Plus if it is a PUT call I only have to reference PUT in one line of code whereas I had to do that in three places when using RestKit. Setting up each call in RestKit took a boatload of error prone boilerplate code. I sure as heck don't miss that.

So why not go with AFNetworking? Seems to also be popular but in the end even AFNetworking is using NSURLSession in the end. Apple seems to put together a decent networking package learning from others. One less pod to include in my build and hopefully using the official Apple networking that appeared in iOS 7 will keep me in the safe zone.

On the Android side I am using Volley and GSON, both from Google but not part of the base Android SDK. Volley is very similar to NSURLSession which is good. GSON is easier to work with than Mantle in there is less boilerplate code. If your variable names match the property names in the JSON you get from the server there really is no boilerplate at all. If they don't match a simple annotation gets them to sync up.

So what was the original issue I was attempting to fix? I want to have two type of NSURLSessions going in the code, one to do the normal user interaction processing - they tap something, I make a server request, I get server result and I show new data in the current view or in a new view. The second was to be a background session for uploading video via Amazon Web Services.

I am using AWS but I am using the straight API from them. Yes, there is sample upload in the background code out there and it works when you don't have the other NSURLSession doing other work which really stinks. I want the user to be able to start a video upload and have it run in the background until complete even if they leave my app or turn off the phone screen. Works like a champ on the Android side where I set up a very basic service.

I realize Apple really does not want you do to anything in the background. They trust no one. They do have a new thing that lets you get maybe 10 minutes of time to do some background work. That is one of the things NSURLSession is set to allow. But I just can't get it to work. It will start, send up some % of the video then restart at 0% and do that over and over again. On the simulator, which does not run like a real device, it can get the whole video uploaded never triggering the restart you see on the iPhone or iPad. I have posted a message on Stack Overflow describing this issue but no answers.

I really wish Amazon would handle this for you in their API. Seems like background uploading would be a really common thing for a programmer to want to do with them. Maybe Apple could handle it in their API as well but I doubt that as they are anti-background as it is.

Tuesday, March 3, 2015

iOS battling 3rd party tools

I have been battling various items in iOS over that past week and it is getting really frustrating.

First up I really wanted a dialog with some text entry and a few buttons. They pulled the "custom view" part out post iOS 6 so I found a few GitHub repositories that should solve the problem. First once just did not pan out and the UIView just did not look right. Second one appeared to work OK at first but then it did not play well in iOS 8 in landscape.

Apple decided to change the way you get back height and width of the screen in iOS 8. Previously you always got height and width as if you were in portrait mode. Now they give it back for the current screen orientation. Huge change for programmers. People had height / width swapping code to handle this and you still have to do that for iOS 7 and older.

I fixed the code so landscape worked for iOS 8 on the simulator. Once I ran it on a real device things went to crap again. Extra things being painted and the keyboard popping up really screwed things. Lesson learned - iOS really does not like this sort of popup with editing.

Gut things yet again and go with a UIPopoverController on the iPad and navigation to a UIViewController on the iPhone. Can't say I am super happy with the iPhone version but it works and popping up the keyboard does not screw anything up.

Next up was the menu. iOS 7 has a bug. If you have too many items in a UIActionSheet on an iPhone you can't tap the top most item if it happens to cover the main navigation area. Works fine on iOS 8 but broken on iOS 7. UIActionSheet expects just a few items.

So I found a popup menu that allows up to 9 items per screen and you can swipe to scroll and see more. It is call btSimplePopUP. Now I should have known that someone using two menus - btSimplePopUp and btSimplePopUP - in the same directory structure was going to be iffy. The demo screens look nice though. I put in the code and I get the menu to appear but with a black background. What? It is not blurring out my UIViews, just blanking them out. Then I look for known issues and it turns out the control does not work in landscape which is a requirement for me.

Punt that control. I am now looking at KxMenu which seems to be working in portrait and landscape and takes up a lot less screen space than UIActionSheet. Hopefully it will be the solution.

Lots of GitHub projects lose support. iOS 8 was a big change and it takes some recoding especially with custom controls due to the changes Apple made. Stinks people don't have the time to keep things updated. Even worse when I waste the time trying to get them to work. I need to start looking at the known issues first. Anytime it does not support landscape I am not going to use it. Hopefully they also list if there is iOS 8 support issues as well.

Tuesday, January 20, 2015

MacOS has lost its stability

I do both iOS and Android development thus I have a MacBook Pro has my main development device. I have had one for the last 3 years. Since upgrading to Yosemite it has become the least stable development box I have worked on in a long time.

I leave the machine on and lock / put it to sleep when I am away from my desk. This may be going to a meeting, going to lunch or home for the evening. When I come back from lunch there is a very good chance, 2 out of 5 days, that the machine has rebooted. This also may happen during the day when I am actively working on the machine but that is pretty rare. The sleep cycle seems to be the main trigger.

This is an upper end machine with an SSD drive so the reboot does not take too long but it does interrupt my day and it may happen a couple of times a day, when I come in, after lunch and then maybe after a meeting. Yes, all the programs restart but they don't show up in the same position or with the same data showing. Sublime text appears on screen 1 instead of screen 2. Finder does not have the same tabs open. Chrome might be annoyed in some manner. I will not have the tabs in iTerm on the same directories.

This was never a problem in the past. The MacBook just worked. Now it reboots and has issues with DNS getting lost part way through the day as well. Ping will not find a machine but NSLookup will.

I also have a Dell PC that is used for my Windows activities running Windows 8.1. I leave Outlook, Hipchat, Sublime Text, Chrome and a few other things running on it as well. I do a lot of my graphics work on that machine because Paint.NET is free and pretty darn full featured. We also use TFS for version control and I do that work on that machine along with anything I need to do in Visual Studio including C#. I don't have a massive love for Windows but at least that machine is only rebooting when it needs to do updates, which does occur too often for an OS, but otherwise it is there ready to go.

iOS has become less stable as well. I think Apple needs to stagger the releases instead of trying to do MacOS, iOS and iOS hardware release all at the same time. I bet their QA department is hammered during that yearly cycle and it is really starting to show. I love new and exciting things but they need to be stable. Right now Yosemite is not stable and is highly annoying.

Tuesday, January 13, 2015

Why I have given up on Interface Builder and Story Boards

I just ran into another case where Interface Builder did not allow me to do what I wanted to do and I finally just gave up and pulled everything but the first view controller from the storyboard. This is the story of how I got to this point.

My first iOS app was one of "finish this". Another developer who was no longer with the company had developed the app. I had the job of finishing the app and converting it to Android. I already knew Java and had written an Android app that was in the store. The iOS version used NIBs as this was back in the iOS 4 timeframe.

I continued down the NIB path and converted the app to be universal with special code for iPad layouts. There was special cases for landscape vs. portrait on one of the screens as well. Seemed to work OK but it was a fairly straightforward app.

I worked only on Android apps for a some time before my next position where I did both iOS and Android work again.

The next iOS app I worked on was written by another developer and he used storyboards. Still using the old style layouts with pixel perfect positioning. I kept the storyboards in place seeing some of the advantages of using them and added the iPad storyboard side of things. I liked how much easier it was to get things going, used segues and like the idea of seeing the program flow in a visual designer. Took quite a bit of web research to understand how it all tied together and a lot of clicking on tabs in IB to find all the secret nooks and crannies where you could set things.

I did a couple of other apps for the company that I got to write from scratch. I used the new found storyboards for them as well. Sadly none of these apps went to market as they never finished the server side of the work. Lots of pretty apps to demo at sales meetings but they were just demos.

For my current job I am again getting to write the app from scratch. I am doing the same with the Android side of things. I started out using storyboards and it was time to get into autolayout. Since I have been doing Android work and I have also done a lot of Java desktop work I have a solid understanding of doing layouts that scale.

I dove into autolayout and found it rather confusing. It appears to me to be written in the land of academia instead of the land of real world programming. One layout to rule them all no matter how you have to force things into it. Very verbose in one code only format and very terse in the other. If you do it in Interface Builder then you just have to know how to do things. Click here, Ctrl + Click here, set up constraints, delete them, set them up again, have them conflict, pull hair. Always something wrong and it get really bad when you have a complex layout. For a company that prides itself in UI and UX I must say IB is not a good reflection of that goal.

After fighting it and working with other iOS devs over chat I found Masonry and switched to that. Yes, it is code and not WYSIWYG but I could create complex layouts and have them work. I could do different layouts for iPad and iPhone and follow them logically. I still have storyboard layouts but most of them were empty as the code created the real layout. I was just using them for segues and to see program flow. That was until yesterday.

There I was back in Interface Builder. I just wanted a UITableView to move down one level, to have another UIView as its parent. IB fought me tooth and nail. I could and a UIView to the list but it would not show up under the UIViewController no matter how I dragged and dropped and clicked. I then said screw it and deleted that entire view controller and created a new one where I could re-add the UITableView but then all my segue links broke and all the IBOutlets into the code broke and I would have to do it again for the iPad storyboard and all the work went on and on. Plus Xcode crashed more than once while I was in it doing simple things.

Storyboards end up sucking pretty quickly. There is not enough screen room to see your iPad layouts. You get to see one scene at a time. Sure you can zoom out but the minute you edit something it zooms back in. Just opening a storyboard seems to trigger Xcode into thinking there was a change. If you look in the XML you will see it changed x = 4.0 to x = 3.999999999 or something just as stupid. Everything I did I had to do twice, once for iPhone and once for iPad. The IDE does not tell you if you forget to wire up a UIView to an IBOutlet. Objective C does not care if you send messages to a nil object. Moving a UIView can screw up the whole layout quickly. You can't see all the constraints in one place, you have to look in each level of the layout to see them and they are terse and unrelated to each other. When you try to Ctrl+Drag a UIView into the code you hardly can see anything else on screen.

I gave up. IB was fighting me not helping me. I converted all the code to Masonry and I was able to control that layout exactly. I had to move all the segue processing in code as well. It took me all day to get my code back to where it was before but now I am in control of all of it.

I don't have to do things twice. iPad and iPhone both work from one code base. I may have some if statements in code to tweak layout for iPad but I don't have to double layout it out in a crappy UI editor called IB and I don't have to double connect every UIView to a IBOutlet.

I can move a control around in my layout by changing a few lines of code instead clicking a bunch of times in IB and having it get pissed and redo other constraints.

I can name my controls so when I do get log messages about my layout being screwy I know exactly which UILabel it is mad about instead of guessing.

Another issue that bit me, I fixed, that bit me again and I fixed the right way arose. I needed a second line for the title area on iPhone. iPad has enough horizontal space to not need this. I was using the navigation prompt property which adds a second line of text to the title area. On Android I could use title / subtitle to do same thing but on Android this requires no extra vertical space.

How did this bite me twice? A number of months ago I wanted to add a UILabel above my UITableView but I could not due to same issues that I just covered, I could not get the UITableView hosted by another UIView. Thus I used the prompt property. It worked OK. After the conversion away from storyboards everything in this UIViewController aligned just fine the first time I displayed it but when I tapped a table row and moved to the detail screen then back to the table screen setting the prompt caused the navigation area to grow and it covered up part of my table. Rotating to landscape and back would fix it. I tried all sorts of relayout, needs display, calculation of offsets etc. and could not get it to work. Why autolayout would not stay in sync is beyond me but I got sick of fighting that.

Then I remembered what I originally wanted to do - put a UILabel above the UITableView on iPhone only. Now I am in control as I am using Masonry. Put the UILabel in place and changed all code references from prompt = to promptLabel.text = and I have a working layout the way I originally wanted.

I have no plans use prompt again due to it screwing up layouts and I will not be using storyboards or Interface Builder either. They just are not stable and cause more trouble than they are worth. I also do most of my work in AppCode instead of Xcode as AppCode does a much better job in a lot of areas. Better editor, much better refactoring, GIT actually works properly and it is stable. I have had it crash on me once in the two plus years I have been using it.

The other added benefit - I can take my code and drop it in another project and it will work. I have no dependencies on copying the layouts twice and having to manually reconnect every single freaking UIView to an IBOutlet. My code is self contained. It lays itself out and knows how to talk to all of its controls.

Goodbye IB and storyboards. I don't miss you.