569Layering one UIImage onto of another UIImage

Combining two images, especially useful, if the overlay image has an alpha value:

//
//  UIImage+Category.h
//  ImageOverlay
//
//  Created by Georg Tremmel on 29/04/2010.
//

#import 

@interface UIImage (combine)

- (UIImage*)overlayWith:(UIImage*)overlayImage;

@end

And the implementation file.

//
//  UIImage+Category.m
//  ImageOverlay
//
//  Created by Georg Tremmel on 29/04/2010.
//

#import "UIImage+Category.h"

@implementation UIImage (combine)

- (UIImage*)overlayWith:(UIImage*)overlayImage {

    // size is taken from the background image
    UIGraphicsBeginImageContext(self.size);

    [self drawAtPoint:CGPointZero];
    [overlayImage drawAtPoint:CGPointZero];

    /*
    // If Image Artifacts appear, replace the "overlayImage drawAtPoint" , method with the following
    // Yes, it's a workaround, yes I filed a bug report
    CGRect imageRect = CGRectMake(0, 0, self.size.width, self.size.height);
    [overlayImage drawInRect:imageRect blendMode:kCGBlendModeOverlay alpha:0.999999999];
    */

    UIImage *combinedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return combinedImage;
}

@end

An update to 334 Combining Images with UIImage & CGContext – (Offscreen drawing)

(Did I say, how much I love Categories...?)

Update I came across some strange behaviour when layering a PNG image with transparency over another image. Did not show up in the Simulator, only in iPhone 3GS (and probably also on other devices.) The base image draws fine, but the overlay image appears to be truncated and the last pixels shifted, producing some bright green artifacts. Changing

[overlayImage drawAtPoint:CGPointZero];

to

CGRect imageRect = CGRectMake(0, 0, self.size.width, self.size.height);
[overlayImage drawInRect:imageRect blendMode:kCGBlendModeOverlay alpha:1.0];

did not really help; the green artifacts remainded. It was strange though, that they did not appear in the other blendmodes. Using

CGContextDrawImage(c, imageRect, [overlayImage CGImage]);

would also work, but then the images turn up upside down. Not what I really needed. (Yes, I know, there might not be a hard fix for that, but really - it should be that complicated.)

After playing a bit more with the values, I found, that setting alpha lower than 1.0 gets rid of the display artifact:

[overlayImage drawInRect:imageRect blendMode:kCGBlendModeOverlay alpha:0.9999999];

Bug filed at Apple's Bug Report, let's see. Or maybe am I missing something here?

Anyway here they the files are, zipped and ready for download.

Post Scriptum

Test Project, showing the visual artifact in action. Only appears on the device, NOT IN THE SIMULATOR.

560#import vs #include in Objective C – A quick reminder

#import is identical to #include, except that it makes sure that the same file is never included more than once. It’s therefore preferred and is used in place of #include in code examples throughout Objective-C–based documentation.

http://developer.apple.com/ mac/library/documentation/ cocoa/conceptual/ObjectiveC /Articles/ ocDefiningClasses.html

457Singleton Classes and Shared Resources in Objective-C

Resource.h

#import 

@interface Resource : NSObject {
    float myValue;
}

@property float scale;

+ (id)shared;

@end

 

Resource.m

#import "Resource.h"

@implementation Resource

@synthesize scale;

- (id)init {
    scale = 1.0f    // my default value
}

+ (id)shared {
    static Resource *sharedResource = nil;
    if (!sharedResource) {
        sharedResource = [[self alloc] init];
    }
    return sharedResource;
}
@end

An now it can be used like the following:

Resource *r = [Resource shared];
NSLog(@"Resource Test: %f", [r myValue]);
// Resource Test: 1.000000

[r setMyValue:2.0];
NSLog(@"Resource Test: %f", [r myValue]);
//# Resource Test: 2.000000

Resource *s = [Resource shared];
[s setMyValue:2.111];
NSLog(@"Resource Test: %f", [s myValue]);
// Resource Test: 2.111000

NSLog(@"Resource Test: %f", [r myValue]);
//Resource Test: 2.111000

Note that the values stays constant, even if another instantionation occurs. I guess that's what Singleton classes are all about.

Adapted from Scott Stevenson's fantastic introduction at Cocoa Dev Central.

And more tutorials from Scott Stevenson... Cocoa Dev Central: Learn C for Cocoa Cocoa Dev Central: Learn Objective C

420Getting current Time with Microseconds

#import <sys/time.h>

struct timeval tv;
gettimeofday(&tv, NULL);
int sec = tv.tv_sec;
int usec = tv.tv_usec;
The system's notion of the current Greenwich time and the current time zone is obtained with the gettimeofday() call, and set with the ettimeofday() call. The time is expressed in seconds and microseconds since midnight (0 hour), January 1, 1970. The resolution of the system clock is hardware dependent, and the time may be updated continuously or in ``ticks.'' If tp is NULL and tzp is non-NULL, gettimeofday() will opulate the timezone struct in tzp. If tp is non-NULL and tzp is NULL, then only the timeval struct in tp is populated. If both tp and tzp are NULL, nothing is returned.

