XVim

Assistant editors

:sp

Add new assistant editor. Assistant editors are laid out horizontally.

:vsp

Add new assistant editor. Assistant editors are laid out vertically.

Replace

When text is visually selected, press : to enter a command

s/old/new/g

Search

/search_text
Press Enter, then next with n

Reference

120 total views, no views today

Simple caching

Memory and disk

This simple cache uses both memory and disk cache
– Retrieval: Ask memory first. If not, ask disk, then set back to memory cache
– Save: Save to both memory and disk.

I used to use TMCache, but then I found Realm to be much better.

Code

Take a look at my gist SimpleCache

Reference

114 total views, no views today

Debugging Auto Layout

hasAmbiguousLayout

Returns whether the constraints impacting the layout of the view incompletely specify the location of the view.

exerciseAmbiguityInLayout

This method randomly changes the frame of a view with an ambiguous layout between its different valid values, causing the view to move in the interface. This makes it easy to visually identify what the valid frames are and may enable the developer to discern what constraints need to be added to the layout to fully specify a location for the view.

_autolayoutTrace

This returns a string describing the whole view tree which tells you when a view has an ambiguous layout.

NSLayoutConstraint identifier

The name that identifies the constraint.

UIViewAlertForUnsatisfiableConstraints

Autolayout Breakpoints

Reference

139 total views, no views today

Understanding Layout Guide

iOS 8

topLayoutGuide and bottomLayoutGuide
– is a property on UIViewController
– inherits from UIView
– conforms to UILayoutSupport protocol

UILayoutSupport

In iOS 7 and later, a view controller’s view occupies the full height of the screen when there are no opaque UIKit bars (such as opaque navigation or tab bars). To keep your content within the area of a view that is not overlaid by translucent or transparent UIKit bars, employ the topLayoutGuide and bottomLayoutGuide properties in the UIViewController class and take advantage of Auto Layout. Query these properties within your implementation of the UIViewController method viewDidLayoutSubviews.

The guides work as follows:
– The top layout guide indicates the distance, in points, between the top of a view controller’s view and the bottom of the bottommost bar that overlays the view
– The bottom layout guide indicates the distance, in points, between the bottom of a view controller’s view and the top the bar (such as a tab bar) that overlays the view.

topLayoutGuide

The topLayoutGuide property comes into play when a view controller is frontmost onscreen. It indicates the highest vertical extent for content that you don’t want to appear behind a translucent or transparent UIKit bar (such as a status or navigation bar). This property implements the UILayoutSupport protocol and you can employ it as a constraint item when using the NSLayoutConstraint class.

The value of this property is, specifically, the value of the length property of the object returned when you query this property. This value is constrained by either the view controller or by its enclosing container view controller (such as a navigation or tab bar controller), as follows:

A view controller not within a container view controller constrains this property to indicate the bottom of the status bar, if visible, or else to indicate the top edge of the view controller’s view.

A view controller within a container view controller does not set this property’s value. Instead, the container view controller constrains the value to indicate:
– The bottom of the navigation bar, if a navigation bar is visible
– The bottom of the status bar, if only a status bar is visible
– The top edge of the view controller’€™s view, if neither a status bar nor navigation bar is visible

If a container navigation controller’€™s navigation bar is visible and opaque, the navigation controller lays out the frontmost view controller’€™s view so its top edge abuts the bottom of the navigation bar. In this case, the value of this property is 0.

bottomLayoutGuide

iOS 9

UILayoutGuide

topLayoutGuide and bottomLayoutGuide
– inherits from UILayoutGuide

They do not participate in the view hierarchy. Instead, they simply define a rectangular region in their owning view’s coordinate system that can interact with Auto Layout.

Layout guides can also act as a black box, containing a number of other views and controls. This lets you encapsulate part of your view, breaking your layout into modular chunks.

152 total views, no views today

iOS configuration

This is about creating multiple targets from a project.

Source file

Source files (.m, .plist, …) must be checked into appropriate target

Info.plist

Each target should have its own Info.plist. Info.plist should not be checked into the target. Otherwise, you will get a warning

The Copy Bundle Resources build phase contains this target’s Info.plist file

Instead, it must be specified in the target ‘s Build Setting -> Packaging -> Info.plist file. It can be absolute or relative to the project file

Entitlement

Entitlement should not be checked into the target

Instead, it must be specified in the target ‘s Build Setting -> Code Signing -> Code Signing Entitlement. Ut can be absolute or relative to the project file

Asset Catalog

Asset Catalog must be checked into the appropriate target. The fix for multiple target with multiple Asset Catalog together with Cocoapods is Multiple targets and Asset Catalog with Cocoapods

Read Build Setting Reference

Build Setting Reference has some predefined macros that can be useful.

Preprocessor Macro

Under target Build Setting -> Apple LLVM Preprocessing -> Preprocessor Macros, we can define our own macro, which can be useful in code.

For example, in Distro A target, I can set macro DISTRO_A to both Debug and Release Configuration.

Configuration

Multiple targets can have different configuration (server path, Facebook ID, …). This can be achieved by several ways

ifdef

#ifdef DISTRO_A
NSString *serverPath = @"http://distro-a.com";
#else
NSString *serverPath = @"http://distro-b.com";
#endif

1 config.h file and multiple config.m file for each target

Config.h

extern NSString *serverPath;

Config.m (Distro A target)

