Archive for December, 2010

[iOS] Asynchronous Library in Objective-C

Tuesday, December 28th, 2010

I made a asynchronous library in Objective-C.
Here is Project file.

What is this ?

Asynchronous library is one of the CommandPettern.
Set a command, and execute it.
Then it can call method asynchronously.

Class Explanation

Command > Base class
WaitCommand > timer class
FunctionCommand > function class
SerialCommand > it call registered methods sequentially
ParallelCommand > it call registered methods at the same time

Inspired from
These ActionScript 3 libraries in Japan.
Commands (@fladdict)
Progression(@nium)

How to use

First, you copy below picture files.

WaitCommand test

- (void)commandCompleteHandler:(NSNotification *)aNotification
{
	NSLog(@"command complete !");
}

- (void)waitCommandTest
{
	WaitCommand *wc = [[WaitCommand alloc] initWithTime:1.0];
	[wc addEventListener:kCommandEventCommandComplete target:self listener:@selector(commandCompleteHandler:)];
	[wc execute];
	[wc release];
}

FunctionCommand test

- (void)commandCompleteHandler:(NSNotification *)aNotification
{
	NSLog(@"command complete !");
}

- (void)testFunction
{
	NSLog(@"test function");
}

- (void)functionCommandTest
{
	FunctionCommand *fc = [[FunctionCommand alloc] initWithTarget:self selector:@selector(testFunction)];
	[fc addEventListener:kCommandEventCommandComplete target:self listener:@selector(commandCompleteHandler:)];
	[fc execute];
	[fc release];
}

SerialCommand test

- (void)commandCompleteHandler:(NSNotification *)aNotification
{
	NSLog(@"command complete !");
}

- (void)testFunction
{
	NSLog(@"test function");
}

- (void)serialCommandTest
{
	SerialCommand *sc = [[SerialCommand alloc] init];
	WaitCommand *wc = [[WaitCommand alloc] initWithTime:1.5];
	FunctionCommand *fc = [[FunctionCommand alloc] initWithTarget:self selector:@selector(testFunction)];
	
	[sc addCommand:wc];
	[sc addCommand:fc];
	[sc addEventListener:kCommandEventCommandComplete target:self listener:@selector(commandCompleteHandler:)];
	[sc execute];

	[wc release];
	[fc release];
}

ParallelCommand test

- (void)commandCompleteHandler:(NSNotification *)aNotification
{
	NSLog(@"command complete !");
}

- (void)testFunction
{
	NSLog(@"test function");
}

- (void)parallelCommandTest
{
	ParallelCommand *pc = [[ParallelCommand alloc] init];
	WaitCommand *wc = [[WaitCommand alloc] initWithTime:1.5];
	FunctionCommand *fc = [[FunctionCommand alloc] initWithTarget:self selector:@selector(testFunction)];
	
	[pc addCommand:wc];
	[pc addCommand:fc];
	[pc addEventListener:kCommandEventCommandComplete target:self listener:@selector(commandCompleteHandler:)];
	[pc execute];

	[wc release];
	[fc release];
}

PrallelCommand and SerialCommand Mixed test

- (void)commandCompleteHandler:(NSNotification *)aNotification
{
	NSLog(@"command complete !");
}

- (void)testFunction
{
	NSLog(@"test function");
}

- (void)testFunction2:(id)arg1
{
	NSLog(@"testFunction 2, arg1 = %@", arg1);
}

- (void)testFunction3:(id)arg1 arg2:(id)arg2
{
	NSLog(@"testFunction 2, arg1 = %@, arg2 = %@", arg1, arg2);
}

- (void)parallelSerialMixedTest
{
	ParallelCommand *pc = [[ParallelCommand alloc] init];
	WaitCommand *wc = [[WaitCommand alloc] initWithTime:1.5];
	FunctionCommand *fc = [[FunctionCommand alloc] initWithTarget:self selector:@selector(testFunction)];
	FunctionCommand *fc2 = [[FunctionCommand alloc] initWithTarget:self selector:@selector(testFunction2:) withObject:[UIColor blueColor]];
	UIViewController *vc = [[UIViewController alloc] init];
	FunctionCommand *fc3 = [[FunctionCommand alloc] initWithTarget:self selector:@selector(testFunction3:arg2:) withObject:@"Hello command !" withObject:vc];
	[vc release];
	WaitCommand *wc2 = [[WaitCommand alloc] initWithTime:1.0];
	SerialCommand *sc = [[SerialCommand alloc] init];
	[pc addCommand:fc];
	[pc addCommand:fc2];
	[pc addCommand:fc3];
	
	[sc addCommand:wc];
	[sc addCommand:fc];
	[sc addCommand:wc2];
	[sc addCommand:pc];
	
	[sc addEventListener:kCommandEventCommandComplete target:self listener:@selector(commandCompleteHandler:)];
	[sc execute];
	
	[pc release];
	[wc release];
	[fc release];
	[fc2 release];
	[fc3 release];
	[wc2 release];
}

