"ios" entries

WORA Can Be Better Than Native

Targeting the highest common denominator

Some would claim that native is the best approach, but that looks at existing WORA tools/communities, which mostly target cost saving. In fact, even native Android/iOS tools produce rather bad results without deep platform familiarity. Native is very difficult to properly maintain in the real world and this is easily noticeable by inspecting the difficulties we have with the ports of Codename One, this problem is getting worse rather better as platforms evolve and fragment. E.g. Some devices crash when you take more than one photo in a row, some devices have complex issues with http headers, and many have issues when editing text fields in the “wrong position”.

There are workarounds for everything, but you need to do extensive testing to become aware of the problem in the first place. WORA solutions bring all the workarounds and the “ugly” code into their porting layer, allowing developers to focus on their business logic. This is similar to Spring/Java EE approaches that addressed complexities of application server fragmentation.

Read more…

What Does iOS 7 Mean for Developers?

UI dynamics, multitasking, maps, and more

iOS 7 is here and we are all very excited. But, as programmers, this isn’t a time to celebrate. This is a time to be concerned. About what, you ask? API Differences is all I can say. How does iOS 7 affect our apps and what is there for us to learn? The iOS SDK is a huge collection of APIs and many of us won’t have time to play with all of the APIs. So we need to be selective about what APIs we use and how efficiently we plan to use them. In this post, I’m going to briefly tell you about some of the new APIs that you need to keep an eye on in iOS 7.

Additions to iOS 7

UI Dynamics
These are all the Dynamics APIs that Apple has added to UIKit. Start by learning about the UIDynamicAnimator class and take it from there. That is the key to UI Dynamics.

Read more…

What Do the New iPhones Mean For Developers?

Sometimes earth changing moments come in fingertip-sized packages

Well, the media feeding frenzy that is an Apple product release press conference is over, and the whelmingness is definitely on the under, rather than over side. Part of the lack of drama is that, these days, it’s almost impossible for Apple to keep anything under wraps. There are just too many hands in the supply chain, too many carriers to coordinate a launch with, and too many opportunities for a stealthy cameraphone snapshot of a box or component. Add in patent and FCC filings, and your barber can tell you what’s going to be unveiled, at least a week or less from the event.

Read more…

Upward Mobility: If I Were King of XCode

Even a great development environment has room for improvement

As the not-so-mysterious September 10th Apple event approaches, it’s widely anticipated that the final version of iOS 7 will be released at the same time. Along with it will come a new version of XCode. While XCode is a pretty awesome development environment (in my opinion, at least), there are a few things that just irk the heck out of me. So, if anyone at Apple happens to be listening, here’s my laundry list of things I’d like to see fixed.

Read more…

Keeping Apps in the Air With TestFlight

Long a development tool, TestFlightApp wants to move into analytics

For most iOS developers, TestFlightApp has become the go-to tool when they want to distribute a development build to testers. For those not familiar with the site, you can register applications, and then upload IPA files signed with either a development or AdHoc profile, either manually or using a desktop app that integrates directly into XCode.

Once uploaded, your testers can be automatically notified via email that there is a new version of the app available, and download it directly onto their device without having to use iTunes. It can even capture device IDs for new users (or new devices for existing users), and export them for use in the Apple developer portal.

You can also add code to have the running app check in with TestFlight. You can add “checkpoint” flags, ask survey questions (“why did you come to this page”), and have console logs and crash reports automatically uploaded to the site.

The problem is, once you’re ready to ship a production version, you have traditionally had to turn everything off and make sure that the Test Flight library was not linked in to the app. This has meant that there was no way to capture crash data from customers running the app. But now that’s changing.

Recently, TestFlightApp announced that it was now OK to leave the library in copies of your app uploaded to the App Store, and to have the app check in with TestFlight. Why the change? Probably because it is needed to support FlightPath, their new analytics tool. FlightPath seems to want to be the Google Analytics of mobile, allowing developers to see how customers use their app and offering demographic data.

FlightPath is likely to be the path that TestFlightApp takes to start monetizing their service. TestFlightApp has always been free, but there has been no pronouncement about whether FlightPath will follow that same model. It is currently in an open beta, so we may have to wait and see what the pricing model for the final product is. Of course, by then, all those beta users will have become hooked.

