Archive for the ‘iOS’ Category

CSS and Attributed Strings

Can you initialize an attributed string with CSS-populated HTML? This question popped up in #iphonedev. The answer is: kind of. HTML initialization is meant for lightweight use, not for full page layout. But yes, you can.

Screen Shot 2015-08-24 at 2.55.14 PM

This question in particular had to do with whether you could customize  list bullets:

Screen Shot 2015-08-24 at 3.05.37 PM

As far as I know, you cannot use externally sourced images but if you worked hard enough (and I’m not willing to do that), there are always attributed strings image attachments.

The upshot of all this is 1: I touched CSS. 2: I’m busy trying to figure out error naming. and 3: I figured that if it’s really important you’ll either use a web view or work out a post-hoc way to insert attachments that I’m not willing to spend any time on here but someone will point me to them if I throw out a post.

There you go.

source:

enum AttributedStringError : ErrorType {case Unconstructable}
func stringWithHTMLString(var string : String) throws -> NSAttributedString {
    string = string.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet())
    if !string.hasPrefix("<html>") {string = "<html>" + string}
    if !string.hasSuffix("</html>") {string = string + "</html>"}
    guard let htmlData = string.dataUsingEncoding(NSUTF8StringEncoding) else {
        throw AttributedStringError.Unconstructable}
    var attributes : NSDictionary = [NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType]
    let options = [String : AnyObject]()
    let aptr = AutoreleasingUnsafeMutablePointer<NSDictionary?>(&attributes)
    return try NSAttributedString(data: htmlData, options: options, documentAttributes: aptr)
}

Blast from the past: All I want for WWDC is…nothing

CCj7O_1VIAAa3fQ

Logo has been fixed by  Radek Pietruszewski ‏@radexp        

 

From February 2014: original post

February may seem early to you to be strategizing about Apple WWDC announcements. For tech writers, it’s crunch time. To plan books, posts, and other coverage, you try to anticipate how big a change is coming up and what areas will be affected.

For example, Victor was asking me the other day what I’d like to see in the next installments of iOS and OS X. My answer is the same as it’s been for years: “Bug fixes and security enhancements.” I’m a bit over the yearly update cycle.

Read On…

Flashback to Voice Control

Someone popped up today with a classic iPhone 3GS, looking for docs on the VoiceControl system. Sadly, Apple has long since expunged nearly everything VoiceControl related from their main site.

Screen Shot 2015-03-02 at 4.31.36 PM

 

Following some links, I hopped over to the Internet WayBack machine to find that not much has been saved. Although the main voice control page was there, few of the secondary pages, videos, or assets were archived. (You can still link to a couple of audio clips, and the second one on making calls still plays.)

I finally googled up the iPhone iOS 3.1 user guide, which contains about a page and a half of text. This material is still hosted, and I’d imagine this continuing for the foreseeable future.

It was an interesting reminder about the fleeting nature of information.

Size dumps

Make of this what you will. I’ve interspersed updates into everything that follows.

When I ran my older apps, everything ran at 320×568 on the new devices. To get the following numbers, I created entirely new projects. (Saniul Ahmed tweeted me that you need to provide current launch images to get the new dimensions.) Lesson: Update your launch images or create new projects to take full advantage of the new dimensions.

From the docs: “The iPhone 6 Plus uses a new Retina HD display with a screen scale of 3.0. To provide the best possible experience on these devices, include new artwork designed for this screen scale. In Xcode 6, asset catalogs can include images at 1x, 2x, and 3x sizes; simply add the new image assets and iOS will choose the correct assets when running on an iPhone 6 Plus. The image loading behavior in iOS also recognizes an @3x suffix.” So the 6 Plus is 3x. Right. (Even though it’s reporting oddly  in the below info dump.)

Compare and contrast with the marketing text: “The size of the new, higher-resolution Retina HD displays on iPhone 6 and iPhone 6 Plus may be the first thing you notice.” (The same  HD mention is here as well.) But the 6 non-plus is reporting correctly for @2x ,not @3x, so I suspect the marketing text is wrong. (Thanks akempgen)