[iOS] EventDispatcher Class in Objective-C

Tuesday, December 28th, 2010

I am a iOS developer, and also a Flash Developer.
I wanted to EventDispatcher class in objective-c.
And I implemented it.

*update Feb.8.2011

IEventDispatcher.h

#import <Foundation/Foundation.h>

@protocol IEventDispatcher
- (void)addEventListener:(NSString *)type target:(id)target listener:(SEL)listener;
- (void)removeEventListener:(NSString *)type target:(id)target;
- (void)dispatchEvent:(NSString *)type;
@end

EventDispatcher.h

#import <Foundation/Foundation.h>
#import "IEventDispatcher.h"

@interface EventDispatcher : NSObject <IEventDispatcher> {
	NSMutableDictionary *targets;
}
@property (nonatomic, retain) NSMutableDictionary *targets;
- (void)addEventListener:(NSString *)type target:(id)target listener:(SEL)listener;
- (void)removeEventListener:(NSString *)type target:(id)target;
- (void)dispatchEvent:(NSString *)type;
@end

EventDispatcher.m


#import "EventDispatcher.h"


@implementation EventDispatcher
@synthesize targets;

- (id)init
{
	if ((self = [super init])) {
		NSMutableDictionary *mytargets = [[NSMutableDictionary alloc] init];
		self.targets = mytargets;
		[mytargets release];
	}
	return self;
}

- (void)addEventListener:(NSString *)type target:(id)target listener:(SEL)listener
{
	NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
	NSString *identifier = [type stringByAppendingFormat:@"_%d", &(*target)];
	if ([targets valueForKey:identifier] == nil) {
		[center addObserver:target selector:listener name:type object:self];
		[targets setObject:target forKey:identifier];
	}
}

- (void)removeEventListener:(NSString *)type target:(id)target
{
	NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
	NSString *identifier = [type stringByAppendingFormat:@"_%d", &(*target)];
	if ([targets valueForKey:identifier] != nil) {
		[center removeObserver:target name:type object:self];
		[targets removeObjectForKey:identifier];
	}
}

/**
 * Override this method. if you want to custom userInfo
 */
- (void)dispatchEvent:(NSString *)type
{
	NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
	[center postNotificationName:type object:self userInfo:nil];
}

- (void)dealloc
{
	NSNotificationCenter *center = [NSNotificationCenter defaultCenter];
	for(NSString *identifier in targets){
		NSArray *idenntifierArr = [identifier componentsSeparatedByString:@"_"];
		[center removeObserver:[targets objectForKey:identifier] 
						  name:[idenntifierArr objectAtIndex:0] 
						object:self];
	}
	[targets removeAllObjects];
	[targets release];
	[super dealloc];
}
@end

how to use

set handler method

- (void)testHandler:(NSNotification *)aNotification
{
	NSLog(@"test handler");
	
	NSLog(@"name is %@", aNotification.name);
	NSLog(@"object is %@", aNotification.object);
	NSLog(@"info is %@", aNotification.userInfo);
}

and test

    EventDispatcher *myEd = [[[EventDispatcher alloc] init] autorelease];
	[myEd addEventListener:@"EventComplete" target:self listener:@selector(testHandler:)];
	[myEd dispatchEvent:@"EventComplete"];

Sample project file is here.

This article is very useful. Thanks
>> ustom Events in Objective-C | Raphael Wichmann

[iOS] Call CGImageCreateWithImageInRect with CGImageRelease

Wednesday, December 22nd, 2010
	NSString *path = [[NSBundle mainBundle] pathForResource:@"myimage" ofType:@"png"];
	UIImage *img = [[UIImage alloc] initWithContentsOfFile:path];
	CGImageRef clipImage = CGImageCreateWithImageInRect(img.CGImage, CGRectMake(0, 100, 100, 200));
	//do something
	CGImageRelease(clipImage);
	[img release];

