PIXEL
DOCK

I like the smell of Swift in the morning…

How to remove an option from a NS_OPTIONS bitmask

Posted: | Author: | Filed under: Objective-C | No Comments »

I really like the NS_OPTIONS macro. I think it is a neat and tidy way to store multiple boolean values in one bitmask.

So for example if you have a car object that stores the features a customer ordered for his new car you could define something like:

typedef NS_OPTIONS(NSInteger, Feature) {
    FeatureNavigationSystem = (1 << 0),
    FeatureHeatedSteeringWheel = (1 << 1),
    FeatureParkDistanceControl = (1 << 2),
    FeatureSunRoof = (1 << 3),
    FeatureConvertible = (1 << 4)
};

Now you can store the features that a customer selected in one NSInteger (or in this case 'Feature') value using the bitwise OR operator (|):

Feature selectedFeatures = FeatureNavigationSystem | FeatureParkDistanceControl;

To check if a customer has selected a certain feature you use the bitwise AND operarator (&):

if (selectedFeatures &= FeatureNavgiationSystem) {
    // user has selected navigation system
}

Now there might be a situation where you want to remove a feature from the bitmask of selected options. In my simple example that might be the case when a user selects the option FeatureConvertible. If the customers does that, you might want to make sure that the feature FeatureSunRoof is not selected (because obviously a convertible does not have a roof).

So you want to remove the option FeatureSunRoof from the selected options while leaving the rest of the selected options as they were. This is where our friend the bitwise NOT operator (~) comes into play:

selectedOptions &= ~FeatureSunRoof

This removes the FeatureSunRoof from the selectedFeatures bitmask.

How to get rid of the padding / insets in an UITextView

Posted: | Author: | Filed under: iOS | Tags: | 15 Comments »

Sometimes you want to display some text that contains an email address, an URL, a phone number, an address or a date. Of course you want to make these text parts interactive so that a user can tap on an URL and directly go to the linked webpage, or make a phone call when he taps on a phone number, etc.

Implementing that is really easy. You just use an UITextView and set dataDetectorTypes = .all. And voilá: the UITextView now automatically detects phone numbers, links, calendar events and addresses and makes them tappable. Really nice!

However, there is one caveat: UITextView adds some insets around the text it displays. So if you want to align an UITextView with another UI element (like an UILabel) and you set both elements to the same origin.x, you will see that the text of the UILabel and the text of the UITextView are not aligned. The text of the UITextView is shifted a bit to the right. If you try to align them horizontally you will notice that it is also shifted a bit to the bottom. When you add background color to the UITextView you see that it adds some padding around it’s text. That is nice, if your UITextView has a border or a background color, or you use it to display some editable or scrollable text, but in our case it is not ideal.

Luckily there is a solution for that. UITextView has a property called textContainerInset. The default value for this inset is (top = 8, left = 0, bottom = 8, right = 0). So setting this inset to UIEdgeInsetsZero should get rid of the top and the bottom padding.

textView.textContainerInset = .zero

Works as expected. But there is still some padding to the left and the right of the text. The solution to get rid of that is not as obvious as setting the insets to zero. UITextView uses a NSTextContainer object to define the area in which the text is displayed. And this NSTextContainer object has a property called lineFragmentPadding. This property defines the amount by which the text is inset within line fragment rectangles, or in other words: the left and right padding of the text. The default value for this is 5.0, so setting this to 0 removes the padding.

textView.textContainer.lineFragmentPadding = 0

So, now the text in the UITextView aligns beautifully with the text of the UILabel.

iOS8 Share extension – completionHandler for loadItemForTypeIdentifier: is never called

Posted: | Author: | Filed under: iOS, Swift | Tags: , | 5 Comments »

Creating a Share Extension in iOS8 is really easy:

  1. In your app choose File > New > Target
  2. Choose Application Extension > Share Extension
  3. Enter a name for your Share Extension and press Finish

That’s all! Xcode creates everything you need for you and puts it in it’s own folder. You’ll find a ShareViewController that is a subclass of SLComposeServiceViewController. That class’ UI looks a lot like the SLComposeViewController that you’ve probably worked with when using iOS’s Social Framework (to share your app’s content to Twitter or Facebook).

