ALGOBIT

2010/06/22

シェルからCocoa (3) – メモリ管理

Filed under: 離散的な気まぐれ — タグ: , , , — Kohyama @ 15:28

Cocoaメモリ管理プログラミングガイド
何が行われるか自分なりに理解はできたと思う.
今は分かったけど, どうせすぐ忘れるので, 絵入りの簡潔な説明を作っておきたいけど…

何をするべきかはだいたい以下.
自分が, alloc か new で始まる, または copy を含むメソッド名を持つメソッドによってメモリを確保したオブジェクトには, 不要になった時点で release メッセージを送る.
自分がメモリを確保したオブジェクトでないならば, 理由がなければ何のメッセージを送る必要もない.
自分がメモリを確保したオブジェクトでない場合で, オブジェクトを必要とする範囲を明確にしたいならば, retain メッセージを送って必要であることを通知し, 不要になった時に release メッセージを送る.
確保したオブジェクトへの参照を返すメソッドは, 不要になったことを同じスコープの範囲内で通知することができないので, オブジェクトに autorelease メッセージを送り, 「必要な人が他にいないなら自分はもう要らないです.」と宣言しておく.
main() の最初で NSAutoreleasePool を alloc] init する.
main() の最後でそれを release する.
autorelease されたオブジェクトの管理範囲をもうけたければ,
NSAutoreleasePool の alloc] init と release で挟む.
NSAutoreleasePool はスタックを形成するので, 最後に alloc] init したものから順に, release しなければならない. (release した時点で, 最後の alloc] init 以降に autorelease されたオブジェクトの解放が検討される).
メモリを確保し, 参照を返してくれるメソッドによって, オブジェクトの参照を取得した場合, これが不要になった時点で, 最後に alloc] init した NSAutoreleasePool に release メッセージを送る.

シェルからCocoa (2) のコード直した. main() だけなので実際問題にはならないにしてもね.

#import <Cocoa/Cocoa.h>
#import <QTKit/QTKit.h>

int
main(int argc, char *argv[])
{
	NSAutoreleasePool *ap = [[NSAutoreleasePool alloc] init];
	NSFileManager *fm;
	NSString *path, *newpath, *prefix, *dt, *suffix;
	NSImage *img;
	NSArray *arr;
	NSDictionary *dic;
	QTMovie *mov;
	NSError *err;
	NSDateFormatter *df;

	if (argc < 2)
		exit(1);

	/*
	 * prefix and suffix should be variable
	 * but now hard coded.
	 */
	prefix = @"iph";
	suffix = @"";

	/*
	 * to format an NSDate as an NSString of format "YYYYmmddHHMMSS"
	 */
	df = [[NSDateFormatter alloc]
	    initWithDateFormat:@"%Y%m%d%H%M%S"
   		allowNaturalLanguage:FALSE];
	fm = [[NSFileManager alloc] init];
	while (0 < --argc) {
		path = [NSString stringWithCString: *++argv encoding: NSUTF8StringEncoding];
		dt = nil;
		err = nil;

		if (img = [[NSImage alloc] initWithContentsOfFile:path]) {
			if ((arr = [img representations]) &&
				(dic = [[arr objectAtIndex:0] valueForProperty: @"NSImageEXIFData"])) {
				/* now
				 *   [dic objectForKey:@"DateTimeOriginal"]
				 * returns string like "2010:05:13 12:36:45"
				 * let's retrieve colon(':') and space(' ') from this.
				 */
				dt = [[[dic objectForKey:@"DateTimeOriginal"]
					stringByReplacingOccurrencesOfString:@":" withString:@""]
					stringByReplacingOccurrencesOfString:@" " withString:@""];
			} else {
				NSLog(@"Can't recognize NSImage.DateTimeOriginal field of the file : %@", path);
			}
			[img release];

		} else if (mov = [QTMovie movieWithFile:path error:&err]) {
			if (!err) {
				/* now
				 *   [mov attributeForKey:QTMovieCreationTimeAttribute]
				 * returns the datetime as NSDate
				 * let's format it to "YYYYmmddHHMMSS"
				 */
				dt = [df stringFromDate:
					[mov attributeForKey:QTMovieCreationTimeAttribute]];
			} else {
				NSLog(@"Can't recognize QTMovie.CreationTimeAttributes field of the file : %@",
					path);
			}
		} else {
			NSLog(@"Can't recognize format of the file : %@", path);
		}

		if (dt != nil) {
			newpath = [[[path stringByDeletingLastPathComponent]
				stringByAppendingPathComponent: [[prefix stringByAppendingString: dt]
					stringByAppendingString:suffix]]
				stringByAppendingPathExtension: [path pathExtension]];
			if ([fm fileExistsAtPath:newpath]) {
				NSLog(@"'%@' already exists.", newpath);
			} else {
				err = nil;
				[fm moveItemAtPath:path toPath:newpath error:&err];
				if (err)
					NSLog(@"failed to rename '%@' to '%@'.", path, newpath);
				else
					NSLog(@"'%@' has been renamed as '%@'.", path, newpath);
			}
		}
	}

	[fm release];
	[df release];
	[ap release];
	return 0;
}

Copyright © 2010 Yoshinori Kohyama All Rights Reserved.