NSString *serverPath = @"http://distro-a.com";

Config.m (Distro B target)

NSString *serverPath = @"http://distro-b.com";

Protocol and Abstract Factory

We can define a protocol
Config.h

@protocol Config <NSObject>

- (NSString *)serverPath;

@end

DistroAConfig.h

@interface DistroAConfig : NSObject <Config>

@end

DistroAConfig.m

@implementation DistroAConfig

- (NSString *)serverPath {
    return @"http://distro-a.com";
}

@end

Theme

Each target can have different themes (different color, font, text size, spacing, …). We can use protocol together with Abstract Factory pattern. Each target has a ThemeFactory that can produces HomeTheme, SettingTheme, AboutTheme, FavoriteTheme, … This way you only need to use ifdef once

Theme.h

id<ThemeFactory> themeFactory();

Theme.m

id<ThemeFactory> themeFactory() {
#ifdef DISTRO_A
    return [DistroAHomeThemeFactory new];
#else
    return [DistroBThemeFactory new];
#endif
}

ThemeFactory.h

@protocol ThemeFactory <NSObject>

- (id<HomeTheme>)home;

@end

HomeTheme.h

@protocol HomeTheme <NSObject>

- (UIColor *)titleColor;
- (UIFont *)titleFont;

@end

DistroAThemeFactory.h

@interface DistroAThemeFactory : NSObject <ThemeFactory>
@end

DistroAThemeFactory.m

@implementation DistroAThemeFactory

- (id<HomeTheme>)home {
    return [DistroAHomeTheme new];
}

@end

DistroAHomeTheme.h

@interface DistroAHomeTheme : NSObject <HomeTheme>

@end

DistroAHomeTheme.m

@implementation DistroAHomeTheme

- (UIColor *)titleColor {
    return [UIColor redColor];
}

- (UIFont *)titleFont {
    return [UIFont boldSystemFontOfSize:15];
}

@end

HomeViewController.m

#import "Theme.h"

self.label.textColor = themeFactory().home.titleColor;

Reference

161 total views, no views today

Understanding PSTAlertController – weakSheetStorage

For those who don’t use PSTAlertController

API similar to UIAlertController, backwards compatible to iOS 7. Will use the new shiny API when you run iOS 8.

The thing I find interesting about it is its dance for weakSheetStorage and strongSheetStorage
Read Understand strongSheetStorage vs weakSheetStorage

It’s for exact object lifecycle management. The controller isn’t retained but needs to stick around, and once show is called we bind the lifetime to the views presented, so everything is cleaned up at the correct time without worrying about manually retaining things.

Init

When PSTAlertController is initialized, it hold a strong reference to UIAlertView and UIActionSheet

if (preferredStyle == PSTAlertControllerStyleActionSheet) {
                _strongSheetStorage = [[UIActionSheet alloc] initWithTitle:title delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];
            } else {
                _strongSheetStorage = [[UIAlertView alloc] initWithTitle:title message:message delegate:self cancelButtonTitle:nil otherButtonTitles:nil];
            }

Show

PSTAlertController may not be kept by any object, but the system keeps UIAlertView and UIActionSheet, so when UIAlertView and UIActionSheet is shown, we attach PSTAlertController to these

- (void)moveSheetToWeakStorage {
    NSParameterAssert(self.strongSheetStorage);

    objc_setAssociatedObject(self.strongSheetStorage, _cmd, self, OBJC_ASSOCIATION_RETAIN_NONATOMIC); // bind lifetime
    self.weakSheetStorage = self.strongSheetStorage;
    self.strongSheetStorage = nil;
}

172 total views, no views today

Understanding FLEX – Orientation

FLEX ‘s bar always follow the orientation of your app. To do that, FLEX custom UIWindow ‘s rootViewController must ask your app for orientation and status bar style

FLEXExplorerViewController.m

This is the core method, it finds the correct viewController to ask

// Try to get the preferred status bar properties from the app's root view controller (not us).
// In general, our window shouldn't be the key window when this view controller is asked about the status bar.
// However, we guard against infinite recursion and provide a reasonable default for status bar behavior in case our window is the keyWindow.

- (UIViewController *)viewControllerForStatusBarAndOrientationProperties
{
    UIViewController *viewControllerToAsk = [[[UIApplication sharedApplication] keyWindow] rootViewController];
    
    // On iPhone, modal view controllers get asked
    if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
        while (viewControllerToAsk.presentedViewController) {
            viewControllerToAsk = viewControllerToAsk.presentedViewController;
        }
    }
    
    return viewControllerToAsk;
}

For orientation, it simply asks the found viewController

- (NSUInteger)supportedInterfaceOrientations
{
    UIViewController *viewControllerToAsk = [self viewControllerForStatusBarAndOrientationProperties];
    NSUInteger supportedOrientations = [FLEXUtility infoPlistSupportedInterfaceOrientationsMask];
    if (viewControllerToAsk && viewControllerToAsk != self) {
        supportedOrientations = [viewControllerToAsk supportedInterfaceOrientations];
    }
    
    // The UIViewController docs state that this method must not return zero.
    // If we weren't able to get a valid value for the supported interface orientations, default to all supported.
    if (supportedOrientations == 0) {
        supportedOrientations = UIInterfaceOrientationMaskAll;
    }
    
    return supportedOrientations;
}

Reference

103 total views, no views today