In ShareViewController Xcode creates some stubs for you where you have add the code to actually share the content to your service. In my case I want to build an extension for Safari that allows the user to share the page’s URL on my service. So when the user selects my share extension from Safari I need to retrieve the page’s URL to send it to my server.

When the user starts my Share Extension and presses the “Post” button the method didSelectPost is called on the ShareViewController.

Let’s have a look at the stub method that Xcode created:

- (void)didSelectPost {
    // This is called after the user selects Post. 
    // Do the upload of contentText and/or NSExtensionContext attachments.
    
    // Inform the host that we're done, so it un-blocks its UI. 
    // Note: Alternatively you could call super's -didSelectPost, 
    // which will similarly complete the extension context.
    [self.extensionContext completeRequestReturningItems:@[] 
                                       completionHandler:nil];
}

So far so good. So I added the code to retrieve the page URL. Compared to the easiness of creating the whole extension, the simple task of retrieving the URL takes quite some effort:

- (void)didSelectPost {
    NSExtensionItem *item = self.extensionContext.inputItems.firstObject;
    NSItemProvider *itemProvider = item.attachments.firstObject;
    if ([itemProvider hasItemConformingToTypeIdentifier:@"public.url"]) {
        [itemProvider loadItemForTypeIdentifier:@"public.url"
                                        options:nil
                              completionHandler:^(NSURL *url, NSError *error) {
                                  NSString *urlString = url.absoluteString;
                                  // send url to server to share the link
                                  // BUT THIS BLOCK IS NEVER EXECUTED!!!
                              }];
    }
    [self.extensionContext completeRequestReturningItems:@[] 
                                       completionHandler:nil];
}

That’s a lot of code for just an URL. And the worst thing: It’s not working! The completion handler of the loadItemForTypeIdentifier:options:completionHandler: is never called.

As it turns out calling completeRequestReturningItems:completionHandler: at the bottom of the method causes this problem. In Apple’s documentation it says that you are supposed to call this method to ‘Tell the host app to complete the app extension request with an array of result items’. Calling this methods dismisses the ShareViewController and deallocates it. So the NSItemProvider that contains the URL is also destroyed before it can access the URL.

So the solution is quite simple: The call to completeRequestReturningItems:completionHandler: has to be done AFTER retrieving the URL and sending it to the server. So it has to go into the completionHandler block:

- (void)didSelectPost {
    NSExtensionItem *item = self.extensionContext.inputItems.firstObject;
    NSItemProvider *itemProvider = item.attachments.firstObject;
    if ([itemProvider hasItemConformingToTypeIdentifier:@"public.url"]) {
        [itemProvider loadItemForTypeIdentifier:@"public.url"
                                        options:nil
                              completionHandler:^(NSURL *url, NSError *error) {
                                  NSString *urlString = url.absoluteString;
                                  // send url to server to share the link
                                  [self.extensionContext completeRequestReturningItems:@[]         
                                                                     completionHandler:nil];
                              }];
    }
}

And now the URL is retrieved and can be posted to my server.

In case you need to do this in Swift, here is how that would look like:

override func didSelectPost() {
    if let item = extensionContext?.inputItems.first as? NSExtensionItem {
        if let itemProvider = item.attachments?.first as? NSItemProvider {
            if itemProvider.hasItemConformingToTypeIdentifier("public.url") {
                itemProvider.loadItemForTypeIdentifier("public.url", options: nil, completionHandler: { (url, error) -> Void in
                    if let shareURL = url as? NSURL {
                        // send url to server to share the link
                    }
                    self.extensionContext?.completeRequestReturningItems([], completionHandler:nil)
                })
            }
        }
    }
}

Strange looking UIAlertViews in iOS8

Posted: | Author: | Filed under: iOS | Tags: , | 4 Comments »

Do you have UIAlertViews that look strange under iOS8? The alert text is bold and clings to the top of the alert container?

Apparently iOS8 does not tolerate setting the UIAlertView’s title to nil. When you set it to an empty string instead, the UIAlertView looks like it should.

So instead of doing this:

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:nil 
                                                message:@"Hello World!"
                                               delegate:nil
                                      cancelButtonTitle:nil
                                      otherButtonTitles:@"OK", nil];

Do this:

UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"" 
                                                message:@"Hello World!"
                                               delegate:nil
                                      cancelButtonTitle:nil
                                      otherButtonTitles:@"OK", nil];

