Recent Updates Toggle Comment Threads | Keyboard Shortcuts

  • Jay 9:10 pm on January 11, 2015 Permalink | Reply
    Tags:   

    How to use Categories in Objective-C 

    Objective-C has a feature called Categories. These are used to extend existing classes. The principle is different than subclassing in that a Category will behave like the original class with additions, rather than a completely different class.

    For example, if we’d subclass NSString then the resulting class name would be something like YourStringClass. We would hence need to instantiate it with [[YourStringClass alloc]init]. By contrast, a Category is instantiated and used like the original class (such as [[NSString alloc]init], however additional methods we provide are henceforth included.

    We need separate header and implementation files for our Category, just like for a regular class. Apple recommend to name such files by starting with the superclass, followed by a plus sign, followed by your Category name.

    In this example we’ll create a Category for NSString called Test. Hence we need NSString+Test.h and .m files. Xcode 6 no longer provides a mechanism for that, so either empty .h and .m files will suffice, or alternatively create a standard subclass and overwrite the relevant sections.

    Here’s NSString+Test.h:

    @import Foundation;
    
    @interface NSString (Test)
    
    - (NSString *)myModification;
    
    @end
    

    Instead of separating our class name from the superclass with a semicolon, we’ll use brackets. We add one public method here. We’ll write the code for it in NSString+Test.m:

    #import "NSString+Test.h"
    
    @implementation NSString (Test)
    
    - (NSString *)myModification {
        
        // add your code here
        return @"Result!";
    }
    
    @end
    

    No big surprises here either: we simply import the header file and write our method – a simple one will do here, returning “Result!”. Notice the way we declare the @implementation, again with brackets.

    Here’s how we call the extended class from somewhere else, for example a view controller:

    #import "ViewController.h"
    #import "NSString+Test.h"
    
    @interface ViewController ()
    
    @end
    
    @implementation ViewController
    
    - (void)viewDidLoad {
    
        [super viewDidLoad];
        
        // call my own method
        NSString *result = [[NSString alloc]init];
        NSLog(@"%@", [result myModification]);
    }
    
    @end
    

    After importing the Category we can instantiate an NSString object and use our own method as if Apple had baked it right into the Foundation Framework. How cool is that?

    Singletons

    Categories appear to be even cooler when we implement a singleton. That’s a method we can call on the class without having to instantiate it first. While the above example makes little difference beside convenience, when we call something like [[NSString myKillerExtension] it really feels as if our code is part of the Foundation Framework.

    Defining a singleton works just like defining a standard method, but instead of the minus sign we use a plus sign. I’m also demonstrating how to take a parameter in our method:

    // singleton signature in header file
    +(NSString *)specialInstruction:(NSString *)parameter;
    
    // and in the implementation file
    +(NSString *)specialInstruction:(NSString *)parameter {
        
        // singleton implementaion
        NSString *result = [NSString stringWithFormat:@"The parameter was %@.", parameter];
        return result;
    }
    

    We can now call the singleton as it it was part of the NSString class:

    - (void)viewDidLoad {
        [super viewDidLoad];
        
        // call my singleton
        result = [NSString specialInstruction:@"testing"];
        NSLog(@"%@", result);
    }
    

    Now go forth and categorise!





     
  • Jay 11:57 am on January 11, 2015 Permalink | Reply
    Tags: , , UIVisualEffect   

    How to apply Blur Effects to images and views in iOS 8 

    This slideshow requires JavaScript.

    In iOS 8 there’s a new class called UIVisualEffect with which you can apply blur effects to entire views. Reading the Class Reference however you’d never figure out how.

    In a nutshell, we need to create a UIVisualEffect (either a UIBlurEffect or a UIVibrancyEffect) which is applied to a UIVisualEffectView. The latter needs the same size as the view we want to blur and is then added as a subview to the view we’d like to apply an effect to.

    This sounds way more complicated than it really is. Imagine this: you have a UIView, any view will do. To it you add a subview (the UIVisualEffectView). The effect view is created with an effect.

    So as soon as you apply the effect view, all other existing views below it are blurred. Anything above the effect view is not blurred. Remove the effect view and the blur goes away again.

    Here’s an example:

    // show image
    self.imageView.image = [UIImage imageNamed:@"boat6"];
    
    // create effect
    UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
    
    // add effect to an effect view
    UIVisualEffectView *effectView = [[UIVisualEffectView alloc]initWithEffect:blur];
    effectView.frame = self.view.frame;
    
    // add the effect view to the image view
    [self.imageView addSubview:effectView];
    

    In this example we have a UIImageView which is referenced in the storyboard. To it we apply the desired effect.

    The UIBlurEffect can be created with three options and no other parameters:

    • UIBlurEffectStyleLight
    • UIBlurEffectStyleExtraLight
    • UIBlurEffectStyleDark

     

    UIVibrancyEffect

    There’s an additional (disappointing) UIVibrancyEffect which cannot be used on its own, only in conjunction with a blur effect. To use the vibrancy effect, we need to first create a blur, then a new vibrancy effect with that blur. From both effects we need to then create two separate effect views and add both of those to the view we’d like to blur.

    Here’s an example:

    // show image
    self.imageView.image = [UIImage imageNamed:@"boat6"];
    
    // create blur effect
    UIBlurEffect *blur = [UIBlurEffect effectWithStyle:UIBlurEffectStyleLight];
    
    // create vibrancy effect
    UIVibrancyEffect *vibrancy = [UIVibrancyEffect effectForBlurEffect:blur];
    
    // add blur to an effect view
    UIVisualEffectView *effectView = [[UIVisualEffectView alloc]initWithEffect:blur];
    effectView.frame = self.view.frame;
    
    // add vibrancy to yet another effect view
    UIVisualEffectView *vibrantView = [[UIVisualEffectView alloc]initWithEffect:vibrancy];
    effectView.frame = self.view.frame;
    
    // add both effect views to the image view
    [self.imageView addSubview:effectView];
    [self.imageView addSubview:vibrantView];
    

    I know… this seems an awful lot of trouble to get an effect which isn’t even all that good. But then, “new things” aren’t always “improvements” these days (the 2014 Mac Mini springs to mind).

     

    How to do this in iOS 7

    If you’re as disappointed by the results as I am, take a look at a UIImage Category with which Apple have demonstrated this effect at WWDC 2013. Look for a sample project called UIImageEffects.

    The category is free to use and redistribute and allows for greater control over such things as colour tint and blur radius:

     

    Further Reading





     
  • Jay 3:06 pm on January 10, 2015 Permalink | Reply
    Tags: , ,   

    How to take a screeshot in iOS programmatically 

    In iOS we can press the HOME and the POWER button together at any time and a screenshot of what’s currently being displayed will be saved to the Camera Roll as if by magic. If we wanted to do the same thing programmatically it’s not that easy. It appears there’s no iOS system method that does this for us.

    We have several options, let me describe two of those. I’ll add others if there are more convenient methods.

    OPTION 1: using UIWindow

    To make sure we screengrab everything in our display we can transfer the content of our top most UIWindow into a graphics context with the size of our screen. This will work no matter which class you use it in:

    // create graphics context with screen size
    CGRect screenRect = [[UIScreen mainScreen] bounds];
    UIGraphicsBeginImageContext(screenRect.size);
    CGContextRef ctx = UIGraphicsGetCurrentContext();
    [[UIColor blackColor] set];
    CGContextFillRect(ctx, screenRect);
    
    // grab reference to our window
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    
    // transfer content into our context
    [window.layer renderInContext:ctx];
    UIImage *screengrab = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    

    The advantage with this method is that even popovers and alert views are added to the resulting UIImage.

    OPTION 2: using UIView

    If we only need to turn a UIView into a UIImage then the next method will work fine. The disadvantage is that certain types of views (such as OpenGL and popovers) will not be captured. In addition, you need a reference to the UIView you’d like to capture. In this example I’m using my Master/Detail App’s split view controller:

    // grab reference to the view you'd like to capture
    UIView *wholeScreen = self.splitViewController.view;
    
    // define the size and grab a UIImage from it
    UIGraphicsBeginImageContextWithOptions(wholeScreen.bounds.size, wholeScreen.opaque, 0.0);
    [wholeScreen.layer renderInContext:UIGraphicsGetCurrentContext()];
    UIImage *screengrab = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();
    

    Saving a UIImage to Camera Roll

    The result of both methods above is a UIImage you can do with as you please. Let’s save it to the Camera Roll for now:

    // save screengrab to Camera Roll
    UIImageWriteToSavedPhotosAlbum(screengrab, nil, nil, nil);
    

    One thing of note:
    If you call either method above via a standard button, the screenshot is taken during the button animation (half faded for example).

    Further Reading





     
  • Jay 2:46 pm on January 10, 2015 Permalink | Reply
    Tags: ,   

    How to grab a reference to the top most UIWindow 

    It’s easy to get a reference to the very top window if we write code in our AppDelegate. We can easily refer to it with self.window.

    But if you’re writing code in another class then this doesn’t work. Instead, we can use UIApplication and ask for the keyed window – that’s the one currently being displayed:

    // grab reference to our keyed window
    UIWindow *window = [UIApplication sharedApplication].keyWindow;
    




     
c
compose new post
j
next post/next comment
k
previous post/previous comment
r
reply
e
edit
o
show/hide comments
t
go to top
l
go to login
h
show/hide help
shift + esc
cancel
Password Reset
Please enter your e-mail address. You will receive a new password via e-mail.