Three truths of software revisions

I am no expert in user experience, probably not even in software design, but over the over the course of more than a decade using and writing software i have come to impart several truths, i will go on dispensing these things i consider as such.

 

But first off i need wax philosophically on the concept of revision itself, feel free to skip ahead to jump to the meat of it if you are so inclined.

So what are revisions, what do they imply, and why are they important ?

Revisions are not exactly a new concept, as with al things we can take a look at nature for immediate analogues, i trust you will be able to find plenty in a glance, they are new however for some things.

As time goes by some familiar concepts, like the books in your network connected e-reader, gain revisions they become a living entity, others like a De Lorean DMC-12 get frozen in time, forever still (or not).

And what do revisions imply ? well they imply evolution for one and a lifeline for a close second.

Something that has revisions can almost feel as living and breathing and is very different from the coldness and perfection of master’s ancient greek sculpture (very different and very similar if you will see the sculpted figure as alive).

As to why are they are important, just thinking about your opposable thumb the next time you grab something with your hand should suffice.

.

Now on to the truths i threatened with, i assume there are books that feature them, not that i read any, but i digress, software revisions colloquially called “updates” are a mighty important concept and they need to hold true to some values.
As all truths, these specific ones on software updates might apply to some extent to all software at large, some might sound like common sense, if they do please let me know which ones.

  • Truth one: what once was given should not be easily taken, even if it was wrong, a good update takes this into account above all and in treats the rare cases where something just has to be taken with extreme care.

This is probably the most controversial of the bunch and can be argued pro and against to no end, battle scarred developers know which ones weight more, as far as i am concerned as true as i even known truth to be.

  • Truth two: a good update is discreet, noninvasive, it does not hit you in the head, does not scream change, one might even find himself wondering if the update existed at all, only very few things are needed to denote new, if any.

This is probably less controversial, if you want to hit people in the head you should seek professional treatment, i am just going to state it as a truth because it is.

  • Truth three: a good update has a continuum, most changes in it have a segue to a previous concept, very few, if no changes stand on their own coming out of thin air.

You know this one to be true yourself, i don’t even have to argue it, if you wake up one morning with one extra limb that you have no idea how to operate i just don’t see how you’ll appreciate it.

.

That’s it for now, i never claimed to have all truths about software updates, any constructive commentary is one of the reasons for writing this, so please do.

The way i see it the future is all software, the survival or demise of humanity might as well hang on it, we cant just bang rocks together hoping for the best.

So please do the world a favor, if you are going to change something so much in a revision that it barely resembles it’s predecessor make it a new thing, not a revision, rethink it from the ground up and let the original turn cold and perfect like a ancient greek sculpture.

basics of iOS and OS X API’s


The structure of OS X and iOS native* API’s is very straight forward/minimalistic, typically one does not need to know about anything that goes below the Foundation API however taking a look at the headers can help understanding it better and clearing common confusions between Foundation and CoreFoundation or what exactly constitutes CocoaTouch and Cocoa since the later is a explicit framework while the former is just a naming convention.

All the API’s are present as binary frameworks under /System/Library/Frameworks (with resources but without headers) and under your Xcode toolchain SDK (with headers but without resources) , the objc binary is at /usr/lib/libobjc.A.dylib while the headers are under /usr/include/objc/ and your Xcode toolchain.

I
Now let’s dig right into it, at the lowest level there is CoreFoundation and objc, they are independent of each other :

<objc/objc.h>
objc_class,objc_object,objc_selector etc

<objc/runtime.h>
objc_getClass,objc_getProtocol,class_conformsToProtocol etc

<objc/message.h>
super_class,objc_super,objc_msgSend,objc_msgSendSuper etc