The funny thing is that with an UIAlertSheet the behavior is opposite: passing an empty string as title results in an empty title section on top of the UIActionSheet. Passing nil for the title fixes this.

Could not launch “APP_NAME”, process launch failed: Security

Posted: | Author: | Filed under: Xcode | Tags: , | No Comments »

After switching to Xcode 6 and the iOS8 SDK I was confronted with a strange error message when trying to test my app on a device. The app was built and deployed to the device but Xcode did not run it. Instead it showed an alert with the following error message:

Could not launch "APP_NAME", process launch failed: Security

The only thing you can do is to press “OK”, but the app still does not run. When you try to run it again from Xcode you just get the same alert.

The solution to this problem is quite simple:

  1. Run the App from Xcode
  2. When the alert shows, press “OK”
  3. Open the app on the device
  4. An alert will be shown, asking you if you want to trust this app. Press “Trust”.

Now you should be able to run the app from Xcode.

Open settings directly from your app

Posted: | Author: | Filed under: iOS | Tags: , | 5 Comments »

Once upon a time it was possible to go to the settings right from your app using:

[[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"prefs://"]];

That was quite useful when some feature in your app could not be used, because the user disabled something in his settings. In that case you could inform the user that he had to change his settings if he wanted to use that feature and offer to open the settings directly from your app.

Unfortunately Apple decided to not longer allow this after the introduction of iOS 5.1

Good news: This feature is back with iOS8! Apple has added a NSString constant to UIKit that you are supposed to use. To avoid crashes on iOS versions below iOS8 it is a good idea to check if the constant exists on the system version the device is running. You could check if the user is running iOS8 or higher but I prefer to check directly if the constant exits rather than checking the iOS version. Who knows if Apple will decide to remove this constant again in the future…

So, to open the settings, you can use the following snippet:

BOOL canOpenSettings = (&UIApplicationOpenSettingsURLString != NULL);
if (canOpenSettings) {
   NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
   [[UIApplication sharedApplication] openURL:url];
}

Swift:

if let settingsURL = NSURL(string: UIApplicationOpenSettingsURLString) {
    UIApplication.sharedApplication().openURL(settingsURL)
}

If your app has it’s own settings bundle, the settings will be opened showing your app’s settings. If your app does not have a setting bundle, the main settings page will be shown.

Unfortunately there does not seem to be a way to go directly to subpages of the settings (except your own settings bundle). If you’ve found a way to do that, please let me know in the comments!

Update: Linking to a subpage of the Setting seems to work again for system versions greater or equal than iOS8. It is not officially documented by Apple but it seems to work, although I not sure how reliable this is. It works on my iOS 9.1 iPhone but not in the Simulator. So I would not recommend to use this in production.

So, with caution, you can try this to open the Keyboard Settings:

if let settingsURL = NSURL(string: "prefs:root=General&path=Keyboard") {
    UIApplication.sharedApplication().openURL(settingsURL)
}

Or go even one level deeper:

if let settingsURL = NSURL(string: "prefs:root=General&path=Keyboard/KEYBOARDS") {
    UIApplication.sharedApplication().openURL(settingsURL)
}

To make these unofficial URLs work you might have to add prefs to the URL schemes of your project’s Info.plist file.

Working with JSONP in AngularJS

Posted: | Author: | Filed under: Javascript | Tags: , | 3 Comments »

One thing that I really like in AngularJS is how easy it is to load JSONP from the server and work with the result. With just one line of code you have the JSON object “in your hand”:

$http.jsonp('https://myurl.com/getlist?callback=JSON_CALLBACK')
   .success(function (data) {
      $scope.jsonObject = data;
   }
);

Really easy. But at first I could not make it work. The request was returning a valid JSONP response but the Javascript would throw an error:

Uncaught ReferenceError: angularcallbacks_0 is not defined

As usual the reason for this error was quite simple once I found it: When you work with JSONP you need to add the name of the callback function (aka “padding”) to the request. The JSON that comes back from the server will then be padded in a function of the name that you provided. For example:

When you request a JSON file like this:

{"key": "data"}

using JSONP:

https://myurl.com/getlist?callback=myCallback

you will get the following response:

myCallback({"key": "data"});