[iOS] UIImage CGImage clipping and copy in rect

Wednesday, December 22nd, 2010

I created useful UIimage utilty class.

UIImageDrawUtil.h

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

@interface UIImageDrawUtil : NSObject {

}
/*
 * clipping sourceImage in sourceRect. and copy it to targetImage in destPoint
 * returns new UIImage
 * This dimension is in UIImage, not in QuarzCore
 */
+ (UIImage *)copyPixels:(UIImage *)targetImage sourceImage:(UIImage *)sourceImage sourceRect:(CGRect)sourceRect destPoint:(CGPoint)destPoint;
@end

UIImageDrawUtil.m

#import "UIImageDrawUtil.h"
#import <QuartzCore/QuartzCore.h>

@implementation UIImageDrawUtil
+ (UIImage *)copyPixels:(UIImage *)targetImage sourceImage:(UIImage *)sourceImage sourceRect:(CGRect)sourceRect destPoint:(CGPoint)destPoint
{
	CGImageRef tempImage = CGImageCreateWithImageInRect(sourceImage.CGImage, sourceRect);
	int tw = targetImage.size.width;
	int th = targetImage.size.height;
	int tempw = CGImageGetWidth(tempImage);
	int temph = CGImageGetHeight(tempImage);

	UIGraphicsBeginImageContext(CGSizeMake(tw, th));
	CGContextRef ctx = UIGraphicsGetCurrentContext();
	CGContextTranslateCTM(ctx, 0, th);
	CGContextScaleCTM(ctx, 1.0, -1.0);
	CGContextDrawImage(ctx, CGRectMake(0, 0, tw, th), targetImage.CGImage);	
	CGContextClipToRect(ctx, CGRectMake(destPoint.x, th - temph -destPoint.y, tempw, temph));
	CGContextDrawImage(ctx, CGRectMake(destPoint.x, th - temph -destPoint.y, tempw, temph), tempImage);
	UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
	UIGraphicsEndImageContext();
	CGImageRelease(tempImage);
	tempImage = NULL;
	return newImage;
}
@end

how to use

There is 400 x 400 png.
This name is myimage.png.

and write below code.

- (void)viewDidLoad {
    [super viewDidLoad];
	
	NSString *path = [[NSBundle mainBundle] pathForResource:@"myimage" ofType:@"png"];
	UIImage *img = [[UIImage alloc] initWithContentsOfFile:path];
	CGImageRef clipImage = CGImageCreateWithImageInRect(img.CGImage, CGRectMake(0, 100, 100, 200));
	UIImage *newImage = [UIImageDrawUtil copyPixels:[UIImage imageWithCGImage:clipImage] sourceImage:img sourceRect:CGRectMake(100, 0, 100, 100) destPoint:CGPointMake(0, 50)];
	UIImageView *imgView = [[UIImageView alloc] initWithImage:newImage];
	[self.view addSubview:imgView];
	
	CGImageRelease(clipImage);
	clipImage = nil;
	newImage = nil;

	[imgView release];
	imgView = nil;
	[img release];
	img = nil;
}

Then result is

[iOS] How to protect view autoresize in UIPopoverController

Tuesday, December 21st, 2010

I tried to add UINavigationController in UIPopoverController.
The navigationController has UITableView.
When the tableView cell was selected, pushed more tableView to navigationController.
But popover automatically resizing to max height.

I googled this problem.
I found this page.
UIPopoverController automatically resizing to max height on pushViewController

Just one !

And I solved the problem.

Each TableView must set the property named contentSizeForViewInPopover.
I set the property in viewDidLoad.
And fixed it.

[iOS] how to archive and unarchive custom struct and array.

Tuesday, December 14th, 2010

I saw this page.
>> How to store custom objects with struct in Coredata

MyData.h

#import <UIKit/UIKit.h>

typedef struct{
	float data1;
	int data2;
} MyStruct;

@interface MyData : NSObject <NSCoding>{
	NSString *str;
	int count;
	float myf;
	MyStruct mystruct2;
	CGPoint pt;
	int *array1;
}
@property (nonatomic, retain) NSString *str;
@property (assign) int count;
@property (assign) float myf;
@property (assign) CGPoint pt;
@property (assign) MyStruct mystruct2;
@property (assign) int *array1;
@end

MyData.mm

#import "MyData.h"