Lesson: The 6 plus uses a 3x scale. The 6 does not. Retina HD seems to mean something different between marketing text (high density) and developer docs (3x resolution).

More explanation about iPhone 6 screens from the guys at PaintCode. Read about it here. Lesson: This new stuff is strange.

With no further ado, here are my original tests.

Testing iPhone 6 plus
iPhone Simulator
iPhone OS
8.0
iPhone Simulator
<UIView: 0x7f854596f7a0; frame = (0 0; 414 736); autoresize = W+H; layer = <CALayer: 0x7f854596bd50>>
<UIWindow: 0x7f854596e1e0; frame = (0 0; 414 736); gestureRecognizers = <NSArray: 0x7f854596edd0>; layer = <UIWindowLayer: 0x7f854596c0d0>>

Testing iPhone 6
iPhone Simulator
iPhone OS
8.0
iPhone Simulator
<UIView: 0x7ffb11415b80; frame = (0 0; 375 667); autoresize = W+H; layer = <CALayer: 0x7ffb11402be0>>
<UIWindow: 0x7ffb14113000; frame = (0 0; 375 667); gestureRecognizers = <NSArray: 0x7ffb14113a20>; layer = <UIWindowLayer: 0x7ffb1410f410>>

Testing iPhone 5s
iPhone Simulator
iPhone OS
8.0
iPhone Simulator
<UIView: 0x7fcb21d13d90; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7fcb21d13090>>
<UIWindow: 0x7fcb21d10e70; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x7fcb21d11770>; layer = <UIWindowLayer: 0x7fcb21d0d140>>

Testing iPhone 5
iPhone Simulator
iPhone OS
8.0
iPhone Simulator
<UIView: 0x7a0d6a50; frame = (0 0; 320 568); autoresize = W+H; layer = <CALayer: 0x7a0d6310>>
<UIWindow: 0x7a17a5c0; frame = (0 0; 320 568); gestureRecognizers = <NSArray: 0x7a17ac00>; layer = <UIWindowLayer: 0x7a17a550>>

Testing iPhone 4s
iPhone Simulator
iPhone OS
8.0
iPhone Simulator
<UIView: 0x7ae9a000; frame = (0 0; 320 480); autoresize = W+H; layer = <CALayer: 0x7ae9c730>>
<UIWindow: 0x7ae9c600; frame = (0 0; 320 480); gestureRecognizers = <NSArray: 0x7ae9cb20>; layer = <UIWindowLayer: 0x7ae9c210>>

Anyway, this was what I tested out:
Screen Shot 2014-09-15 at 2.54.04 PM

Auto Layout: iOS 8

It’s been a pretty exciting summer as far as Auto Layout goes. I’m busy going over material so I can get some dates and work estimates to Trina on a possible 3rd edition of Auto Layout. Between Swift, OSX, iOS 8, and whatever is going to be announced in September, it looks like a particularly interesting place to be.

I can’t tell you how thrilled I am about active, the property that self-installs and removes constraints to their natural destination. I submitted my first radar on this back before the first edition was even published. Now with the third edition, I suppose I’ll be all “Yeah, that’s my radar baby!”

The long iOS 8 summer first gave us left and right layout guides, a la the top and bottom guides we first encountered in iOS 7 but they soon disappeared and have since been replaced by a suite of Margin-based layout attributes:

    NSLayoutAttributeLeftMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeRightMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeTopMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeBottomMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeLeadingMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeTrailingMargin NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeCenterXWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),
    NSLayoutAttributeCenterYWithinMargins NS_ENUM_AVAILABLE_IOS(8_0),

Comments and properties in the UIView header file indicate a layout tree of margins. I think it’s fair to assume this ties into the adaptive application that runs properly both on full-screen as well as side-by-side.