When you use AngularJS, the callback name must be JSON_CALLBACK.

https://myurl.com/getlist?callback=JSON_CALLBACK

AngularJS changes the callback name internally to make sure that you can use several requests simultaneously. So your response will look like this:

angular.callbacks._0({"key": "data"});

So far so good. But when I looked at the response that I got I noticed that the callback name was missing the dots. That was the reason for the Javascript error. AngularJS was expecting angular.callbacks._0 when all it got was angularcallbacks_0.

As it turned out the PHP on the server side was stripping all dots from request parameters. That was the reason why the JSONP response could not be handled by AngularJS.

How to remove all conflicted files from a Dropbox folder

Posted: | Author: | Filed under: Tools | No Comments »

This surely is trivial to most developers, but I am not exactly a wizard when it comes to bash scripting. So let me just post this as a note to myself.

This is how you remove all files that contain a specific substring in their file name. In this example I use it to remove all the conflict files in a Dropbox folder:

Open your terminal and navigate to the folder that contains the files that should be removed. This folder can also contain subfolders. Files in subfolders will also be removed if they contain the substring “Konflikt”.

Then use the following command:

find . -type f -name "*Konflikt*" -exec rm -f {} \;

As you can see, my system language is German, so Dropbox names all conflicted files with the Keyword “Konflikt”. Just change that to your system language.

Be careful! Once you have removed the files there is no turning back. No “undo” button here!!!

How to avoid the ugly flickering effect when using CSS transitions in iOS

Posted: | Author: | Filed under: CSS, HTML, iOS | 2 Comments »

Recently I used CSS transitions to animate some images inside an UIWebView. Everything worked fine and the transitions where really smooth. I used the translate transition to move the images that where inside a div HTML element:

To move the images I created a CSS class that contained the transition:

.move {
   -webkit-transform: translate(50px,100px); 
}

Then I would add the CSS Class to the

to move the div and the images contained in it.

document.getElementById('image-container').className = "move";

This worked as expected. However, when the images moved, there was an ugly flicker. It turned out that this is caused by a CSS property call “backface-visibility”. Normally this is used, when you do 3D CSS transitions (e.g. 3D rotations). “backface-visibility” determines whether the backside of a HTML element is visible, when it is not facing the screen. As I am not doing any 3D transitions it should not matter how this property is set. Wrong. Obviously in Webkit Browsers it does matter. To fix the ugly flickering you have to add the following to the CSS class:

.move {
   -webkit-transform: translate(50px,100px); 
   -webkit-backface-visibility: hidden;
}

And thats not enough. The flickering became less but it was still there. Only after I also set the “backface-visibility” property on the images themselves, the flickering went away completely:

.move {
   -webkit-transform: translate(50px,100px); 
   -webkit-backface-visibility: hidden;
}

.move img {
   -webkit-backface-visibility: hidden;
}

I don’t know if this is a bug in Webkit or if there is a logical explanation for this behavior, but setting “backface-visiblity” to “hidden” on all animated elements did the trick.

Dismiss keyboard in HTML form displayed in UIWebView inside modal view controller

Posted: | Author: | Filed under: HTML, iOS | Tags: , | 3 Comments »

Recently I encountered a problem with the keyboard while displaying a HTML form inside a UIWebView: The HTML form was a simple form to ask the login credentials from a user. Nothing more than 2 text input fields and a submit button. When the user tapped on an input field the iOS Keyboard came up, as it should. But then, when the user tapped the submit button, the keyboard stayed in placed and was not dismissed. The normal behaviour would be that the keyboard would be dismissed as soon as the textfield loses it’s focus. But somehow this was not happening.

I found several solutions on how to dismiss the keyboard programatically by either using javascript or calling resignFirstResponder on the UIWebView when the form was being submitted, but the keyboard would still not go away.

Then I found the solution to that problem. I turned out that the lingering keyboard was a UI design choice by Apple. The keyboard dismissal is disabled when you present your UIWebView using a modal ViewController with presentation style UIModalPresentationFormSheet!

The solution is quite simple: You have to override your ViewController’s disablesAutomaticKeyboardDismissal method:

- (BOOL)disablesAutomaticKeyboardDismissal {
    return NO;
}

After that the keyboard will be dismissed as soon as the input fields lose focus (or the form is being submitted).