One major caution for people intending to keep TestFlight in their production code, watch out for leakage of private data! Many test builds spit out tons of information to the console. At times, I’ve had everything going back and forth to a server dumping itself onto the log. If you don’t disable that in the shipping code, you could be accidentally capturing all sorts of sensitive data, including credit cards, HIPPA restricted information, etc. So make sure that you have compiled out (or disabled) anything like that in the production build (which you can test with an AdHoc profile.)

Upward Mobility: Black Magic Method Swizzling

Great hacks, great responsibility

This week, we’re going to depart from the basics, and talk about a piece of Objective-C black magic that, when used properly, can be a powerful tool. However, used incorrectly, it can cause devastation on a biblical scale. Let’s talk Method Swizzling.

Image that you have an app just about ready to go into the store, and your UI designer suddenly decides that all the UIButtons should use a different font.  Unfortunately, you have hundreds of them scattered over dozens of XIB files. Sure, you could go through and change each one by hand, but what happens if he changes his mind again?

Wouldn’t it be nice if you could programmatically force all the UIButtons in your app to use a new font? Maybe we can do it with a category? If we override the initWithCoder and initWithFrame methods of UIButton, we can call super and then set the font explicitly, right? Unfortunately, no, because super isn’t available in an overriden category method. But there is a way we can do it, using swizzling.
Read more…

Upward Mobility: Overly Defensive Programmer

Sometimes, the best defense is a good offensive core dump

By now, most meme-aware internet surfers have encountered Overly Attached Girlfriend  (and the Rule 63 counterpart, Overly Attached Boyfriend.) What isn’t as well known is that they have a brother, Overly Defensive Programmer (ODP, for short.)

ODP is a mobile developer who lives in the constant fear that the server-side folks are going to subtly change an API out from under him, making his app crash. To avoid this, he puts in code like this:

NSError *error;
NSDictionary *responseData =
     [NSJSONSerialization JSONObjectWithData:data 
                      options:0 error:&error];