Check out the man page for more info.

289Simulating Keyboard & Mouse Events. And Key-Modifier Events

Creating and Posting a Keyboard Event:

CGEventRef sDown, sUp;
sDown = CGEventCreateKeyboardEvent (
            NULL,
            (CGKeyCode)1,
            true
);
CGEventSetFlags(sDown, kCGEventFlagMaskShift);  

// setting flags with special function. 
// Setting it via CGCreateKeyboardEvent
// would work only for the first time it's run

CGEventPost(kCGHIDEventTap, sDown);

sUp = CGEventCreateKeyboardEvent (
            NULL,
            (CGKeyCode)1,
            false
);
CGEventPost(kCGHIDEventTap, sUp);

CFRelease(sDown);
CFRelease(sUp);

That leaves the door open for applying the same to mouse events:

CGEventRef mouseEvent;
mouseEvent = CGEventCreateMouseEvent (
            NULL,
            kCGEventMouseMoved,
            CGPointMake(100, 100),
            kCGMouseButtonLeft
);
CGEventPost(kCGHIDEventTap, mouseEvent );

Magical. Isn't it.

Of course, in pre-10.6 days it would have looked like that:

CGPostKeyboardEvent (0,5,true);
CGPostKeyboardEvent (0,5,false);

275UIWebView – checking when user clicks a link

- (BOOL)webView:(UIWebView )webView shouldStartLoadWithRequest:(NSURLRequest )request navigationType:(UIWebViewNavigationType)navigationType {

// intercepting web click in the webView
NSLog(@"%@,  %i", [request.URL absoluteString], navigationType);

}

Don't forget to set <UIWebViewDelegate>

269Caching on Objective-C with NSURLCache

A quick reminder on how caching works in Objective-C.

Initially there is one cache, NSURLCache administrates it.

Get the object:

NSURLCache *cache = [NSURLCache sharedURLCache]

[cache memoryCapacity];
[cache setMemoryCapacity: 1024*1024*1]; // in byte
[cache currentMemoryUsage];

Don't worry about the disk aka the flash memory in iPhone, it's not accessible.

A bit of strange behaviour, either a bug in the software or in my brain: When changing ViewControllers the memoryCapacity seems to reset itself to 0, although previous caches remain intact. Re-setting the memoryCapacity back to the original level seems to solve this. (The cache is not overwritten.)

Using the Cache The whole point of using the cache is to not download online material over again. The following steps make for a happy cache:

//URLRequest
NSURLRequest *request = [NSURLRequest requestWithURL:theURL
cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10.0f];

The delegate response would allow you to alter the about-to-be-cached-data, leaving it in is not necessary:

- (NSCachedURLResponse *)connection:(NSURLConnection *)c
willCacheResponse:(NSCachedURLResponse *)response {
    NSLog(@"willCacheResponse");
    return response;
}

All in all, not that much to take it. Finding out, that the memoryCapacity gets reset was the most time-consuming bit. For another example, of how to roll your own cache, look at URLCache example.

265Like explode(), only componentsSeparatedByString:

PHP explode(", " , "One, Two, Three");

Objective-C NSArray *listItems = [@"One, Two, Three" componentsSeparatedByString:@", "];

259The mystery of self.* – resolved?

self If you want to access a property of self using accessor methods, you must explicitly call out self as illustrated in this example:
self.age = 10; 
If you do not use self., you access the instance variable directly. In the following example, the set accessor method for the age property is not invoked:
age = 10;

p57, The Objective-C 2.0 Programming Language Language (v2008-06-09) p22, The Objective-C 2.0 Programming Language Language (v2009-10-19)

So basically it's a shortcut to:

int* a = [self age];
[self setAge:12];

(providing there is a setter/getter for age.)

243Stepping over an Array (or Dictionary)

NSArray *paths = [[NSFileManager defaultManager] 
    directoryContentsAtPath: NSHomeDirectory()];

// either like that...
NSEnumerator *e = [paths objectEnumerator];
for (NSString *p in e) {
    NSLog(@"path: %@", p);
}

// or like that.
for (NSString *p in [paths objectEnumerator]) {
    NSLog(@"path: %@", p);
}

NSDictionary has both [myDict objectEnumerator] and [myDict keyEnumerator].

Fast Enumberation is a feature in Objective-C 2.0, it allows you to step over arrays and dictionaries in a fast, consice, and secure (guarded against mutations) manner.

for (NSString *p in paths) {
    NSLog(@"path: %@", p);
}

// or

NSString *p;
for (p in paths) {
    NSLog(@"path: %@", p);
}

Sometimes things are really as simple as they should be.