@implementation MyData
@synthesize str, count, myf;
@synthesize pt;
@synthesize mystruct2;
@synthesize array1;

- (void)encodeWithCoder:(NSCoder *)encoder
{
	[encoder encodeObject:str forKey:@"str"];
	[encoder encodeInt:count forKey:@"mycount"];
	[encoder encodeFloat:myf forKey:@"myfloat"];
	NSValue *value = [NSValue valueWithCGPoint:pt];
	[encoder encodeObject:value forKey:@"mypt"];
	[encoder encodeObject:[NSData dataWithBytes:&mystruct2 length:sizeof(MyStruct)] forKey:@"mystruct"];
	[encoder encodeObject:[NSData dataWithBytes:array1 length:sizeof(int) * 3] forKey:@"myarr"];
}

- (id)initWithCoder:(NSCoder *)decoder
{
	if (self = [super init]) {
		self.str = [decoder decodeObjectForKey:@"str"];	
		self.count = [decoder decodeIntForKey:@"mycount"];
		self.myf = [decoder decodeFloatForKey:@"myfloat"];
		NSValue *value = [decoder decodeObjectForKey:@"mypt"];
		[value getValue:&pt];		
		NSData *data = [decoder decodeObjectForKey:@"mystruct"];
		[data getBytes:&mystruct2 length:sizeof(MyStruct)];
		NSData *data2 = [decoder decodeObjectForKey:@"myarr"];
		NSLog(@"data2 = %@", data2);
		array1 = new int[3];
		[data2 getBytes:array1 length:sizeof(int) * 3];
	}
	return self;
}

- (void)dealloc
{
	if (array1) {		
		delete [] array1;
		NSLog(@"delete");
	}
	[super dealloc];
}
@end

ViewController.h

#import <UIKit/UIKit.h>

@interface ArchiveTest2ViewController : UIViewController {

}
- (IBAction)savePressed;
- (IBAction)loadPressed;
@end

ViewController.mm

#import "ArchiveTest2ViewController.h"
#import "MyData.h"

@implementation ArchiveTest2ViewController

- (NSString *)dataFilePath
{
	NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
	NSString *documentsDir = [paths objectAtIndex:0];
	return [documentsDir stringByAppendingPathComponent:@"archive"];
}

- (IBAction)savePressed
{
	MyData *mydata = [[MyData alloc] init];
	mydata.str = @"My Data !!";
	mydata.count = 12;
	mydata.myf = 0.35;

	MyStruct mystruct;
	mystruct.data1 = 0.98;
	mystruct.data2 = 888;
	mydata.mystruct2 = mystruct;

	CGPoint pt = CGPointMake(13.0, 12.5);
	mydata.pt = pt;
	
	int *arr = new int[3];
	arr[0] = 183;
	arr[1] = 283;
	arr[2] = 200;
	mydata.array1 = arr;

	NSMutableData *data = [[NSMutableData alloc] init];
	NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:data];
	[archiver encodeObject:mydata forKey:@"Data"];
	[archiver finishEncoding];
	[data writeToFile:[self dataFilePath] atomically:YES];
	
	[mydata release];
	[archiver release];
	[data release];
}

- (IBAction)loadPressed
{
	NSString *filePath = [self dataFilePath];
	if ([[NSFileManager defaultManager] fileExistsAtPath:filePath]) {
		NSData *data = [[NSMutableData alloc] initWithContentsOfFile:[self dataFilePath]];
		NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
		MyData *mydata = [unarchiver decodeObjectForKey:@"Data"];
		[unarchiver finishDecoding];
		
		NSLog(@"str = %@", mydata.str);
		NSLog(@"count = %d", mydata.count);
		NSLog(@"float = %f", mydata.myf);
		NSLog(@"pt = %@", NSStringFromCGPoint(mydata.pt));
		NSLog(@"myst = %f, %d", mydata.mystruct2.data1, mydata.mystruct2.data2);
		int *arr = mydata.array1;
		NSLog(@"array = %d, %d, %d", arr[0], arr[1], arr[2]);
		[unarchiver release];
		[data release];
	}
}



- (void)didReceiveMemoryWarning {
	// Releases the view if it doesn't have a superview.
    [super didReceiveMemoryWarning];
	
	// Release any cached data, images, etc that aren't in use.
}

- (void)viewDidUnload {
	// Release any retained subviews of the main view.
	// e.g. self.myOutlet = nil;
}


- (void)dealloc {
    [super dealloc];
}

@end