(you can include all the above with #import <objc/objc-class.h>)

<CoreFoundation/CoreFoundation.h>
CFString,CFNumber,CFArray,CFRunLoop,CFStream etc (this is just C, there is no Objective-C syntax or anything at this level)

II
On top of these and including (relying on both) is Foundation, as the name implies you typically never use any API’s below foundation directly.

<Foundation/Foundation.h>
NSString,NSNumber,NSArray,NSRunLoop,NSStream etc, much of it is toll-free bridged to CoreFoundation

III
on top of Foundation there is AppKit for OS X or UIKit for iOS
(on OS X you typically include Foundation, AppKit and CoreData with #import <Cocoa/Cocoa.h>, there is no corresponding CocoaTouch shell framework on iOS)

<AppKit/AppKit.h>
NSView,NSButton,NSColor,NSEvent etc

<UIKit/UIKit.h>
UIView,UIButton,UIColor,UIEvent etc

This is pretty much all there is, from this on there are multiple optional frameworks you can use for specific cases, but the basics are just in the headers above, most API’s are Cocoa but there is still a big chunk of C API’s especially on the OS X side.

It’s worth nothing that there are two types of frameworks : private and public , the private ones are not safe to be used and not allowed in the Mac App Store , the public ones are safe to be used as long as they have headers in the SDK (they could be present in /System/Library/Frameworks but not in the SDK) typically such disparity is a rare occasion nowadays and it was more common prior to 10.6.

One more note is that public frameworks with headers might not have all their methods/classes documented, nevertheless using them should be pretty safe but the lack of documentation is a indication that they are more likely to change/go away than the documented ones.

*OS X and IOS also have the low level BSD API’s (found in /usr/include) most of which are cross-platform and outside the scope of this post.

getting positive software feedback

It has been proven that the drive to give feedback on something is strongly polarized, that is the feedback is shaped by strong feelings either positive or negative, which makes sense, the people with median feelings do not care enough to give feedback, it should come as no surprise that this mechanic is relevant to getting positive feedback, basically to get positive feedback you want engagement, for people to care enough to say something, once you have that positive feedback is a given.

Negative feedback is inevitable, a user’s hardware or operating system could be defective, tampered by factors like jailbreaking/hacking or the feedback could be plain untruthful by either confusion or spambots/competitor malevolence, either way there will always be some, you might as well accept it.

However that inherent negative feedback is limited in scale, positive feedback can easily outpace it if there is any drive for the users to feel the need to express anything positive, what you want to do is instill that drive for positive feedback, those that have median feelings will not engage at all, it is only the poles of the spectrum that will generally be the source of most feedback.

Unless you have a serious problem that causes significant feedback all negative, just a little engagement to outweigh that inherent negative feedback will always tip the scale towards positive, with no engagement that little negative feedback is all you get.

discrete graphics and you

In 2010 Apple introduced a feature in MacBooks with the aim of extending battery life “Automatic graphics switching” that switches between using either the integrated Intel GPU  inside the CPU or the standalone discrete AMD/Nvidia GPU.

The exact conditions however that make it switch one or the other were never clearly stated by Apple, and there has been much debate confusion and speculation on the subject.

Upon testing i found the answer to be pretty straight forward in that if a application ever loads the OpenGL.framework the machine switches to the standalone GPU (easiest way to determine this is inspect the files area of the program with Activity Monitor and look for OpenGL.framework) ,i have so far unable to find any other framework besides it to trigger the switch.

Determining what can make it load that framework is not that straight forward however, and remember it does not have to be linked for it to be loaded, any API that relies on it can trigger it’s loading, and the likely culprit in most cases will be Core Animation which uses OpenGL backing.

So to make sure you do not trigger the standalone GPU you need to make sure your code does not rely on any Core Animation API’s or any that otherwise uses OpenGL, also remember that all the “Effects” in Interface Builder require a Core Animation layer that will trigger the loading of the OpenGL.framework

EDIT: As of lion there is a property you can control this behavior with, the NSSupportsAutomaticGraphicsSwitching key as detailed in the Allowing OpenGL applications to utilize the integrated GPU QA

 

iOS and vectorial artwork

Any conscious iOS developer wants his artwork to look as good as possible, and with the retina display for example we were told to upgrade our artwork to higher resolution, which involved alternative @2x versions for each file and gets daunting fast if you have a lot of artwork files, and especially if a lot of your artwork is vectorial and you could just use it directly.

A popular vectorial format is PDF, and Apple has implemented a lot of the resolution independent artwork in their OSX apps as PDF, unfortunately there is no straightforward way to do that, the iOS SDK does not yet have the PDFKit.framework that exists on OSX (Interface Builder does still accept pdf files as images but they will not show on iOS) so what is there to do ?

Well the only way to do it currently is to set your artwork images in code, after rendering the PDF file into a UIImage, there are a couple of approaches to this and i am going to show you the one i use :

#include <dlfcn.h>

-(UIImage *)UIImageFromPDF:(NSString*)fileName size:(CGSize)size{
    CFURLRef pdfURL = CFBundleCopyResourceURL(CFBundleGetMainBundle(), (CFStringRef)fileName, NULL, NULL);
    if (pdfURL) {
        CGPDFDocumentRef pdf = CGPDFDocumentCreateWithURL(pdfURL);
        CFRelease(pdfURL);
        //create context with scaling 0.0 as to get the main screen's if iOS4+
        if (dlsym(RTLD_DEFAULT,"UIGraphicsBeginImageContextWithOptions") == NULL) {
            UIGraphicsBeginImageContext(size);
        }else {
            UIGraphicsBeginImageContextWithOptions(size,NO,0.0);
        }
        CGContextRef context = UIGraphicsGetCurrentContext();
        //translate the content
        CGContextTranslateCTM(context, 0.0, size.height);
        CGContextScaleCTM(context, 1.0, -1.0);
        CGContextSaveGState(context);
        //scale to our desired size
        CGPDFPageRef page = CGPDFDocumentGetPage(pdf, 1);
        CGAffineTransform pdfTransform = CGPDFPageGetDrawingTransform(page,kCGPDFCropBox,CGRectMake(0,0,size.width,size.height),0,true);
        CGContextConcatCTM(context, pdfTransform);
        CGContextDrawPDFPage(context, page);
        CGContextRestoreGState(context);
        //return autoreleased UIImage
        UIImage *ret = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
        CGPDFDocumentRelease(pdf);
        return ret;
    }else {
        NSLog(@"Could not load %@",fileName);
    }
    return nil;
}

Typically you would use it like this : [someButton setImage:[self UIImageFromPDF:@”search.pdf” size:CGSizeMake(20,20)] forState:UIControlStateNormal];

The best thing about this is that it not only makes your artwork compatible with the current form and scaling factors, but most likely with further ones as well.

This is compatible with iOS 3.0+ and has been tested on iPhone and iPad, it is compatible with any resolution scaling (retina display has 2.0 for example) , i have also attached 4 pdf icons to get you started (created with Photoshop, exported with no layers or color profiles).

If for some reason you do not want to #include dlfcn.h and use dlsym() you can weak link UIKit and just check if UIGraphicsBeginImageContextWithOptions is NULL, or obviously if you are not supporting anything before iOS4 remove the conditional altogether.

NOTE: technically on IOS 4  you can currently exploit a bug and load a pdf file from [UIImage imageNamed:@”filename”] by stripping the extension, however the default size of the artwork in the pdf has to be exactly the size of the UIImage you want, if it gets scaled significant pixelation occurs basically making this shortcut unfeasible, plus it could stop working altogether at any time.

iphone signal testing with code

Closest cell tower 1 Km, iPhone 3G, Wi-fi mode, iOS 4.0, Orange network.

With device held gently by edges:

signal avg 90 (outdoor, line of sight to cell tower, same altitude)
signal avg 😯 (indoor, line of sight to cell tower, same altitude)
signal avg 60 (indoor, no line of sight to cell tower, same altitude)
signal avg 4O (outdoor, no line of sight to cell tower, ground level)

With device cradled in hand a average decrease of signal by about 20 in all cases and whatever finger configuration.

Turning 3G on causes a average decrease of signal by 5 in all cases.

The connection strength bars shows 5 bars in all cases.

Absolute minimum experienced : 19, absolute maximum 96.

The thing to take away from all this is that if  you already had a very bad connection under 20 and subtract the hand attenuation of about 20 you are left with no signal, and it did not hep that until iOS 4.0.1  a bad connection with a 20 strength would have shown 4 or even 5 bars.

The application used to test gets the signal strength from private calls to apple’s CoreTelephony framework, in a effort to help the iphone signal testing going on share a common base i am providing the application to anyone, please let me know what are the results of your tests and feel free to contribute to the code on github.

The application is named  VAFieldTest , it’s code is under a open source license and can be found at http://github.com/valexa/VAFieldTest , you need Xcode and a iPhone developer account to compile and run it.

iOS 4.0.1 update
same behavior as before, with the difference that now the connection bars properly reflect changes in the strength (I 1-19, II 20-29, III 30-39, IIII 40-49, IIIII 50-99 ) , with previous versions they just show 5 bars for any signal strengths above 25.

enforcing iAd implementations


There seems to be a significant issue with the iAd implementation at the moment, the ads themselves are not cached on the operating system, and that has two major implications:
1 – ads can be disabled by the user by just turning off the network connection
2 – the user has incentive to disable ads under pricy data plans as every load adds to their data quota

To a developer this gives a strong incentive to both give the user the ability to purchase a removal of ads and make sure the user does not turn adds off otherwise (i am even starting to see places advising users to do so) i will go on showing how to do both and all the code is given as a xcode project attached.

Wether you have a free application and your business model depends solely on iAd’s or you monetize in other ways, if you implemented iAd you have to acknowledge the next thing:
People will want to remove the ads if at all possible, if you implemented iAd you should also allow the user to make an in app purchase for removing the ads, i will also show you how to do that in the code attached as a xcode project.


Do not get me wrong, i believe that some of the users will make the right choice and pay compensation in return of removing the ads if you give them that option, but a lot of the people will make the choice of depriving you of your ad income if they can make them stop loading.
So i will also show you how to implement a way to check if a ad was loaded after a amount of time and effectively disable the application otherwise, you can find the code in the xcode project attached.

I want to end with saying that this is clearly not a ideal situation and i hope that Apple will move quickly to address both issues 1 and 2 from within the operating system which would make a lot of sense and is a case of how they should have leveraged the fact that they built it within the operating system in the first place.

Now i will give you some details about the code, it supports all interface orientations, all devices, it requires 2 frameworks (iAd and StoreKit with iAd being weak linked) , the bulk of the code is in iAdAppViewController, this is the only one you need to edit to suit your interface and change com.foo.bar.removeads to your ProductID, besides that there is a PaymentObserver class that handles the in-app purchasing.

AdAppViewController must implement the PaymentObserverDelegate and ADBannerViewDelegate protocols, it subclasses viewDidLoad to do the initializations, viewDidAppear to position the elements, adLoadCheck to check if the ad was loaded, adsButtonPressed for when the user buys, removedAdsPurchased for when the purchase is confirmed, bannerViewDidLoadAd fires when an ad loads and willAnimateRotationToInterfaceOrientation when the device orientation is changed, resizeBanner is the code called to position/reposition the ad and the other elements in your interface.

ADBannerView *adBanner is the banner itself,  UIButton *adButton is the button above the ad to purchase ad removal, UIView *adBlockView is the view presented over the interface as shown in the image to the right.

I will not go into more detail than this other than to say it was all tested and should work as expected, but i did not implement this myself and i give no absolute guarantees , if you have any specific question leave it as a comment.