Testing is good practice, but sometimes you may get into trap. Opposite to Objective-C, in Swift 2.x you don’t need to add each file to your test target, even more – you should not do this at all!

Using Swift 1.x developers had to make every testable class and methods public, which was very annoying. Now, all you have to do, is use:

@testable import ProjectName

in each of your test files (this is required for both unit testing and UI testing). But there is one catch – what if your project name contains spaces like “My First Swift Project”? Fortunately there is simple solution, in most cases just replace space with underscore, but if you want to be sure, go to your app’s target, then “Build settings”, and search for “Module name” – this is string you should use in import.

Swift unit/UI testing

Sooner or later you will face with “Invalid predicate: nil RHS”. What does it mean? Fortunately solution is very simple, somewhere in your code, you are using NSPredicate with “CONTAINS” while your search text is nil. All you have to do is make sure to check and validate text entered by user.

The common mistake is using more then one “@” placeholders, while having only one parameter.

I pretty sure all of you know how to do it in Objective C, but in Swift 2.x this is even simpler.

First you need to subscribe to  keyboardWillShow and keyboardWillHide events, which is achieved a bit different then in ObjC:

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyViewController.keyboardWillShow), name:UIKeyboardWillShowNotification, object: nil);

NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(MyViewController.keyboardWillHide(_:)), name:UIKeyboardWillHideNotification, object: nil);

Since we are using Swift 2.2 here, note different #selector. Where “MyViewController” is you view controller class name. Next and last step is to add functions for handling screen movement:

func keyboardWillShow(notification: NSNotification) {
        let keyboardHeight = notification.userInfo?[UIKeyboardFrameBeginUserInfoKey]?.CGRectValue.height
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.window?.frame.origin.y = -1 * keyboardHeight!
            self.view.layoutIfNeeded()
        })
    }
func keyboardWillHide(notification: NSNotification) {
        UIView.animateWithDuration(0.1, animations: { () -> Void in
            self.view.window?.frame.origin.y = 0
            self.view.layoutIfNeeded()
        })
    }

This will work without adding any scroll views, just out of the box.

Sooner or later you will face with changing back button title in navigation bar. This may seem simple. But after few hours trying to change this damn text, you will change your mind. I have no idea why this is designed this way, but answer for question “How can I change back button text in current view controller?” is – you cannot. So how to do it without overriding whole navigation bar? All you have to do is change title of backBarButtonItem in PREVIOUS view controller. But there is another catch – you can’t just do :

self.navigationItem.backBarButtonItem.title = @"" 

becouse this won’t work. Instead of this, you need to:

UIBarButtonItem* backBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:@"" style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationItem.backBarButtonItem = backBarButtonItem;

And keep in mind – this has to be done in PREVIOUS controller, not the one you need to change your back button text. The alternative is to give up on native back button and create your own with:

UIBarButtonItem *backButton = [[UIBarButtonItem alloc] initWithTitle:@"My back button" style:UIBarButtonItemStylePlain target:nil action:nil];
self.navigationItem.hidesBackButton = YES;
self.navigationItem.leftBarButtonItem = backButton;

This can seem trivial, but I saw lot of people complaining about not working tint color when using UIImage. Here is the proper way:

UIImageView *imageView = [[UIImageView alloc] init];
UIImage *image = [UIImage imageNamed:@"my_image"];
imageView.image = [image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
[imageView setTintColor:[UIColor redColor]];

The point is – “imageWithRenderingMode” method just returns new image with rendering mode set, it does not changes anything in image object itself.

If you are new to iOS programming this may take you a while to found out. But I’m here to help so will give you ready to use solution. So you have two (or more) view controllers (UIViewController) and one of them should show list of items, second one details of selected item? Well, solution depends on the way you are doing transitions betweeen controllers.

Continue reading

If you just started playing with CloudKit, probably you will see that error trying to implement custom synchronization. Why need custom synchronization? Because receiving push message each time something changed in your cloud will be annoying. So probably you started with:

and this is a place where you will see such error. Why this happens? Becouse you cannot fetch changed records for default zone. This applies both private and public cloud. So what to do? You need to create new zone before you will save anything to database:

After refreshing your cloud dashboard you will see your zone in “Private data” section. Now you can change zoneId to:

Of course you can use whatever name you want, this will also allow you to logically group records. Now in fetchRecordChangesCompletionBlock you should see:

And the second info means there is no error, and in first you have your CKServerChangeToken you need to save somewhere for next call.

Recently I had an NSDate object which had to be convered to unix timestamp and added to NSDictionary. But, what a surprise – I can’t add anything which is not object, and time_t is C element. So what to do? Solution as usual is very simple:

As result of this snipped, you will have NSNumber object in your dictionary instead of NSDate

Recently I noticed this may not be such obvious, but if you need to know when user pauses video or resumes playback, just use:

and since there are constants like kYTPlayerStatePlaying or kYTPlayerStatePaused  you can just do:

but to make it work, do not forget to set proper delegate:

and add YTPlayerViewDelegate in your header file for view controller:

There are also few other useful methods:

so there is pretty easy to handle most of player behavior.