590Adding an UIAlertView

Unlike other UIViews, UIAlertView does not need to be added to another view via addSubView. [myAlertView show] takes care of that.

Trivial, maybe. But I wasn't aware of it.

583UIAlertViews additional Buttons

UIAlertView *alert = [[UIAlertView alloc]
     initWithTitle:@"Hello"
     message:@"Do you really want to?"
     delegate:self
     cancelButtonTitle:@"Cancel" 
     otherButtonTitles:@"OK", nil];

The intuively unobvious thing is, that otherButtonTitles requires a nil-terminated, comma-seperated list(?) of NSStrings.

Although you can add (any number?) of additional buttons, it gets silly after about 3.

Another thing to note is that in the case of two buttons, they get displayed side by side, whereas one button or more than two are shown vertically stacked.

581Resizing an UIImage

Nice and simple Category to resize an UIImage

@interface UIImage (Resize)

- (UIImage*)scaleToSize:(CGSize)size;

@end
#import "UIImageResize.h"
#import 

@implementation UIImage (Resize)

- (UIImage*)scaleToSize:(CGSize)size {

    UIGraphicsBeginImageContext(size);

    [self drawInRect:CGRectMake(0, 0, size.width, size.height)];

    UIImage* scaledImage = UIGraphicsGetImageFromCurrentImageContext();

    UIGraphicsEndImageContext();

    return scaledImage;
}

@end

576NSDictionary and NSArray plist examples

NSDictionary





    arrayKey
    
        string1
        string2
        string3
        string4
    
    dicKey
    
        key1
        object1
        key2
        object2
        key3
        object3
    
    key2
    object2
    key3
    object3



NSArray





    string1
    string2
    string3
    
        key1
        object1
        key2
        object2
        key3
        object3
    
    string5



At the end, after </plist>, there's another CR.

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.

566Writing and Reading Preferences

Writing

CFStringRef textColorKey = CFSTR("defaultTextColor");
CFStringRef colorBLUE = CFSTR("BLUE");
CFPreferencesSetAppValue(textColorKey, colorBLUE, kCFPreferencesCurrentApplication);
CFPreferencesAppSynchronize(kCFPreferencesCurrentApplication);

Reading

CFStringRef textColorKey2 = CFSTR("defaultTextColor");
CFStringRef textColor;
textColor = (CFStringRef)CFPreferencesCopyAppValue(textColorKey2,kCFPreferencesCurrentApplication);

textColor must still be releasesed with CFRelease(textColor);

Side note As we should know by now, CFStringRef is a toll-free bridge to NSString, meaning it's possible to use a CFStringRef like a NSString.

NSLog(@"my CFStringRef %@", textColor);

More at Preferences Programming Topics for Core Foundation

565Stripping Characters from an NSString

NSString *stripped = [unstripped stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"\n\t "]];

Well, Cocoa, a bit of too much syntactic nutrasweet here. Take a look at PHP and wheep:

$stripped = trim($unstripped);

(Yes, I am aware that's somewhat of an unfair comparion, but still...)

564NSData to NSString and vice versa

From NSData to NSString:

NSString *s = [[NSString alloc] initWithData:d encoding:NSUTF8StringEncoding];

And the other way round:

NSData *d = [s dataUsingEncoding:NSUTF8StringEncoding]:

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

553CAAnimation and the Snapback Problem

Having previously done Core Animation only on the iPhone, I am still a beginner when it comes dealing with in on OSX.

The first thing that surprised me, is that layers have implicit animations; meaning whenever you change a value, the layer will animate to it using certain defaults. (duration = 0.25, etc.) While it is nice, I am still looking for a way to control it.

When you want to know, when an animation is finished, you need to make a CAAnimation, set the delegate and let it call animationDidStop:

CAAnimationGroup *group = [CAAnimationGroup animation];
group.delegate = self;
group.duration = 0.25;
group.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];

CABasicAnimation *position = [CABasicAnimation animationWithKeyPath:@"position"];
position.fromValue = fromPointValue;
position.toValue = toPointValue;

CABasicAnimation *opacity = [CABasicAnimation animationWithKeyPath:@"opacity"];
opacity.fromValue = [NSNumber numberWithFloat:1.0];
opacity.toValue = [NSNumber numberWithFloat:0.0];

group.animations = [NSArray arrayWithObjects:position, opacity, nil];

[removeTarget addAnimation:group forKey:@"group"];

While this animates nicely, it still is not quite right. Because the layer basically does not know, that it values are changed in the animation, and therefore, after the animation stopped, the values are reset to the ones BEFORE the animation.

That's the annoying snapback.

To get rid of it, tell the layer the new values, right after you add the animation.

removeTarget.opacity = 0.0;
removeTarget.position = toPointValue;

%nbsp;

Interesting to see, that others seem to go throught the same learning experience.