Tuesday, April 14, 2015

Fixing Xcode 6.3 (iOS SDK) Error: Could not load NIB in bundle

After the recent update of Xcode to version 6.3 iOS developers reported to encounter exceptions of kind


Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: Could not load NIB in bundle: ...

followed by the path to the running iPhone or iPad application, and the name of the NIB file the it was trying to load. These exceptions appear to fire at runtime only, not at compile time. So make sure you test your iOS applications completely after building them with Xcode 6.3!

The reason for this issue seems to be a bug of Xcode 6.3 when compiling XIB files using size classes. Size classes is a concept introduced with iOS 8 which enables you to define view layouts for different UI orientations and different iPhone and iPad devices within a single Interface Builder document. A very good introduction to size classes is given at adaptioncurve.net.

So let's have a look at a little example to elaborate the problem! 

We have an Xcode project with the deployment target set to iOS 7 and Universal device support:











We have two XIB files: TestSizeClasses.xib is targeted to iPhone and iPad. TestSizeClassesIphone~iphone.xib is named according to Apple's conventions to be targeted to iPhone only:










Both XIB files have size classes enabled:















After compiling these files with XCode 6.2, and running them in Simulator let's have a look at the NIB files created at compile time. You will find these NIBs in your user directory under a path of this structure:
~/Library/Developer/CoreSimulator/Devices/<cryptic_device_number>/data/Containers/Bundle/Application/<cryptic_app_number>/<app_name>.app

In order to identify the correct cryptic number directory, just sort directories by modification date and choose the last modified one.

Xcode 6.2 created these three NIB files:





TestSizeClasses.xib was split into two device specific NIB files, but TestSizeClassesIphone~iphone.xib was compiled to a single, iPhone specific NIB file because the '~' - part of the file name signals to the compiler that we care about device specific layouts by ourselfs. So everything is fine!

Now lets compile the same files with Xcode 6.3 and have a look at the results:





As you can see, Xcode appends another '~iphone' part to the name of TestSizeClassesIphone~iphone.nib, although we wanted it to leave our file name alone! So this is the bug in Xcode 6.3 XIB processing which will lead to runtime 'could not load nib' exceptions when your app tries to load the badly named nib file. 

The bug will haunt you when you have size classes enabled for a XIB file, and the deployment target of your Xcode project is set to something earlier than iOS 8. Because size classes are only supported in iOS 8.0 and later, Xcode will compile the old device specific nib files automatically for older iOS versions. It doesn't matter whether your app is universal or targeted to iPad or iPhone only. As soon as you name a XIB device specific using the '~', your app will crash.

Now that we know the reasons for this exception, we have four options to handle it:



Option 1: Target to iOS 8.0 or later 

The simplest option would be to target your app to iOS 8 or later, thus the device specific NIB files would just not be created. But if you want to support older iOS versions, this is not an option for you.

Option 2: Use storyboards instead of  XIB files

If you can afford to make the effort, migrate all your XIBs to storyboards. These will be compiled correctly by Xcode 6.3.

Option 3: Disable Size Classes

When you disable size classes for a XIB file, Xcode will force you to target this file to a specific device and will remove all data it thinks will not be of use to represent this device:












So choose this option only when you absolutely trust in that Xcode will not remove anything you need from your XIB files. As a rule of thump: If all layout constraints in a XIB apply to all size classes, you are safe. If different constraints apply to different size classes, think twice!

Option 4: Handle device specific XIBs in code

This is the less destructive of all options and it is not as expensive to implement as it might seem! All you have to do is to name your XIB device specific by avoiding Apple's naming conventions (the '~'), and add very few lines of code to load the correct NIBs.

So we rename our TestSizeClassesIphone~iphone.xib to TestSizeClasses-Iphone.xib. We create another TestSizeClasses-Ipad.xib to cover all devices. And we create a  single TestSizeClassesViewController, which we set the file's owner of both XIB files:










After compiling the code, we'll find the following NIBs:









As you can see, Xcode created both, an ~iphone version and an ~ipad version of all of our NIB files. Now all we have to do is to tweak our Objective-C code to load the correct NIB version per device.

So open TestSizeClassesViewController and implement its init method to load device specific nib files:

- (id)init
{
    if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
    {
        return [self initWithNibName:@"TestSizeClasses-iPad" bundle:nil];
    }
    else
    {
        return [self initWithNibName:@"TestSizeClasses-iPhone" bundle:nil];
    }

}

Do the same in all places of your code where the view controller is instantiated directly using initWithNibName:

...
TestSizeClassViewController* sizeClassController;    
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad)
{
    sizeClassController = [self initWithNibName:
        @"TestSizeClasses-iPad" bundle:nil];
}
else
{
    sizeClassController = [self initWithNibName:
        @"TestSizeClasses-iPhone" bundle:nil];
}

...

This way, the app will load the TestSizeClasses-Iphone~iphone.nib and TestSizeClasses-Ipad~ipad.nib only. It will ignore the TestSizeClasses-Iphone~ipad.nib and TestSizeClasses-Ipad~iphone.nib.


That's all there is about this Xcode issue. Now it's up to you to decide which of the four options is the best for your needs.




Monday, March 9, 2015

One more thing.. - *** The all vintage myWatch!!! ***


  • The smart watch that was always there!
  • Operates without a mobile phone in your pocket!
  • Displays current time on its 10k++HDSuperDuperDensityRealityViewRetina(TM)-Display!
  • Comes with pre-installed calendar app to display current date and day of week - all on a distinct tile!
  • Makes realistic tick-tock noise with it's built-in VintageSound(TM) Signal Processor!
  • Runs 4+ years without recharging!
  • DIY replaceable battery pack
  • Comes with built-in AnalogueCrown technology which lets you adjust time, date, and day of week in real time!
  • Covered by saphire glass with a single rounded edge!
  • Features Swipe-To-Clean gesture!
  • Knows your pulse - but won't tell!

This changes nothing - again!

http://www.joobikplayer.com

Tuesday, March 3, 2015

How iTunes Match does (or does not) sync Video Playlists to iPhone, iPod, and iPad



When Apple first introduced iTunes Match in 2011, everyone was excited: Eventually there was an easy way of getting all those iTunes media files to synchronize between all your Macs, PCs, iPhones, iPods, and iPads seamlessly via iCloud! But after a few days of using it it became obvious that there were some very annoying drawbacks and restrictions. And many of them do still exist today.

iTunes Match works best when used with music files (audio and music videos) purchased at Apples iTunes Store. It does not feel quite as comfortable with oder media kinds, especially videos. It works even worse with playlists. And it (almost) refuses to operate on media not available from the iTunes Store.

So the ultimate challenge for the media enthusiast these days is to get this playlist of home videos synced from iTunes to the iPhone via iCloud! And I will try to show you in this post how this can be achieved.

So lets start with the facts I found out during my research about playlists and videos in the realm of iTunes Match and iCloud. All these findings are based on iTunes 12.1 on OS X Yosemite and iOS 8.1.3 on iPod Touch 5g. There's no warranty that all or only some of these findings can be reproduced by everyone with the same or different hardware and software configuration:


Finding 1: There's almost no official documentation

You can check which media types iTunes Match will sync in your country at all. And somewhere in the F.A.Q-section of this page you will find the statement, that "playlists with videos, voice memos, or PDF files will not sync."
That's it! And it's not even half of the truth, as we will see later.

Finding 2: iTunes Match behaves different on an iOS device and on iTunes 

When you turn on iTunes Match in iTunes on your PC or Mac, it is still possible to select videos and playlists for local synchronization to your iOS device. iTunes will even try to tell you that these playlists are there:



BUT: When you turn on iTunes Match on an iOS device, only the videos are available in the original iOS Video or Music App - The playlists are not! 
The reason: When iTunes Match is turned on on an iOS device, this device will show only playlists available on iCloud. So in order to make some playlists appear on your device at all, you must have iTunes Match enabled on at least one of your desktop computers. Then you can check in iTunes easily if a playlist synced or not:


When the cloud symbol is struck through, the item is not on iCloud.


Finding 3: iTunes Match handles Music and Music Videos different from the Rest

Short side note: Everything just said above is not true for Music and Music Videos. These cannot be synced manually when iTunes Match is turned on on your iOS device:



Finding 4: iTunes Match will only sync media available from the iTunes Store

You will only get your media files into iCloud, if the iTunes Store offers them for sale in your country. It doesn't matter whether you purchased them from Apple or not. When iTunes Match is turned on, your media library will be scanned and iTunes tries to match each of your media files with the Store. It is Apple's secret how a match would be recognized. But you can definitely say that there is no chance to ever get any of your home made videos into iCloud. You will have to sync all of these files locally from your computer to your iOS device.
Whether a playlist is synced to iCloud depends on the playlist type and sync status of the items it contains. Details will be discussed in Finding 7.

Finding 5: It's cumbersome to check your iOS device for playlists synced to it

While you can use the native iOS Video App to check for all videos available on your device (whether from iCloud or not), this app will not reveal any of your playlists.
The native iOS Music App will show you all playlists available on your device. Remember that - as said in Finding 2 - all of these playlists reside on iCloud. You won't be able to access local playlists with iTunes Match turned on. While all playlists are listed here, only music and music video playlists can be played from the iOS Music App. All other playlists appear to be empty:



Use Joobik Player to view the content of all playlists and play them on your iPhone, iPod, or iPad:


In order for a playlist to appear in Joobik Player, the playlist itself must be synced to iCloud, but the media files must reside physically on your iOS device. I.e. if a playlist contains items from iCloud, at least one of these items must be downloaded from the cloud to your device using the native iOS Video or Music App. If a playlist contains items not available from iCloud, these items must be synced locally from iTunes to your iOS device. Detailed instructions on how to do this are given at the end of this post.

Finding 6: iTunes Match might not forget

When I turned on again iTunes Match on my iPod after several months of using only local synchronization, I was surprised to see appear several playlist that where not on my iTunes-Match-enabled Mac. The only explanation I see for this behaviour is that these lists must originate from an old computer, which I don't own anymore. So iTunes Match becomes even more confusing, when more than one Computer is involved in the synchronization pool. But this might be a topic for another blog post..


Finding 7: iTunes Match handles Smart Playlists different from ordinary Playlists

This is the most important finding because it will lead us to the solution of how to get complete playlists synced to an iOS device with iTunes Match turned on!
An ordinary playlist will sync to iCloud as long as it contains only tracks that sync to iCloud as well. So adding a single home video to an ordinary playlist will remove the whole list from the cloud in iTunes 12.
With Smart Playlists it's different: A Smart Playlist doesn't care about the iCloud status of the items it contains. A Smart Playlist containing only ineligible items will sync to iCloud anyway and, thus, appear on your iOS device as an empty playlist. A Smart Playlist becomes ineligible for iCloud sync only when you add the reference to another playlist to the smart playlist rules:



Putting it all toghether

When it's about music and music videos, you will depend on Apple's grace: Either they sync to iCloud or they don't. But all other media types can be tweaked by mixing iCloud Smart Playlists with files synchronized locally:

Create a smart playlist that syncs to iCloud as described in Finding 7. If you cannot find smart rules sufficient to group all desired tracks into one smart list, just create an ordinary playlist containing these tracks and add an unique tag to the comments field (or any other meta data field) of each of the tracks on this list:



Create a Smart Playlist referencing this unique tag:


Now the Smart Playlist itself will sync to iCloud, while the tracks will not:


Sync the Smart Playlist locally from iTunes to your iOS device:


Play the playlist with Joobik Player:



If you want to modify the iTunes Playlist on your iPhone or iPad, just copy it to a Joobik Playlist. With Joobik Playlists you can add, remove, and rearrange tracks.