if (error != NULL) {
   // All sorts of logging code, followed by returning 
   // from the call silently, swallowing the error
}
if ((responseData[@"payload"] != NULL) &&
    (responseData[@"payload"][@"objectId"] != NULL)) {
     self.objectId = 
       ((NSNumber *) responseData[@"payload"][@"objectId"].intValue;
}

We’ve all seen code like this. The developer didn’t want to accidentally cause a fatal error by trying to get the objectId parameter if the payload was missing, or to try accessing the objectId if it was missing. And if objectId is an optional field, this is totally the way to go.

The thing is, objectId sounds like it is probably a critical piece of data, without which the application will fail to operate properly. You want the application to crash if it goes missing, because that means it will crash during QA testing, rather than silently ignoring the problem and possibly malfunctioning in a way that QA misses.
Read more…

Upward Mobility: To Storyboard or Not to Storyboard

That is the question for iOS developers

Storyboarding was introduced in iOS 6, and it offers a way to consolidate all of your disparate Interface Building files into a single overarching whole. Although it’s tempting to jump on board and use it just because it’s the new thing, there are some things to keep in mind.

  1. Storyboards require you to make the jump to iOS 6; there’s no backwards compatibility for earlier versions. While this isn’t as much of a factor as it was a year ago, if you have legacy iPad 1 customers, you’re going to be locking them out of your app if you move to storyboarding.
  2. Having all your XIB files consolidated may sound good, but if you have a lot of them, you can end up with a new storyboard that’s so big that it is unwieldy.
  3. Storyboards are more than just a consolidation move; you also have to adopt a whole new programming style to move between your screens. Instead of explicit pushes and pulls off of view controller stacks or opening of modals, you are firing off segues that cause new view controllers to be created and transitions to occur.

The last point isn’t a bad thing per say. It’s a much more MVC-like paradigm: for example, where the overall controller knows what a transition means, and the individual views are only responsible for requesting a transition. It’s also much more like the way that Android does things. But it’s a different style of programming from traditional iOS UI development, and has a learning curve associated with it.
Read more…

The Ever-Changing Landscape of Mobile Gaming

Unity, iOS 7, and the Quest for a Great Mobile Game Experience

Jon Manning (@desplesda) and Paris Buttfield-Addison (@parisba) talk with me about where mobile gaming is going in the next 12 months.

Key highlights include:

  • Game-specific APIs and standardized gaming accessories in iOS 7 [Discussed at 0:20]
  • Android needs to catch up [Discussed at 1:55]
  • Are tablets putting handheld consoles from Nintendo and Sony out of business? [Discussed at 3:13]
  • Independent developers vs big game studios – fight! [Discussed at 4:53]
  • Unity is now free for mobile game development [Discussed at 6:02]

You can view the full interview here:

Read more…

Rotating a UIView in 3D

OSCON 2013 Speaker Series


Jon Manning (@desplesda) and Paris Buttfield-Addison (@parisba) are co-founders of Secret Lab and authors of the forthcoming Learning Cocoa with Objective-C, 3rd Edition. They’ll be speaking at OSCON this week in Portland, OR. Here they explain how to rotate a UIView in 3D on iOS.


One of the simplest visual tricks you can do in iOS is to make a part of your UI pretend to be a 3D object. We’ve found that this is an excellent way to add some life and visual interest to both apps and games.

Below, you’ll learn how to make a view rotate in 3D and have a perspective effect.

phone

First, your project needs to use the QuartzCore framework.

Next, when you want the animation to begin, you do this:

CABasicAnimation* animation = [CABasicAnimation
animation WithKeyPath:@"transform.rotation.y"];
animation.fromValue = @(0);
animation.toValue = @(2 * M_PI);
animation.repeatCount = INFINITY;
animation.duration = 5.0;

[self.rotatingView.layer addAnimation:animation forKey:@"rotation"];

CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0 / 500.0;
self.rotatingView.layer.transform = transform;

To stop the animation, you do this:

[self.rotatingView.layer removeAnimationForKey:@"rotation"];

How It Works

CABasicAnimation allows you to animate a property of a view from one value to another. In the case of rotating a view, the property that we want to animate is its rotation, and the values we want to animate from and to are angles.

When you create the animation using [CABasicAnimation animationWithKeyPath:], you specify the property you want to animate. In this case, the one we want is the rotation around the Y axis.

CABasicAnimation* animation = [CABasicAnimation
animationWithKeyPath:@"transform.rotation.y"];

The animation is then configured. In this example, we made the rotation start from zero, and proceed through to a full circle. In Core Animation, angles are measured in radians, and there are 2 * π radians in a full circle. So, the from value and to value are set thusly:

animation.fromValue = @(0);
animation.toValue = @(2 * M_PI);

Next, the animation is told that it should repeat an infinite number of times, and that the full rotation should take 5 seconds.

animation.repeatCount = INFINITY;
animation.duration = 5.0;

The animation is started by adding the animation to the view’s layer, using the addAnimation:forKey: method. This method takes two parameters: the animation object that you want to use, and a key (or name) that the animation should be referred by.

Don’t be confused by the similarity between the “key” that you use when you add the animation, and the “key path” you use when creating the animation. The former is just a name you give the animation, and can be anything; the “key path” describes exactly what the animation modifies.

[self.rotatingView.layer addAnimation:animation forKey:@"rotation"];

The last step to this is to give the rotating view a little perspective. If you run the code while omitting the last few lines, you’ll end up with a view that appears to horizontally squash and stretch. What you want is for the edge that’s approaching the user’s eye to appear to get bigger, while the edge that’s moving away from the user’s eye to get smaller.

This is done by modifying the view’s 3D transform. By default, all views have a transform matrix applied to them that makes them all lie flat over each other. When you want something to have perspective, though, this doesn’t apply, and we need to override it.

CATransform3D transform = CATransform3DIdentity;
transform.m34 = 1.0 / 500.0;
self.rotatingView.layer.transform = transform;

The key to this part of the code is the second line: the one where the m34 field of the transform is updated. This part of the transform controls the sharpness of the perspective. (It’s basically how much the z coordinate gets scaled towards or away from the vanishing point as it moves closer to or further from the “camera“.)

As you can see, adding 3D and perspective effects isn’t terribly difficult, but the results can provide an excellent payoff in terms of user immersion.