/*
 -layoutMargins returns a set of insets from the edge of the view's bounds that denote a default spacing for laying out content.
 If preservesSuperviewLayoutMargins is YES, margins cascade down the view tree, adjusting for geometry offsets, so that setting the left value of layoutMargins on a superview will affect the left value of layoutMargins for subviews positioned close to the left edge of their superview's bounds
 If your view subclass uses layoutMargins in its layout or drawing, override -layoutMarginsDidChange in order to refresh your view if the margins change.
 */
@property (nonatomic) UIEdgeInsets layoutMargins NS_AVAILABLE_IOS(8_0);
@property (nonatomic) BOOL preservesSuperviewLayoutMargins NS_AVAILABLE_IOS(8_0); // default is NO - set to enable pass-through or cascading behavior of margins from this view’s parent to its children
- (void)layoutMarginsDidChange NS_AVAILABLE_IOS(8_0);

Unfortunately, the material from WWDC is light on details and these updates didn’t take place until fairly recent betas. Got any insights into how this material will play out? I’d love to hear it. (And thanks in advance!)

iOS Utilities: UIImage from PDF

I’ve posted before about how the new PDF support in asset catalogs doesn’t really do what we expect (offer resizable vector assets). To make up for that, here’s a class that loads images from PDF files directly, building them to whatever UIImage size you need. Supply a path to the image and a target size, height, or width. If using a size, the functions will scale-aspect-fit to that target. With width or height, they’ll use the built-in aspect and build an appropriately sized partner dimension.

This class is part of my useful things repo, which is where I stash stuff that people may generally find useful. A bunch of classes and utilities are tied to my InformIT write-ups, but others meander there over time because I was inspired for whatever reason.

 

That UIAlertView thing: Deprecation and dinosaurs

Are you surprised at how many devs are focused on developing new iOS 7-specific applications this late into the game? iOS 7 has a 2 – 3 month ticking time bomb on it and yet every day, I encounter developers whose primary focus is getting their iOS 7 apps into shape for this autumn rather than building iOS 8 for launch this fall.

Sure iOS 7 and iOS 7 compatibility aren’t going away for a while. Even those devs aware of UIAlertView deprecation are focused on bigger deployment issues. Nearly all of them have irrational partners and bosses who insist on backwards compatibility to roughly the jurassic period. If a new iOS 7 app will work on iOS 8 that’s all they want or need. Taking advantage of iOS 8 features, well that’s for other people.

When you work on books, it’s awfully easy to get stuck in Apple headspace. Take UIAlertView. It’s been deprecated and I keep coming back to that, mostly because deprecated classes aren’t even available in Swift these days. Somehow this keeps resonating to my “It’s dead, Jim! I’m a doctor not a miracle worker” senses. I have to keep reminding myself of the day-to-day realities of the app store as it exists, not as Apple would have it. And yet when developers come to me asking how to build HUDs based on UIAlertView this late in the game, I start going UIAlertController ballistic.

The way I see it, ever since App Store started offering platform-specific upgrades, the pressure to back-support all devices all the time was gone. Unless you’re developing something new but specific to older devices (there’s a big market out there if you’re prepared to fight the tool suite, hi Chris S!), why not keep pushing forward with new releases? It’s not as if older systems can’t still do business with you. And when they upgrade, your newer versions are ready for them to download.

How much back compatibility do you think is necessary, especially if you put out regular updates?  If the world is upgrading with you, what are you gaining from supporting those 10% of users who have access to your product but may not be running the latest version of your software? What am I missing here?

I’m really curious to hear what you have to say.

Beta: Apps and Traits, some thoughts

The iOS family continues to grow. Although iOS targets are not nearly as splintered as Android’s multitude, iOS apps must adapt interfaces to numerous configurations for universal deployment. Routines specific to iPads or iPhones, to landscape or portrait orientation, and to retina or non-retina screens have transformed many iOS apps into a tangle of special-purpose code.

To push back, iOS 6 introduced Auto Layout, a descriptive system for interface design. Auto Layout enabled developers to use rule-based view placement that automatically adjusts to screen dimensions and orientation.

Now iOS 8 adds the notion of adaptive deployment. New classes and protocols enable apps to retrieve the specifics of the current runtime environment. This enables them to adapt not only to hardware limitations but also to whatever screen space has been allocated to their presentations. A truly adaptive app gracefully responds with a well designed and engaging interface, ready for the user at any size.

A iOS 8 trait collection describes a single point in deployment space. This space represents the range of possible conditions an interface might encounter in the real world. By making these traits concrete, Apple enters into a somewhat implicit contract with the developer – these are the types and ranges of flexibility you must design for.

Even if Apple introduces multi-windowing, you only have to worry about “compact” and “regular” interface sizes under the current system. There’s a (vague and legally unenforcable) guarantee that for at least the next year Apple will not add some “Ultra Compact” game-changer where you suddenly have to worry about designing forms for 100-pixel destinations. And, if Apple does introduce that windowing, the traitCollectionDidChange callback means you can switch your tablet presentations to phone ones for side-by-side execution and then back again.

No matter what kind of apps you design, a tension always exists between pixel-perfect control and adaptability. An interface that looks stunning on a 4″ iPhone may look cramped on a 3.5″ screen and sparse on a tablet. This has led some developers to build what is essentially multiple codebases under a single app umbrella.

With trait collections and standardized callbacks, iOS 8 is attempting to bring sanity back to those apps. So long as the presentation specifics don’t get too ridiculous, Auto Layout and trait-driven assets should be able to handle those specifics both at launch time and during run time.

Will Apple introduce a 3x display resolution? I think it unlikely but if they do, the technology is already in-place to handle that trait collection with a 3.0 display scale. Will Apple add a new geometry to the phone family? That’s a rumor that seems to have more appeal — but Auto Layout is ready for that, and the compact-regular layout traits will support any baby-dolphin-sized phablet that might hit the market. Will iOS 8 support multi-app display? The technology to support it is ready for developers if they take advantage of those features.

I admit that some of Apple’s design choices for trait collections baffle me. For example, how is it that a 480-point height is “regular” and a 586-point width is “compact”? But despite that, I find it comforting to  receive a concrete set of interface expectations via the trait API.

What do you think? Please do let me know.

Beta: Auto Layout Constraint Activation

I’m pretty excited about the new active constraint property. To date, a lot of my work involves adding and removing constraints. Now with activateConstraints: and deactivateConstraints: you can enable and disable constraint groups all at once. I can see this being used in a variety of ways:

  • Disabling constraints for dynamic animators — you don’t have to layout and then remove items
  • Choosing constraint sets for various states — you can use one set for example when a view is visibly presented and another if it is hidden or create closed and open presentations.
  • Bringing individual constraints on-line or off-line that have competing priorities, so you can disable rather than remove a higher-priority item until it is needed again.

I’m not sure if this is animatable so I have to test that bit, but I’m really hoping it is.

One final note: the two activator/deactivator methods are documented to be more efficient than accessing constraints one-by-one.

UPDATE: WHOA! Self-installing constraints! Finally!

UIView *v = [UIView new];

v.autoLayoutEnabled = YES;

[self.view addSubview:v];

NSLayoutConstraint *c = [NSLayoutConstraint constraintWithItem:v attribute:NSLayoutAttributeCenterX relatedBy:NSLayoutRelationEqual toItem:self.view attribute:NSLayoutAttributeCenterX multiplier:1 constant:0];

NSLog(@”%@”, self.view.constraints);

c.active = YES;

NSLog(@”%@”, self.view.constraints);

2014-07-11 16:44:09.138 Hello World[18020:1138706] (

)

2014-07-11 16:44:09.141 Hello World[18020:1138706] (

    “<NSLayoutConstraint:0x7fed2d809090 UIView:0x7fed2d9449b0.centerX == UIView:0x7fed2d93da70.centerX>”

)