오브젝트C2010.10.12 04:55
[objective-c] 클래스 멤버변수를 hashmap사용때처럼 key로 사용.
모든 클래스는 NSObject를 상속받으며, 
모든 클래스의 멤버변수명은 key로 간주된다.
변수값이 value이다.

따라서 모든 객체의 멤버변수의 값을 얻기위해 멤버변수명을 키값으로해서 얻을 수 있겠다.
 NSDictionary처럼 모든객체를 딕셔너리처럼 사용할 수 있다.

class Student 의 멤버변수 myName이 있을때, 값이 "angel"이면

멤버변수값을 넣을때
[ student setValue:@"angel" forKey@"MyName"];
빼낼때
NSString *name= [student valueForKey:@"myName"];

Posted by 오늘마감
복잡한 SQLite3 간단하게 하는 클래스
This library is more suitable for smaller databases as right now is automatically transforming all the data from select into the NSMutableArray where every row has it's Own NSMutableDictionary. This is not the best idea if you have loads of data, because that you have all the data in the variable and that means that it eats all your memory and application crashes.

To get some data from database is as easy as that:

  1. NSMutableArray *arr = [conn getData:@"SELECT * FROM testTable;" fromDatabase:@"testDatabase"];  

http://code.google.com/p/sqlite3connector/

Now I'll show you how easy is to connect to the database and retrieve some data.

  1. //
  2. //  ContactsController.h
  3. //  TestApp
  4. //
  5. //  Created by Ondrej Rafaj on 26.10.09.
  6. //  Copyright 2009 Home. All rights reserved.
  7. //
  8. #import 
  9. #import "SQLite3Connector.h"
  10. @interface ContactsController : UIViewController {  
  11.     IBOutlet UITableView *table;  
  12.     IBOutlet UIActivityIndicatorView *preloader;  
  13.     NSMutableArray *data;  
  14.     SQLite3Connector *conn;  
  15. }  
  16. @property (nonatomic, retain) IBOutlet UITableView *table;  
  17. @property (nonatomic, retain) IBOutlet UIActivityIndicatorView *preloader;  
  18. @property (nonatomic, retain) NSMutableArray *data;  
  19. @end  

We've included the SQLite3Connector class into the project and we've created tableView and activity indicator as a preloader, than we have the data variable where we are going to have all the results from the database. Last thing is a class SQLite3Connector which allows you to do all the queries.

  1. //
  2. //  ContactsController.m
  3. //  TestApp
  4. //
  5. //  Created by Ondrej Rafaj on 26.10.09.
  6. //  Copyright 2009 Home. All rights reserved.
  7. //
  8. #import "ContactsController.h"
  9. @implementation ContactsController  
  10. @synthesize table, preloader, data;  
  11. /* 
  12. - (id)initWithStyle:(UITableViewStyle)style { 
  13.     // Override initWithStyle: if you create the controller programmatically and want to perform customization that is not appropriate for viewDidLoad. 
  14.     if (self = [super initWithStyle:style]) { 
  15.     } 
  16.     return self; 
  17. } 
  18. */
  19. - (void) importDataFromContacts {  
  20.     // creating fake data for import
  21.     [conn executeQuery:@"INSERT INTO contacts (name, surname) VALUES ('Ondrej', 'Rafaj');" inDatabase:@"contacts"];  
  22.     [conn executeQuery:@"INSERT INTO contacts (name, surname) VALUES ('Hana', 'Cerna');" inDatabase:@"contacts"];  
  23.     [conn executeQuery:@"INSERT INTO contacts (name, surname) VALUES ('Andrew', 'Walker');" inDatabase:@"contacts"];  
  24.     [conn executeQuery:@"INSERT INTO contacts (name, surname) VALUES ('Greg', 'Jarrett');" inDatabase:@"contacts"];  
  25.     [conn executeQuery:@"INSERT INTO contacts (name, surname) VALUES ('Chris', 'Doull');" inDatabase:@"contacts"];  
  26.     [conn executeQuery:@"INSERT INTO contacts (name, surname) VALUES ('Malc', 'Seaborn');" inDatabase:@"contacts"];  
  27.     [conn executeQuery:@"INSERT INTO contacts (name, surname) VALUES ('Jidh', 'George');" inDatabase:@"contacts"];  
  28. }  
  29. - (void)viewDidLoad {  
  30.     [super viewDidLoad];  
  31.     [preloader startAnimating];  
  32.     conn = [[SQLite3Connector alloc] init];  
  33.     if ([SQLite3Connector databaseExists:@"contacts"]) [SQLite3Connector dropDatabase:@"contacts"];  
  34.     NSString *query = @"";  
  35.     query = @"CREATE TABLE IF NOT EXISTS contacts (id INTEGER PRIMARY KEY AUTOINCREMENT, name VARCHAR, surname VARCHAR);";  
  36.     if (![conn executeQuery:query inDatabase:@"contacts"]) NSAssert1(0, @"Error creating database. (%@)", query);  
  37.     [self importDataFromContacts];  
  38.     NSLog(@"Creating database & importing contacts");  
  39.     data = [conn getData:@"SELECT * FROM contacts ORDER BY surname ASC;" fromDatabase:@"contacts"];  
  40.     [table reloadData];  
  41.     [preloader stopAnimating];  
  42. }  
  43. - (void)didReceiveMemoryWarning {  
  44.     // Releases the view if it doesn't have a superview.
  45.     [super didReceiveMemoryWarning];  
  46.     // Release any cached data, images, etc that aren't in use.
  47. }  
  48. - (void)viewDidUnload {  
  49.     // Release any retained subviews of the main view.
  50.     // e.g. self.myOutlet = nil;
  51. }  
  52. #pragma mark Table view methods
  53. - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {  
  54.     return 1;  
  55. }  
  56. // Customize the number of rows in the table view.
  57. - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {  
  58.     return [data count];  
  59. }  
  60. // Customize the appearance of table view cells.
  61. - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {  
  62.     static NSString *CellIdentifier = @"Cell";  
  63.     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];  
  64.     if (cell == nil) {  
  65.         cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease];  
  66.     }  
  67.     int index = [indexPath indexAtPosition: [indexPath length] - 1];  
  68.     cell.textLabel.text = [NSString stringWithFormat:@"%@, %@", [[data objectAtIndex: index] objectForKey: @"surname"], [[data objectAtIndex: index] objectForKey: @"name"]];  
  69.     return cell;  
  70. }  
  71. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {  
  72.     // Navigation logic may go here. Create and push another view controller.
  73.     // AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:@"AnotherView" bundle:nil];
  74.     // [self.navigationController pushViewController:anotherViewController];
  75.     // [anotherViewController release];
  76. }  
  77. - (void)dealloc {  
  78.     [table, preloader, data release];  
  79.     [super dealloc];  
  80. }  
  81. @end  

Check out the importDataFromContacts and viewDidLoad functions ... here you can see that the handling SQLite is quite piece of cake.

All the source codes are available on the google code here:

Here is a little bit more extended example of what you can do with it, please don't worry about the printResults function, I just took part of the example project as I don't have a time right now to prepare anything better (I want to go home, I'm still stucked in the office and right now is 21:45), ok here we go:

  1. - (void) printResults:(NSString *)text {  
  2.     counter++;  
  3.     textView.text = [NSString stringWithFormat:@"%d) %@\r\n\r\n%@", counter, text, textView.text];  
  4. }  
  5. // Implement viewDidLoad to do additional setup after loading the view, typically from a nib.
  6. - (void)viewDidLoad {  
  7.     [super viewDidLoad];  
  8.     counter = 0;  
  9.     SQLite3Connector *conn = [[SQLite3Connector alloc] init];  
  10.     //[conn getData:@"" fromDatabase:@""];
  11.     NSString *queryCount = @"SELECT COUNT(id) FROM testTable;";  
  12.     [self printResults:[NSString stringWithFormat:@"Directory path: %@", [SQLite3Connector getDocumentsDirectoryPath]]];  
  13.     [self printResults:[NSString stringWithFormat:@"Database folder path: %@", [SQLite3Connector getDatabaseFolderPath]]];  
  14.     [self printResults:[NSString stringWithFormat:@"Database file name: %@", [SQLite3Connector getDatabasePathFromName:@"testDatabase"]]];  
  15.     [self printResults:[NSString stringWithFormat:@"Escape string (it's): %@", [SQLite3Connector escapeString:@"it's"]]];  
  16.     //[self printResults:[NSString stringWithFormat:@"Dropping database: %d", [SQLite3Connector dropDatabase:@"testDatabase"]]];
  17.     [self printResults:[NSString stringWithFormat:@"Database exists: %d", [SQLite3Connector databaseExists:@"testDatabase"]]];  
  18.     NSString *query = @"CREATE TABLE IF NOT EXISTS testTable (id INTEGER PRIMARY KEY AUTOINCREMENT, data TEXT);";  
  19.     [self printResults:[NSString stringWithFormat:@"Creating table: %d", [conn executeQuery:query inDatabase:@"testDatabase"]]];  
  20.     [self printResults:[NSString stringWithFormat:@"Database size: %@", [SQLite3Connector getDatabaseFormatedFileSize:@"testDatabase"]]];  
  21.     //[self printResults:[NSString stringWithFormat:@"Dropping table: %d", [conn dropTable:@"testTable" inDatabase:@"testDatabase" useVacuum:YES]]];
  22.     //[self printResults:[NSString stringWithFormat:@"Creating table: %d", [conn executeQuery:query inDatabase:@"testDatabase"]]];
  23.     //[self printResults:[NSString stringWithFormat:@"Database size: %@", [SQLite3Connector getDatabaseFormatedFileSize:@"testDatabase"]]];
  24.     //[self printResults:[NSString stringWithFormat:@"Database exists: %d", [SQLite3Connector databaseExists:@"testDatabase"]]];
  25.     query = @"INSERT INTO testTable (data) VALUES ('Test Data (It''s)');";  
  26.     [self printResults:[NSString stringWithFormat:@"Inserting into the table: %d", [conn executeQuery:query inDatabase:@"testDatabase"]]];  
  27.     //[self printResults:[NSString stringWithFormat:@"Truncate table: %@", [conn truncateTable:@"testTable" inDatabase:@"testDatabase"]]];
  28.     [self printResults:[NSString stringWithFormat:@"Inserting into the table: %d", [conn executeQuery:query inDatabase:@"testDatabase"]]];  
  29.     [self printResults:[NSString stringWithFormat:@"Database size: %@", [SQLite3Connector getDatabaseFormatedFileSize:@"testDatabase"]]];  
  30.     [self printResults:[NSString stringWithFormat:@"Inserting into the table: %d", [conn executeQuery:query inDatabase:@"testDatabase"]]];  
  31.     [self printResults:[NSString stringWithFormat:@"Table exists: %d", [conn tableExists:@"testTable" inDatabase:@"testDatabase"]]];  
  32.     [self printResults:[NSString stringWithFormat:@"Database size: %@", [SQLite3Connector getDatabaseFormatedFileSize:@"testDatabase"]]];  
  33.     [self printResults:[NSString stringWithFormat:@"Table exists: %d", [conn tableExists:@"testTable" inDatabase:@"testDatabase"]]];  
  34.     [self printResults:[NSString stringWithFormat:@"Count rows in the table: %d", [conn executeScalar:queryCount inDatabase:@"testDatabase"]]];  
  35.     NSMutableArray *arr = [conn getData:@"SELECT * FROM testTable;" fromDatabase:@"testDatabase"];  
  36.     NSLog(@"%@", arr);  
  37.     [conn release];  
  38. }  
  39. http://www.xprogress.com/post-38-new-sqlite3-handling-library-for-iphones-and-cocoa-now-under-development/
Posted by 오늘마감
아이폰 개발할때, 유저 정의하는 클래스 생성하는 방법

1. 유저 정의 클래스 생성하기
2. 오브젝트의 생명주기
3. Autorelease
4. Objective-C 속성(Properties)

1. 유저 정의 클래스 생성하기

클래스 디자인 하기

클래스 명을 정하고 슈퍼클래스를 정한다. 필요한 속성과 액션을 정의한다.


메소드(Methods), 셀렉터(Selectors), 메세지(Messages)의 차이와 복습

메소드는 오브젝트의 액션을 정의한 것이다.
- (NSString *)name
{
// 구현
}
- (void)setName:(NSString *)name
{
// 구현
}

셀렉터는 메소드를 참조하기 위한 이름이다. 콜론을 포함하지만 실제 파라메터나 타입은 포함하지 않는다.
SEL mySelector = @selector(name);
SEL anotherSelector = @selector(setName:);
SEL lastSelector = @selector(doStuff:withThing:andThing:);


메세지는 오브젝트의 셀렉터를 실행시키기 위한 방법이다. 필요에 따라 파라메터도 같이 적는다.
NSString *name = [myPerson name];
[myPerson setName:@“New Name”];


클래스 정의
(Public 헤더와 Private implementation)

.h 가 헤더이고 .m 이 소스 파일 이란것은 지금까지 해온 것이기 때문에 구지 다시 설명하지 않아도 될 것이다.

여기서 다시 한번 짚고 넘어 갈 부분은 자기 클래스의 메소드를 호출할때는 self를 사용하고,

슈퍼 클래스의 메소드를 호출할 때는 super를 사용한다는 것이다. self는 자바와 비교하면 자바의 this와 같은 개념이다.


<예>
[self doSomething]
[super doSomething]

2. 오브젝트의 생명주기(Object Lifecycle)

오브젝트의 생성에는 allocinit의 두 단계를 거친다. new는 alloc/init을 대신할수 있지만 별로 쓰이지 않는다.
왜냐하면 실 프로젝트에서는 init 대신 initWith라는 초기값을 가지는 (유저정의)초기화 메소드를 사용하는 경우가 더 많기 때문이다.

#import "Person.h"

@implementation Person
- (id)init {
    // allow superclass to initialize its state first
    if (self = [super init]) {
    age = 0;
name = @“Bob”;
// do other initialization...
}
return self;
}
@end

여기에서 나오는 [super init]은 꼭 불러줘야 하는 필수 사항이며 그 값을 다시 self에 넣는 것은
혹시 슈퍼 클래스에서 다른 인스턴스를 돌려주는 특수 케이스가 있을수 있기 때문이다.
즉, 그냥 필요한 소스라고 생각하고 이 방식을 따라 주면 된다.


여러가지 초기화 메소드를 구현하고 싶을때 우리는 아래와 같은 방법을 쓸 수 있다.

- (id)init;
- (id)initWithName:(NSString *)name;
- (id)initWithName:(NSString *)name age:(int)age;


더 구체적인 값을 가진 초기화 메소드를 다시 불러 주는 방법이다.
이는 위의 self = [super init]과 같은 코드를 반복적으로 적어줘야 하는 불편함을 줄여 준다.

- (id)init {
return [self initWithName:@“No Name”]; //initWithName을 호출
}
- (id)initWithName:(NSString *)name {
return [self initWithName:name age:0]; //initWithName:age:를 호출
}


■ 메모리 관리

 생성  파괴
 C malloc free
Objective-c alloc dealloc


생성과 파괴는 같은 횟수 일어나야 한다.
하지만 Objective-c에서는 직접 dealloc을 부르지는 않는다.


참조 횟수(Reference Counting)

모든 오브젝트는 취득 횟수(Retain Count)를 가지고 있다.
    - NSObject에 정의 되어 있음
    - 취득 횟수(Retain Count) > 0 일 경우, 오브젝트는 유효하며 살아있다.
+alloc 이나 -copy는 오브젝트를 생성하며 취득 횟수(Retain Count) == 1로 만든다.
-retain 은 취득 횟수(Retain Count)를 1 증가시킨다.
-release 는 취득 횟수(Retain Count)를 1 감소시킨다.
취득 횟수(Retain Count)가 0이 될 때 오브젝트는 파괴된다.
    - dealloc 이 자동 실행된다.
    - 한번 dealloc 되면 다시 참조는 불가능 해진다.


Balanced Calls (동일한 횟수의 생성/파괴)

Person *person = nil;

person = [[Person alloc] init]; //오브젝트 생성

[person setName:@“Alan Cannistraro”];
[person setAge:29];
[person setWishfulThinking:YES];

[person castBallot];

// person 오브젝트의 사용이 끝나면 release한다.
[person release]; // person이 파괴될 것이다.


참조 횟수의 증감(Reference counting in action)
Person *person = [[Person alloc] init]; //+alloc에 의해 1이 된다.
[person retain]; //-retain에 의해 2가 된다.
[person release]; //-release에 의해 1이 된다.
[person release]; //-release에 의해 0이 된다. -deallocl 이 자동호출 된다.


참조 횟수가 0이 되어 dealloc된 person오브젝트를 만약 여기에서 다시 호출한다면 프로그램 이상으로 종료 될 것이다.
[person doSomething]; // Crash!


고로 이를 방지하기 위해, release 된 후 person = nil; 이라는 문장을 삽입 한다면 비록 참조되더라도 프로그램이 죽지는 않는다.
앞에서 설명했듯이 Objective-c에서는 nil오브젝트의 메소드를 호출해도 에러가 돌아오지 않기 때문이다.


Person *person = [[Person alloc] init];
// ...
[person release]; // Object is deallocated
person = nil;
[person doSomething]; // No effect (에러가 나지 않는다)


-dealloc 메소드 구현하기
#import "Person.h"
@implementation Person
- (void)dealloc {
// 필요한 cleanup을 적는다.
// ...
// 마지막에 슈퍼클래스의 dealloc을 불러준다.
[super dealloc];
}
@end


정리하면,

    오브젝트는 참조 횟수 1로 시작된다.
-retain과 -release로 참조 횟수가 증감한다.
참조횟수가 0이 되면 오브젝트는 자동으로 파괴된다.
절대 dealloc을 직접 호출해서는 안된다.
-[super dealloc]은 예외.
alloc, copy, retain, release 만 이용해라.

오브젝트의 소유권

Person이라는 오브젝트가 name이라는 속성을 가진다고 해보자.
@interface Person : NSObject
{
NSString *name; // Person class “owns” the name
}
@end


.m 파일에서 setter를 만들때,

1.retain을 사용
- (void)setName:(NSString *)newName {
if (name != newName) {
[name release];
name = [newName retain];
// retain을 사용한다면 name의 참조횟수는 1 증가하게 된다.
}

}

2.copy를 사용

- (void)setName:(NSString *)newName {
if (name != newName) {
[name release];
name = [newName copy];
// 혹은 copy를 사용한다면 name의 참조횟수는 1이 되며, 소유권이 생긴다.
}

}


retain대신 copy를 사용하는 이유는, 만약 수정 가능한 스트링 타입(NSMutableString)을 retain으로 넘겨 받는다면
밖에서 누군가가 이 값을 수정하였을때 파라메터로 넘겨받은 값도 영향을 받기 때문이다.
이를 방지하기 위해 영향을 받고 싶지 않을 경우에는 copy를 쓰도록 한다.


인스턴스 변수의 해방(release)

유저 정의 클래스 에서는 dealloc을 정의하여 필요한 cleanup을 적어준다.

#import "Person.h"
@implementation Person
- (void)dealloc {
    // 필요한 cleanup을 적어준다.
[name release];

// 슈퍼 클래스의 dealloc을 불러준다. 필수!!!
[super dealloc];
}


3. Autorelease

케이스 1
- (NSString *)fullName {
NSString *result;
result = [[NSString alloc] initWithFormat:@“%@ %@”, firstName, lastName];
    return result;
}
Wrong: result is leaked!

생성한 오브젝트를 릴리스 해주는 코드가 없어 잘못된 코드이다.


케이스 2
- (NSString *)fullName {
    NSString *result;
result = [[NSString alloc] initWithFormat:@“%@ %@”, firstName, lastName];
[result release];
return result;
}
Wrong: result를 너무 빨리 릴리스 했기때문에 잘못된 코드이다.


케이스 3
- (NSString *)fullName {
    NSString *result;
result = [[NSString alloc] initWithFormat:@“%@ %@”, firstName, lastName];
[result autorelease];
return result;
}

Just right: autorelease를 사용하면 result는 릴리스 되지만 바로 릴리스 되는것이 아니라 사용이 끝나면 릴리스 된다.


오브젝트의 자동릴리스(Autoreleasing Objects)

autorelease를 사용하면 즉시는 아니지만 필요한 시간이 경과된 후 release 명령이 오브젝트로 보내진다.
오브젝트를 일정시간 유지하고 싶을 때 retain/release를 충족하기 위하여 autorelease를 이용한다.
메모리 관리가 매우 효과적이다.
가장 유용하게 사용되는 부분은, 메소드내에서 새로 생성한 오브젝트를 돌려줄때 이다.


메소드 명과 자동릴리스(Method Names & Autorelease)
alloc이나 copy를 이용하여 오브젝트를 생성 하였을 경우, 생성한 사람은 이를 반드시 릴리스 해주어야 한다.

NSMutableString *string = [[NSMutableString alloc] init];
// -release 또는 -autorelease를 반드시 불러줄 것!
[string autorelease];


그 외 메소드들은 autorelease 오브젝트를 돌려줄 것이다.
NSMutableString *string = [NSMutableString string];
// 여기서는 alloc/copy를 사용하지 않고 오브젝트를 생성하였기 때문에

// autorelease 오브젝트가 생성 되므로 아무것도 안해도 된다.


유저 정의 클래스를 만들 경우에도 이 룰을 따라,

메소드내에서 오브젝트를 생성하였을 경우엔 autorelease 오브젝트를 돌려주도록 한다.


Autorelease의 작동 원리

오브젝트는 현재 자동릴리스 풀(current autorelease pool)에 저장된다.
자동릴리스 풀(autorelease pool)은 오브젝트가 릴리스 될수있도록 스케쥴링 한다.
    - 풀(pool) 자체가 릴리스 될 때, 풀은 모든 소유 오브젝트에게 -release 명령을 보낸다.
UIKit은 자동으로 이벤트 관련 풀을 포함(Wrap)하고 있다.


<어플리케이션의 시작~종료>
App 시작 ---> App 초기화 ---> main nib 로딩 ---> 이벤트 발생 대기 상태 ---> 이벤트 처리 ---> App 종료


여기의 이벤트 발생 대기 ~ 이벤트 처리 사이에서 발생한 이벤트는 자동으로 autorelease 모드로 풀에 들어가게 된다.

 <- 원본 pdf에서 발최


Autorelease 오브젝트를 릴리스 되지 않게 유지하는 방법

앞에서 다룬 룰에 의하면 많은 메소드 들은 Autorelease 오브젝트를 돌려주게 된다.
이 오브젝트들은 풀에 저장되어 있다가 시간이 경과하면 릴리스 되는데, 이를 릴리스 되지 않게 유지하고 싶다면
릴리스 되기 전에 -retain을 해주면 된다.


name = [NSMutableString string];
// 여기서 name을 retain하여 유효하게 유지 하게 된다.
[name retain];
// ...
// 사용이 끝나면 마지막에 release 해주도록 한다. (또는 클래스의 -dealloc에서 릴리스 할 수도 있다.)
[name release];


Garbage Collection

Autorelease는 Garbage Collection이 아니다.
iPhone OS의 Objective-c는 Garbage Collection을 지원하지 않는다. => 메모리 관리를 해야 한다는 뜻.


4.Property

클래스의 프로퍼티 선언은 @property와 @synthesize를 이용하여 간략화 할 수 있다는 것을 이전 문법 공부에서도 알아봤다.
추가로 몇가지 나열하자면 property와 인스턴스 변수의 이름은 다르게 설정 할 수 있다.


@interface Person : NSObject {
    int numberOfYearsOld;
}
@property int age;
@end

@implementation Person

//numberOfYearsOld라는 인스턴스 변수의 Getter/Setter를 age이라는 이름으로 정의.
@synthesize age = numberOfYearsOld;
@end

실제로 Property 가 사용 되고 있는 곳

새로운 API들은 @property를 사용한다.
기존 API들은 getter/setter를 사용한다.
기본 API 보다는 주로 UIKit API에 빈번히 사용되고 있다.
어느쪽을 사용해도 의미는 똑같다.
    @property는 적어야 하는 코드의 양을 줄여주지만, 때로는 코드 내용이 명확하지 않게 느껴질수도 있다.


■ .(Dot) 문법과 self

@interface Person : NSObject
{
NSString *name;
}
@property (copy) NSString *name;
@end

위와 같이 Person 오브젝트에 name 이라는 인스턴스 변수가 있다고 가정 할 때,
우리는 self.name과 같이 .(dot) 문법을 사용할 수 있다.
하지만 여기서 self.name은 name을 직접 호출 하는 것이 아니라 name의 setter/getter 메소드를 통해 접근 하게 된다.


그래서 만약 setter 메소드를 만들때 아래와 같은 실수를 하게 된다면 무한 루프에 빠지게 된다.

@implementation Person
- (void)setAge:(int)newAge {
    self.age = newAge; //이 코드는 [self setAge:newAge]를 호출하게 됨으로 자기자신을 계속 부르는 무한 루프가 된다.
}
@end


■ 읽어야 할 문서들

• Objective-C 2.0 Programming Language
    “Defining a Class”
    “Declared Properties”
• Memory Management Programming Guide for Cocoa


이해를 돕기 위해 위 문서를 읽고 넘어가면 도움이 될 것이다.



출처 : http://blog.naver.com/PostView.nhn?blogId=katchup00&logNo=10078813140
Posted by 오늘마감
아이폰 어플 개발할때 클래스 생성과 사용하는 방법


<순서>
Section 5. 클래스 생성
Section 6. 생성한 클래스 사용


이번 과제에서는 PolygonShape(다각형) 클래스를 생성한후 WhatATool의 메인 함수에서 클래스를 호출하는 함수를 불러본다.


아래와 같은 소스가 추가 될 것이다.


int main (int argc, const char * argv[]) {
    NSAutoreleasepool * pool = [[NSAutoreleasePool alloc] init];

    PrintPathInfo(); // Section 1
PrintProcessInfo(); // Section 2
PrintBookmarkInfo(); // Section 3
PrintIntrospectionInfo(); // Section 4
PrintPolygonInfo(); // Section 6 (section 5는 메인에 함수를 추가하지 않는다)
[pool release];
return 0;
}


Section 5. 클래스 생성

■ 새로운 PolygonShape 라는 클래스 만들기 (다각형 클래스)


Xcode에서
1.File > New File을 선택
2.Mac OS X아래 CoCoa 섹션의 'Objective-C class' 템플렛을 선택한다.
3.PolygonShape.m 으로 생성한다. - 헤더파일을 만들기 위한 체크박스를 체크하는 것을 잊지 말것.


* 새로운 클래스는 디폴트로 NSObject를 계승받는다.


자 이제 새로운 클래스에 속성을 부여해보자.
Objective-C 2.0은 오브젝트의 속성에 접근하는 새로운 메커니즘을 제공한다.
클래스는 "properties"를 정의 할 수 있으며, 이것이 유저가 클래스에 억세스 하는 방법을 제공한다.
properties는 개발자의 단순작업(getter/setter 코딩)을 없애주며 메모리 관리 폴리시와 속성의 사용법을 정의하도록 해준다.
예를 들면, property를 읽기 전용으로 지정하거나 오브젝트의 소유권등을 정의할 수 있다.


■ PolygonShape 클래스에 속성 지정하기


1. 아래의 속성을 지정한다.
• numberOfSides(면의 수) – 정수형
• minimumNumberOfSides(최소 면의 수) – 정수형
• maximumNumberOfSides(최소 면의 수) – 정수형
• angleInDegrees(내각) – 실수형, 읽기전용
• angleInRadians(호도) – 실수형, 읽기전용
• name(이름) – NSString 오브젝트, 읽기전용


2. numberOfSides, minimumNumberOfSides, maximumNumberOfSides의 세가지 속성은
적절한 타입의 인스턴스 변수로 저장될 수 있어야 한다. 이 속성들은 @synthesize 옵션을 이용하면 컴파일러가
자동으로 getter/setter를 생성하여주며, 읽기 전용 속성은 getter만이 생성된다.


3. setter 메소드에 아래와 같은 조건을 부여하라
• numberOfSides – 최소값과 최대값의 사이 값만 가질수 있다.
• minimumNumberOfSides – 2보다 커야 한다.
• maximumNumberOfSides – 12보다 작아야 한다.


maximumNumberOfSides에 5가 설정되어 있는데 numberOfSides에 9를 세팅하려고 한다면 아래와 같은 에러로그를 출력하라.
Invalid number of sides: 9 is greater than the maximum of 5 allowed


4. 아래와 같은 초기화 메소드를 생성하라.
- (id)initWithNumberOfSides:(int)sides minimumNumberOfSides:(int)min maximumNumberOfSides:(int)max;


5. 슈퍼클래스인 NSObject의 init메소드를 오버라이드 하여 아래와 같은 디폴트값을 설정하는 커스텀 init을 생성하라.
numberOfSides – 5, minimumNumberOfSides – 3, maximumNumberOfSides – 10


6. angleInDegrees와 angleInRadians는 @synthesize 옵션을 사용하지 말라.
그리고 인스턴스 변수도 불필요하다. 이 두 속성은 numberOfSides의 값에 의해 결정될 것이다.
여기서는 정규 다각형(regular polygon)만 만들것임으로 각도(angles)의 값은 모두 똑같을 것이다.


7. name속성도 @synthesize 옵션을 사용할 필요가 없다. (인스턴스 변수도 필요없다.)
면의 갯수로부터 다각형의 이름을 출력하게 될 것이다.
<예>
면이 3일 경우: “Triangle”
면이 4일 경우: “Square”


8. PolygonShape 클래스의 -description 메소드를 아래 예와 같이 나오도록 구현하라.
Hello I am a 4-sided polygon (aka a Square) with angles of 90 degrees (1.570796 radians).


9. dealloc메소드를 사용하여 메모리 관리를 하고, dealloc이 불리워졌을때 로그를 출력하도록 하여라.


<힌트>


•다각형의 이름은 위키에서 찾을 수 있다.
•내각(angleInDegrees)을 구하기 위한 식은 다음과 같다. (180 * (numberOfSides - 2) / numberOfSides)
•삼각법(trigonometry): 360° 는 2π(파이) 이다.
•π(파이)의 값은 M_PI에 정의되어 있다.

Section 6. 생성한 클래스 사용

WhatATool.m 파일에 #import "PolygonShape.h" 를 삽입한다.


중요!!! 여기서는 PolygonShape를 생성하기 위해 +alloc과 -init을 사용하도록 한다. 생성된 오브젝트는 배열에 넣도록 하고
사용이 끝난 후엔 메모리 관리 기술을 이용하여 오브젝트를 릴리스 하도록 한다.


1. alloc/init를 사용하여 mutable array를 생성하라.


2. 아래 값을 사용하여 3개 또는 그 이상의 PolygonShape 오브젝트를 생성하라.

Min number of sides Max number of sides Number of sides
 3  7  4
 5  9  6
 9  12  12

3. 생성한 오브젝트를 배열에 추가하고 description을 이용하여 로그를 출력하라. 최소한 3줄의 로그가 찍여야 한다.

4. polygon 오브젝트의 제약을 테스트 해본다.
루프를 돌며 numberOfSides에 10을 세팅해보라. 위의 테이블을 이용해 만든 오브젝트라면 두줄의 로그가 찍힐것이다.

5. polygon 오브젝트가 메모리로부터 릴리스 되었는지 확인한다.
주어진 규칙대로 생성한 클래스라면 dealloc이 불리면서 3번의 로그가 찍힐 것이다.


<시도>

우선 name의 getter를 구현하기 위해 다각형의 이름을 찾아봤다.

Polygon names

Name Edges
digon 2
triangle (or trigon) 3
quadrilateral (or quadrangle or tetragon) 4
pentagon 5
hexagon 6
heptagon 7
octagon 8
enneagon (or nonagon) 9
decagon 10
hendecagon 11
dodecagon 12

<구현한 소스>

PolygonShape.h +-----+-----+-----+-----+-----+

//

//  PolygonShape.h

//  WhatATool

//

//  Created on 09. 12. 14.

//  Copyright 2009 __MyCompanyName__. All rights reserved.

//

#import

@interface PolygonShape : NSObject {

intnumberOfSides;

intminimumNumberOfSides;

intmaximumNumberOfSides;

}

@propertyintnumberOfSides;

@propertyintminimumNumberOfSides;

@propertyintmaximumNumberOfSides;

@property (readonly) float angleInDegrees;

@property (readonly) float angleInRadians;

@property (readonly) NSString *name;

//헤더에 이 메소드를 추가하는걸 까먹어서 에러가 났었다.

- (id)initWithNumberOfSides:(int)sides minimumNumberOfSides:(int)min maximumNumberOfSides:(int)max;

@end

PolygonShape.m +-----+-----+-----+-----+-----+

//

//  PolygonShape.m

//  WhatATool

//

//  Created on 09. 12. 14.

//  Copyright 2009 __MyCompanyName__. All rights reserved.

//

#import "PolygonShape.h"

@implementation PolygonShape

@synthesize numberOfSides;

@synthesize minimumNumberOfSides;

@synthesize maximumNumberOfSides;

//synthesize선언한변수지만 setter존재하면 getter생성됨으로마음놓고써도된다.

-(void)setNumberOfSides:(int)newNumberOfSides {

    //numberOfSides최소값과최대값의사이값만가질수있다

    if(newNumberOfSides > maximumNumberOfSides) {

        //maximumNumberOfSides 5설정되어있는데 numberOfSides 9세팅하려고한다면에러로그를출력하라.

        NSLog(@"Invalid number of sides: %d is greater than the maximum of %d allowed", newNumberOfSides, maximumNumberOfSides);

    } elseif (newNumberOfSides < minimumNumberOfSides) {

        NSLog(@"Invalid number of sides: %d is less than the minimum of %d allowed", newNumberOfSides, minimumNumberOfSides);

    } else {

        numberOfSides = newNumberOfSides;

    }

}

//minimumNumberOfSides 2보다커야한다.

-(void)setMinimumNumberOfSides:(int)newMinimumNumberOfSides {

    if (newMinimumNumberOfSides < 2) {

    NSLog(@"Invalid minumum number of sides: %d is less than 2 allowed", newMinimumNumberOfSides);

} else {

    minimumNumberOfSides = newMinimumNumberOfSides;

}

}

//maximumNumberOfSides 12보다작아야한다.

-(void)setMaximumNumberOfSides:(int)newMaximumNumberOfSides {

    if (newMaximumNumberOfSides > 12) {

NSLog(@"Invalid maximum number of sides: %d is greater than 12 allowed", newMaximumNumberOfSides);

} else {

maximumNumberOfSides = newMaximumNumberOfSides;

}

}

//4. 초기화메소드를생성하라.

//주의! numberOfSides를 Max Min보다 먼저 세팅하려고 Max Min값이 0으로 인식되어 조건에서 튕겨나간다.

-(id)initWithNumberOfSides:(int)sides minimumNumberOfSides:(int)min maximumNumberOfSides:(int)max {

[selfsetMinimumNumberOfSides:min];

[selfsetMaximumNumberOfSides:max];

[selfsetNumberOfSides:sides];

returnself;

}

//5. 슈퍼클래스인 NSObject init메소드를오버라이드하여아래와같은디폴트값을설정하는커스텀 init생성하라.

-(id)init {

if (self = [superinit]) {

    self = [selfinitWithNumberOfSides:5minimumNumberOfSides:3maximumNumberOfSides:10];

}

returnself;

}

//내각

-(float)angleInDegrees {

return (180 * (self.numberOfSides - 2) / self.numberOfSides);

}

//라디안

-(float)angleInRadians {

returnM_PI / 180 * self.angleInDegrees;

}

//7. 면의갯수로부터다각형의이름을출력하게것이다.

-(NSString *)name {

    switch ([selfnumberOfSides]) {

case2: return@"digon"; break;

case3: return@"triangle"; break;

case4: return@"quadrilateral"; break;

case5: return@"pentagon"; break;

case6: return@"hexagon"; break;

case7: return@"heptagon"; break;

case8: return@"octagon"; break;

case9: return@"enneagon"; break;

case10: return@"decagon"; break;

case11: return@"hendecagon"; break;

case12: return@"dodecagon"; break;

default: return@"";

}

}

//8. description오버라이드

//: Hello I am a 4-sided polygon (aka a Square) with angles of 90 degrees (1.570796 radians).

-(NSString *)description {

return [NSStringstringWithFormat: @"Hello I am a %d-sided polygon (aka a %@) with angles of %.0f degrees (%.6f radians)."

self.numberOfSides, self.name, self.angleInDegrees, self.angleInRadians];

}

//9. dealloc메소드를사용하여메모리관리를하고, dealloc불리워졌을때로그를출력하도록하여라.

- (void)dealloc {

NSLog(@"dealloc called");

[superdealloc];

}

@end

WhatATool.m의 함수(Section 6) 부분 +-----+-----+-----+-----+-----+

//#import "PolygonShape.h" 를 잊지말자


//Section 6

void PrintPolygonInfo() {

    NSLog(@"----- Section 6 -----");


    //배열 생성

NSMutableArray *array = [[NSMutableArrayalloc] init];

PolygonShape *polygon1 = [[PolygonShapealloc] initWithNumberOfSides:4minimumNumberOfSides:3maximumNumberOfSides:7];

PolygonShape *polygon2 = [[PolygonShapealloc] initWithNumberOfSides:6minimumNumberOfSides:5maximumNumberOfSides:9];

PolygonShape *polygon3 = [[PolygonShapealloc] initWithNumberOfSides:12minimumNumberOfSides:9maximumNumberOfSides:12];

    //생성한 다각형 정보를 로그에 출력하고 배열에 다각형 오브젝트를 추가한다.

NSLog([polygon1 description]);

[array addObject:polygon1];

NSLog([polygon2 description]);

[array addObject:polygon2];

NSLog([polygon3 description]);

[array addObject:polygon3];

//제약을 테스트하기 위해 numberOfSides에 10을 넣어본다.

for (PolygonShape *polygon in array) {

polygon.numberOfSides = 10;

}

[polygon1 dealloc];

[polygon2 dealloc];

[polygon3 dealloc];

[array dealloc];

}

<결과>

2009-12-17 14:54:31.297 WhatATool[1125:10b] ----- Section 6 -----

2009-12-17 14:54:31.297 WhatATool[1125:10b] Hello I am a 4-sided polygon (aka a quadrilateral) with angles of 90 degrees (1.570796 radians).

2009-12-17 14:54:31.297 WhatATool[1125:10b] Hello I am a 6-sided polygon (aka a hexagon) with angles of 120 degrees (2.094395 radians).

2009-12-17 14:54:31.297 WhatATool[1125:10b] Hello I am a 12-sided polygon (aka a dodecagon) with angles of 150 degrees (2.617994 radians).

2009-12-17 14:54:31.298 WhatATool[1125:10b] Invalid number of sides: 10 is greater than the maximum of 7 allowed

2009-12-17 14:54:31.298 WhatATool[1125:10b] Invalid number of sides: 10 is greater than the maximum of 9 allowed

2009-12-17 14:54:31.298 WhatATool[1125:10b] dealloc called

2009-12-17 14:54:31.299 WhatATool[1125:10b] dealloc called

2009-12-17 14:54:31.299 WhatATool[1125:10b] dealloc called

The Debugger has exited with status 0.



출처 : http://blog.naver.com/PostView.nhn?blogId=katchup00&logNo=10076162791
Posted by 오늘마감
아이폰 어플 개발 , Selector 의 이용과 클래스 정보 보는 방법


지금까지 만들어봤던 NSString, NSURL, NSProcessInfo, NSDictionary 등과 NSMutableString을 인스턴스화해서
배열(NSMutableArray)에 넣어라.


그리고 아래를 수행하라.


1. 오브젝트의 클래스명을 출력하라
2. 오브젝트가 NSString 클래스인지 출력하라
3. 오브젝트가 NSString의 서브클래스인지 출력하라
4. 오브젝트가 "lowercaseString"를 지원하는지 출력하라
5. "lowercaseString"를 지원하는 오브젝트라면 performSelector:를 이용하여 결과를 출력하라


<예상하는 결과 형식>

2008-01-10 20:56:03 WhatATool[360] Class name: NSCFString
2008-01-10 20:56:03 WhatATool[360] Is Member of NSString: NO
2008-01-10 20:56:03 WhatATool[360] Is Kind of NSString: YES
2008-01-10 20:56:03 WhatATool[360] Responds to lowercaseString: YES
2008-01-10 20:56:03 WhatATool[360] lowercaseString is: hello world!
2008-01-10 20:56:03 WhatATool[360] ======================================
2008-01-10 20:56:03 WhatATool[360] Class name: NSURL
2008-01-10 20:56:03 WhatATool[360] Is Member of NSString: NO
2008-01-10 20:56:03 WhatATool[360] Is Kind of NSString: NO
2008-01-10 20:56:03 WhatATool[360] Responds to lowercaseString: NO
2008-01-10 20:56:03 WhatATool[360] ======================================
2008-01-10 20:56:03 WhatATool[360] Class name: NSCFDictionary
2008-01-10 20:56:03 WhatATool[360] Is Member of NSString: NO
2008-01-10 20:56:03 WhatATool[360] Is Kind of NSString: NO
2008-01-10 20:56:03 WhatATool[360] Responds to lowercaseString: NO
2008-01-10 20:56:03 WhatATool[360] ======================================


<힌트>
아마도 NSString과 같은 클래스 명이 예상치 않은 결과가 나올수 있지만
그건 implementation의 문제이니 여기선 그냥 넘어가도록 한다.


<실습>
NSString, NSURL, NSProcessInfo, NSDictionary, NSMutableString을 만든다.


NSString *myString = @"Hello World!";
NSURL *myURL = [NSURL URLWithString:@"
http://www.stanford.edu"];
NSProcessInfo *myProcess = [NSProcessInfo processInfo];
NSDictionary *myDictionary = [NSDictionary dictionary];
NSMutableString *myMutableString = @"This is a mutable string object";


NSMutableArray를 만들고 위의 오브젝트들을 추가한다.


NSMutableArray *array = [NSMutableArray array];
[array addObject:myString];
[array addObject:myURL];
[array addObject:myProcess];
[array addObject:myDictionary];
[array addObject:myMutableString];


루프를 돌며 클래스 정보를 출력한다.


■ 오브젝트의 클래스명을 출력하라


모든 오브젝트는 NSObject를 계승하니까... NSObject reference를 찾아보자.

- (NSString *)description 이라고 하니까, 클래스 설명이 나와버린다.

구글 검색을 해보니까 className을 쓰면 된다고 한다.

[obj className];

왜 NSObject의 리퍼런스에 나와있지 않은지 모르겠지만 아마도 다른 연관이 있는듯. 일단 나오니까 스킵.


 오브젝트가 NSString 클래스인지 출력하라
- (BOOL)isMemberOfClass:(Class)aClass 이용


오브젝트가 NSString의 서브클래스인지 출력하라
- (BOOL)isKindOfClass:(Class)aClass 이용


오브젝트가 "lowercaseString"를 지원하는지 출력하라
- (BOOL)respondsToSelector:(SEL)aSelector 이용


"lowercaseString"를 지원하는 오브젝트라면 performSelector:를 이용하여 결과를 출력하라
- (id)performSelector:(SEL)aSelector 이용

Selector 란 컴파일된 오브젝트의 메소드를 가르키는 이름이라고 한다.

즉, performSelector: 같은 메소드에 Selector를 지정함으로써 실행할수 있다는 뜻이다.

<결과>

성공!!!



출처 : http://blog.naver.com/PostView.nhn?blogId=katchup00&logNo=10075791909
Posted by 오늘마감
NSMutableDictionary 클래스 이용해서 즐겨찾기 만들어보자


아래의 값으로 NSMutableDictionary를 생성한다.

Key (NSString) Value (NSURL)
Stanford University http://www.stanford.edu
Apple http://www.apple.com
CS193P http://cs193p.stanford.edu
Stanford on iTunes U http://itunes.stanford.edu
Stanford Mall http://stanfordshop.com

루프를 돌다가 Stanford로 시작하는 키를 가진 값이 있으면 아래와 같이 로그를 출력한다.


Key: 'Stanford University' URL: 'http://www.stanford.edu'


<조건 및 힌트>
+URLWithString: 을 이용하여 URL 인스턴스를 생성하라.
NSString의 prefix/suffix를 체크하는 메소드를 이용하라.
NSMutableDictionary 는 NSDictionary의 서브클래스임을 기억하라.


NSMutableDictionary를 생성하기 위해 리퍼런스를 보자.

클래스 메소드에 dictionaryWithCapacity: 밖에 없으니... 슈퍼클래스인 NSDictionary의 클래스 메소드를 살펴본다.

dictionary라는 빈 딕셔너리를 생성해주는 클래스 메소드를 찾았다.


이용해 본다.

NSMutableDictionary *myDictionary = [NSMutableDictionary dictionary];


키와 값을 추가한다.


<시도 1>

- (void)setObject:(id)anObject forKey:(id)aKey 을 이용해 본다.


[myDictionary setObject:[NSURL URLWithString:@"http://www.stanford.edu"] forKey:@"Stanford University"];
[myDictionary setObject:[NSURL URLWithString:@"
http://www.apple.com"] forKey:@"Apple"];
[myDictionary setObject:[NSURL URLWithString:@"
http://cs193p.stanford.edu"] forKey:@"CS193P"];
[myDictionary setObject:[NSURL URLWithString:@"
http://itunes.stanford.edu"] forKey:@"Stanford on iTunes U"];
[myDictionary setObject:[NSURL URLWithString:@"
http://stanfordshop.com"] forKey:@"Stanford Mall"];


<결과>
일단 컴파일 에러가 안나니까 성공.

계속해서 Stanford로 시작하는 키의 정보를 로그로 출력해 보자.

NSDictionary의 - (NSArray *)allKeys 를 이용해 본다.


for (NSString *element in [myDictionary allKeys] ) {
    NSLog(element);
}


■ 그럼 스트링이 특정 문자로 시작하는지 알아보는 메소드는?


혹시 prefixWith.. 라는 메소드가 있나 했는데 없다. 음...


NSString Class Reference의 COMPANION GUIDES에 나와있는 String Programming Guide for Cocoa을 열어 봤다.

문서내의 Searching, Comparing, and Sorting Strings를 참조.

검색 메소드중 rangeOfString:options: 이라는게 있는데 이 옵션을 살펴보니 아래와 같은 내용이 있다.

검색 옵션 효과
NSAnchoredSearch Performs searching only on characters at the beginning or end of the range. No match at the beginning or end means nothing is found, even if a matching sequence of characters occurs elsewhere in the string.


NSString의 처음이나 끝에 검색하고자 하는 스트링이 있는지 찾아본다. 중간에 있는건 무효.

<시도>    
NSRange prefixRange = [key rangeOfString:@"Stanford" options:NSAnchoredSearch)];


리턴값은 NSRange인데 rangeOfString:options: 메소드의 설명을 보면 아래와 같다.

Return Value
An NSRange structure giving the location and length in the receiver of the first occurrence of aString, modulo the options in mask. Returns {NSNotFound, 0} if aString is not found or is empty (@"").

즉, 값을 찾지 못했을경우에는 {NSNotFound, 0} 가 돌아온다고 한다.


NSRange는 아래와 같은 구조체 이니까,

typedef struct _NSRange {
   NSUInteger location;
   NSUInteger length;
} NSRange;


location이 NSNotFound인지 살펴보면 될 것 같다.

if ([element rangeOfString:@"Stanford" options:NSAnchoredSearch].location != NSNotFound) {
    로그출력...
}


<결과>
성공!!!



출처 : http://blog.naver.com/PostView.nhn?blogId=katchup00&logNo=10075724258
Posted by 오늘마감
NSProcessInfo 클래스 이용해서 프로세스 ID 찍어보자


NSProcessInfo 를 이용하여 아래와 같이 프로세스명, 프로세스ID를 출력하라

Process Name: 'WhatATool' Process ID: '4556'


클래스 리퍼런스를 참조하니 processNameprocessIdentifier라는 그럴듯한 메소드가 있다.


<시도 1>

NSProcessInfo *pInfo = [NSProcessInfo processInfo];

NSLog(@"Process Name: '%@' Process ID: '%@'", [pInfo processName], [pInfo processIdentifier]);


<결과>

실패.... 컴파일 에러는 안나지만 프로그램 시작후 이상한 메세지가 뜬 상태로 안끝난다...


<시도 2>

프린트할 ID부분의 포멧을 %@ (오브젝트) 에서 %i (정수형)으로 바꿔봤다.

NSLog(@"Process Name: '%@' Process ID: '%i'", [pInfo processName], [pInfo processIdentifier]);


<결과>

성공!!!



출처 : http://blog.naver.com/PostView.nhn?blogId=katchup00&logNo=10075722816
Posted by 오늘마감
아이폰 어플 개발 , 사용자 홈 디렉토리 찍어보기 (NSString 클래스 이용)

[과제B Section 1] 사용자 홈 디렉토리 찍어보기 (NSString 클래스 이용)

NSString *path = @"~";
를 이용하여

My home folder is at '/Users/pmarcos'
를 출력하라.

또한 경로를 배열로 돌려주는 메소드를 이용하여 아래와 같이 출력하라.

/
Users
pmarcos


Objective-C의 NSString을 이용할땐 항상 @”Hello World” 와 같이 앞에 @를 붙여 주어야 한다.

NSString을 이용하여야 할 곳에 C의 String을 이용해 버리면 프로그램이 제대로 작동하지 않을수 있다.

■ NSString 클래스에 대한 정보는 어디에 있을까?

iPhone Dev Center 에 가면

iPhone Reference Library > Resource Types > Reference 를 열면 기본 클래스에 대한 문서들이 나오며 검색창이 보인다.
"NSString"이라고 치면 NSStringClass Reference 라는 링크를 볼 수 있다.
또한 설치한 Xcode의 Help > Documentation으로 가서 찾아도 된다.
■ 유저 홈 디렉토리란?
Mac OS는 유닉스베이스로 만들어져 있음으로 유저 홈 디렉토리는 "~"(틸드)로 표현이 가능하다.
스트링을 선언해 본다.
NSString *path = @"~";
<원하는 결과>
My home folder is at '/Users/pmarcos'
<시도1>
NSLog(@"My home folder is at %@", path);
* 여기서 %@란 Objective-C의 오브젝트를 의미한다. 자세히는 Format Specifiers 참조.
결과는 My home folder is at ~.
당연하다면 당연하지만, 혹시나 자동으로 바꿔주나 싶었다.
다시 NSString의 API Doc을 참조하여 이번엔 어떤 메소드가 있나 봤다.
틸드가 어쩌고 하는 메소드 발견.
내용은... 패스안에 틸드로 생략된 문자? ... 참 긴 이름이다.
stringByAbbreviatingWithTildeInPath

Returns a new string representing the receiver as a path with a tilde (~) substituted for the full path to the current user’s home directory.

- (NSString *)stringByAbbreviatingWithTildeInPath

Return Value

A new string representing the receiver as a path with a tilde (~) substituted for the full path to the current user’s home directory. Returns a new string matching the receiver if the receiver doesn’t begin with a user’s home directory.

어쨋든 틸드 대신 스트링으로 유저홈을 돌려주나보다.

<시도2>

NSLog(@"My home folder is at %@", [path stringByAbbreviatingWithTildeInPath]);

<결과>
성공!!!
 
■ 경로를 배열로 취득하기
 
NSString 클래스 리퍼런스 문서를 더 찾아보니 pathComponents라는 인스턴스 메소드가 존재한다.
리턴값은 NSArray. 사용해 보았다.
 
NSArray *pathComponents = [path pathComponents];
 
배열로 돌아왔으니 루프를 돌리면서 찍어보자.
아.. 루프 돌리는 법을 모르네... 문법 참조. (The Objective-C Programming Language - Fast Enumeration)
 
for (NSString *element in pathComponents){
    NSLog(element);
}
 
무난히 완성!!!
 


출처 : http://blog.naver.com/PostView.nhn?blogId=katchup00&logNo=10075347794
Posted by 오늘마감
유저 정의 클래스

역시나 과제 2의 내용을 복습(?)/해설 해주는 강의 이다.


유저 정의 클래스 (원문 - Custom Classes)

1. 유저 정의 클래스 생성하기
2. 오브젝트의 생명주기
3. Autorelease
4. Objective-C 속성(Properties)

1. 유저 정의 클래스 생성하기

클래스 디자인 하기

클래스 명을 정하고 슈퍼클래스를 정한다. 필요한 속성과 액션을 정의한다.


메소드(Methods), 셀렉터(Selectors), 메세지(Messages)의 차이와 복습

메소드는 오브젝트의 액션을 정의한 것이다.
- (NSString *)name
{
// 구현
}
- (void)setName:(NSString *)name
{
// 구현
}

셀렉터는 메소드를 참조하기 위한 이름이다. 콜론을 포함하지만 실제 파라메터나 타입은 포함하지 않는다.
SEL mySelector = @selector(name);
SEL anotherSelector = @selector(setName:);
SEL lastSelector = @selector(doStuff:withThing:andThing:);


메세지는 오브젝트의 셀렉터를 실행시키기 위한 방법이다. 필요에 따라 파라메터도 같이 적는다.
NSString *name = [myPerson name];
[myPerson setName:@“New Name”];


클래스 정의
(Public 헤더와 Private implementation)

.h 가 헤더이고 .m 이 소스 파일 이란것은 지금까지 해온 것이기 때문에 구지 다시 설명하지 않아도 될 것이다.

여기서 다시 한번 짚고 넘어 갈 부분은 자기 클래스의 메소드를 호출할때는 self를 사용하고,

슈퍼 클래스의 메소드를 호출할 때는 super를 사용한다는 것이다. self는 자바와 비교하면 자바의 this와 같은 개념이다.


<예>
[self doSomething]
[super doSomething]

2. 오브젝트의 생명주기(Object Lifecycle)

오브젝트의 생성에는 allocinit의 두 단계를 거친다. new는 alloc/init을 대신할수 있지만 별로 쓰이지 않는다.
왜냐하면 실 프로젝트에서는 init 대신 initWith라는 초기값을 가지는 (유저정의)초기화 메소드를 사용하는 경우가 더 많기 때문이다.

#import "Person.h"

@implementation Person
- (id)init {
    // allow superclass to initialize its state first
    if (self = [super init]) {
    age = 0;
name = @“Bob”;
// do other initialization...
}
return self;
}
@end

여기에서 나오는 [super init]은 꼭 불러줘야 하는 필수 사항이며 그 값을 다시 self에 넣는 것은
혹시 슈퍼 클래스에서 다른 인스턴스를 돌려주는 특수 케이스가 있을수 있기 때문이다.
즉, 그냥 필요한 소스라고 생각하고 이 방식을 따라 주면 된다.


여러가지 초기화 메소드를 구현하고 싶을때 우리는 아래와 같은 방법을 쓸 수 있다.

- (id)init;
- (id)initWithName:(NSString *)name;
- (id)initWithName:(NSString *)name age:(int)age;


더 구체적인 값을 가진 초기화 메소드를 다시 불러 주는 방법이다.
이는 위의 self = [super init]과 같은 코드를 반복적으로 적어줘야 하는 불편함을 줄여 준다.

- (id)init {
return [self initWithName:@“No Name”]; //initWithName을 호출
}
- (id)initWithName:(NSString *)name {
return [self initWithName:name age:0]; //initWithName:age:를 호출
}


■ 메모리 관리

 생성  파괴
 C malloc free
Objective-c alloc dealloc


생성과 파괴는 같은 횟수 일어나야 한다.
하지만 Objective-c에서는 직접 dealloc을 부르지는 않는다.


참조 횟수(Reference Counting)

모든 오브젝트는 취득 횟수(Retain Count)를 가지고 있다.
    - NSObject에 정의 되어 있음
    - 취득 횟수(Retain Count) > 0 일 경우, 오브젝트는 유효하며 살아있다.
+alloc 이나 -copy는 오브젝트를 생성하며 취득 횟수(Retain Count) == 1로 만든다.
-retain 은 취득 횟수(Retain Count)를 1 증가시킨다.
-release 는 취득 횟수(Retain Count)를 1 감소시킨다.
취득 횟수(Retain Count)가 0이 될 때 오브젝트는 파괴된다.
    - dealloc 이 자동 실행된다.
    - 한번 dealloc 되면 다시 참조는 불가능 해진다.


Balanced Calls (동일한 횟수의 생성/파괴)

Person *person = nil;

person = [[Person alloc] init]; //오브젝트 생성

[person setName:@“Alan Cannistraro”];
[person setAge:29];
[person setWishfulThinking:YES];

[person castBallot];

// person 오브젝트의 사용이 끝나면 release한다.
[person release]; // person이 파괴될 것이다.


참조 횟수의 증감(Reference counting in action)
Person *person = [[Person alloc] init]; //+alloc에 의해 1이 된다.
[person retain]; //-retain에 의해 2가 된다.
[person release]; //-release에 의해 1이 된다.
[person release]; //-release에 의해 0이 된다. -deallocl 이 자동호출 된다.


참조 횟수가 0이 되어 dealloc된 person오브젝트를 만약 여기에서 다시 호출한다면 프로그램 이상으로 종료 될 것이다.
[person doSomething]; // Crash!


고로 이를 방지하기 위해, release 된 후 person = nil; 이라는 문장을 삽입 한다면 비록 참조되더라도 프로그램이 죽지는 않는다.
앞에서 설명했듯이 Objective-c에서는 nil오브젝트의 메소드를 호출해도 에러가 돌아오지 않기 때문이다.


Person *person = [[Person alloc] init];
// ...
[person release]; // Object is deallocated
person = nil;
[person doSomething]; // No effect (에러가 나지 않는다)


-dealloc 메소드 구현하기
#import "Person.h"
@implementation Person
- (void)dealloc {
// 필요한 cleanup을 적는다.
// ...
// 마지막에 슈퍼클래스의 dealloc을 불러준다.
[super dealloc];
}
@end


정리하면,

    오브젝트는 참조 횟수 1로 시작된다.
-retain과 -release로 참조 횟수가 증감한다.
참조횟수가 0이 되면 오브젝트는 자동으로 파괴된다.
절대 dealloc을 직접 호출해서는 안된다.
-[super dealloc]은 예외.
alloc, copy, retain, release 만 이용해라.

오브젝트의 소유권

Person이라는 오브젝트가 name이라는 속성을 가진다고 해보자.
@interface Person : NSObject
{
NSString *name; // Person class “owns” the name
}
@end


.m 파일에서 setter를 만들때,

1.retain을 사용
- (void)setName:(NSString *)newName {
if (name != newName) {
[name release];
name = [newName retain];
// retain을 사용한다면 name의 참조횟수는 1 증가하게 된다.
}

}

2.copy를 사용

- (void)setName:(NSString *)newName {
if (name != newName) {
[name release];
name = [newName copy];
// 혹은 copy를 사용한다면 name의 참조횟수는 1이 되며, 소유권이 생긴다.
}

}


retain대신 copy를 사용하는 이유는, 만약 수정 가능한 스트링 타입(NSMutableString)을 retain으로 넘겨 받는다면
밖에서 누군가가 이 값을 수정하였을때 파라메터로 넘겨받은 값도 영향을 받기 때문이다.
이를 방지하기 위해 영향을 받고 싶지 않을 경우에는 copy를 쓰도록 한다.


인스턴스 변수의 해방(release)

유저 정의 클래스 에서는 dealloc을 정의하여 필요한 cleanup을 적어준다.

#import "Person.h"
@implementation Person
- (void)dealloc {
    // 필요한 cleanup을 적어준다.
[name release];

// 슈퍼 클래스의 dealloc을 불러준다. 필수!!!
[super dealloc];
}


3. Autorelease

케이스 1
- (NSString *)fullName {
NSString *result;
result = [[NSString alloc] initWithFormat:@“%@ %@”, firstName, lastName];
    return result;
}
Wrong: result is leaked!

생성한 오브젝트를 릴리스 해주는 코드가 없어 잘못된 코드이다.


케이스 2
- (NSString *)fullName {
    NSString *result;
result = [[NSString alloc] initWithFormat:@“%@ %@”, firstName, lastName];
[result release];
return result;
}
Wrong: result를 너무 빨리 릴리스 했기때문에 잘못된 코드이다.


케이스 3
- (NSString *)fullName {
    NSString *result;
result = [[NSString alloc] initWithFormat:@“%@ %@”, firstName, lastName];
[result autorelease];
return result;
}

Just right: autorelease를 사용하면 result는 릴리스 되지만 바로 릴리스 되는것이 아니라 사용이 끝나면 릴리스 된다.


오브젝트의 자동릴리스(Autoreleasing Objects)

autorelease를 사용하면 즉시는 아니지만 필요한 시간이 경과된 후 release 명령이 오브젝트로 보내진다.
오브젝트를 일정시간 유지하고 싶을 때 retain/release를 충족하기 위하여 autorelease를 이용한다.
메모리 관리가 매우 효과적이다.
가장 유용하게 사용되는 부분은, 메소드내에서 새로 생성한 오브젝트를 돌려줄때 이다.


메소드 명과 자동릴리스(Method Names & Autorelease)
alloc이나 copy를 이용하여 오브젝트를 생성 하였을 경우, 생성한 사람은 이를 반드시 릴리스 해주어야 한다.

NSMutableString *string = [[NSMutableString alloc] init];
// -release 또는 -autorelease를 반드시 불러줄 것!
[string autorelease];


그 외 메소드들은 autorelease 오브젝트를 돌려줄 것이다.
NSMutableString *string = [NSMutableString string];
// 여기서는 alloc/copy를 사용하지 않고 오브젝트를 생성하였기 때문에

// autorelease 오브젝트가 생성 되므로 아무것도 안해도 된다.


유저 정의 클래스를 만들 경우에도 이 룰을 따라,

메소드내에서 오브젝트를 생성하였을 경우엔 autorelease 오브젝트를 돌려주도록 한다.


Autorelease의 작동 원리

오브젝트는 현재 자동릴리스 풀(current autorelease pool)에 저장된다.
자동릴리스 풀(autorelease pool)은 오브젝트가 릴리스 될수있도록 스케쥴링 한다.
    - 풀(pool) 자체가 릴리스 될 때, 풀은 모든 소유 오브젝트에게 -release 명령을 보낸다.
UIKit은 자동으로 이벤트 관련 풀을 포함(Wrap)하고 있다.


<어플리케이션의 시작~종료>
App 시작 ---> App 초기화 ---> main nib 로딩 ---> 이벤트 발생 대기 상태 ---> 이벤트 처리 ---> App 종료


여기의 이벤트 발생 대기 ~ 이벤트 처리 사이에서 발생한 이벤트는 자동으로 autorelease 모드로 풀에 들어가게 된다.

 <- 원본 pdf에서 발최


Autorelease 오브젝트를 릴리스 되지 않게 유지하는 방법

앞에서 다룬 룰에 의하면 많은 메소드 들은 Autorelease 오브젝트를 돌려주게 된다.
이 오브젝트들은 풀에 저장되어 있다가 시간이 경과하면 릴리스 되는데, 이를 릴리스 되지 않게 유지하고 싶다면
릴리스 되기 전에 -retain을 해주면 된다.


name = [NSMutableString string];
// 여기서 name을 retain하여 유효하게 유지 하게 된다.
[name retain];
// ...
// 사용이 끝나면 마지막에 release 해주도록 한다. (또는 클래스의 -dealloc에서 릴리스 할 수도 있다.)
[name release];


Garbage Collection

Autorelease는 Garbage Collection이 아니다.
iPhone OS의 Objective-c는 Garbage Collection을 지원하지 않는다. => 메모리 관리를 해야 한다는 뜻.


4.Property

클래스의 프로퍼티 선언은 @property와 @synthesize를 이용하여 간략화 할 수 있다는 것을 이전 문법 공부에서도 알아봤다.
추가로 몇가지 나열하자면 property와 인스턴스 변수의 이름은 다르게 설정 할 수 있다.


@interface Person : NSObject {
    int numberOfYearsOld;
}
@property int age;
@end

@implementation Person

//numberOfYearsOld라는 인스턴스 변수의 Getter/Setter를 age이라는 이름으로 정의.
@synthesize age = numberOfYearsOld;
@end

실제로 Property 가 사용 되고 있는 곳

새로운 API들은 @property를 사용한다.
기존 API들은 getter/setter를 사용한다.
기본 API 보다는 주로 UIKit API에 빈번히 사용되고 있다.
어느쪽을 사용해도 의미는 똑같다.
    @property는 적어야 하는 코드의 양을 줄여주지만, 때로는 코드 내용이 명확하지 않게 느껴질수도 있다.


■ .(Dot) 문법과 self

@interface Person : NSObject
{
NSString *name;
}
@property (copy) NSString *name;
@end

위와 같이 Person 오브젝트에 name 이라는 인스턴스 변수가 있다고 가정 할 때,
우리는 self.name과 같이 .(dot) 문법을 사용할 수 있다.
하지만 여기서 self.name은 name을 직접 호출 하는 것이 아니라 name의 setter/getter 메소드를 통해 접근 하게 된다.


그래서 만약 setter 메소드를 만들때 아래와 같은 실수를 하게 된다면 무한 루프에 빠지게 된다.

@implementation Person
- (void)setAge:(int)newAge {
    self.age = newAge; //이 코드는 [self setAge:newAge]를 호출하게 됨으로 자기자신을 계속 부르는 무한 루프가 된다.
}
@end


■ 읽어야 할 문서들

• Objective-C 2.0 Programming Language
    “Defining a Class”
    “Declared Properties”
• Memory Management Programming Guide for Cocoa


이해를 돕기 위해 위 문서를 읽고 넘어가면 도움이 될 것이다.



출처 : http://blog.naver.com/PostView.nhn?blogId=katchup00&logNo=10078813140
Posted by 오늘마감
과제A - 클래스 생성과 사용

Lecture2 의 숙제에 대한 설명 또한 Lecture3 에서 주어지는것 같다. 쉬운 답을 얻기전에 검색해서 풀어보란 뜻인가??

아무튼 그냥 순서대로 Lecture3을 듣지 않은 상태에서 Lecture2의 숙제를 하기로 한다.


과제A. 클래스 생성과 사용  원문: WhatATool (Part II)


<순서>
Section 5. 클래스 생성
Section 6. 생성한 클래스 사용


이번 과제에서는 PolygonShape(다각형) 클래스를 생성한후 WhatATool의 메인 함수에서 클래스를 호출하는 함수를 불러본다.


아래와 같은 소스가 추가 될 것이다.


int main (int argc, const char * argv[]) {
    NSAutoreleasepool * pool = [[NSAutoreleasePool alloc] init];

    PrintPathInfo(); // Section 1
PrintProcessInfo(); // Section 2
PrintBookmarkInfo(); // Section 3
PrintIntrospectionInfo(); // Section 4
PrintPolygonInfo(); // Section 6 (section 5는 메인에 함수를 추가하지 않는다)
[pool release];
return 0;
}


Section 5. 클래스 생성

■ 새로운 PolygonShape 라는 클래스 만들기 (다각형 클래스)


Xcode에서
1.File > New File을 선택
2.Mac OS X아래 CoCoa 섹션의 'Objective-C class' 템플렛을 선택한다.
3.PolygonShape.m 으로 생성한다. - 헤더파일을 만들기 위한 체크박스를 체크하는 것을 잊지 말것.


* 새로운 클래스는 디폴트로 NSObject를 계승받는다.


자 이제 새로운 클래스에 속성을 부여해보자.
Objective-C 2.0은 오브젝트의 속성에 접근하는 새로운 메커니즘을 제공한다.
클래스는 "properties"를 정의 할 수 있으며, 이것이 유저가 클래스에 억세스 하는 방법을 제공한다.
properties는 개발자의 단순작업(getter/setter 코딩)을 없애주며 메모리 관리 폴리시와 속성의 사용법을 정의하도록 해준다.
예를 들면, property를 읽기 전용으로 지정하거나 오브젝트의 소유권등을 정의할 수 있다.


■ PolygonShape 클래스에 속성 지정하기


1. 아래의 속성을 지정한다.
• numberOfSides(면의 수) – 정수형
• minimumNumberOfSides(최소 면의 수) – 정수형
• maximumNumberOfSides(최소 면의 수) – 정수형
• angleInDegrees(내각) – 실수형, 읽기전용
• angleInRadians(호도) – 실수형, 읽기전용
• name(이름) – NSString 오브젝트, 읽기전용


2. numberOfSides, minimumNumberOfSides, maximumNumberOfSides의 세가지 속성은
적절한 타입의 인스턴스 변수로 저장될 수 있어야 한다. 이 속성들은 @synthesize 옵션을 이용하면 컴파일러가
자동으로 getter/setter를 생성하여주며, 읽기 전용 속성은 getter만이 생성된다.


3. setter 메소드에 아래와 같은 조건을 부여하라
• numberOfSides – 최소값과 최대값의 사이 값만 가질수 있다.
• minimumNumberOfSides – 2보다 커야 한다.
• maximumNumberOfSides – 12보다 작아야 한다.


maximumNumberOfSides에 5가 설정되어 있는데 numberOfSides에 9를 세팅하려고 한다면 아래와 같은 에러로그를 출력하라.
Invalid number of sides: 9 is greater than the maximum of 5 allowed


4. 아래와 같은 초기화 메소드를 생성하라.
- (id)initWithNumberOfSides:(int)sides minimumNumberOfSides:(int)min maximumNumberOfSides:(int)max;


5. 슈퍼클래스인 NSObject의 init메소드를 오버라이드 하여 아래와 같은 디폴트값을 설정하는 커스텀 init을 생성하라.
numberOfSides – 5, minimumNumberOfSides – 3, maximumNumberOfSides – 10


6. angleInDegrees와 angleInRadians는 @synthesize 옵션을 사용하지 말라.
그리고 인스턴스 변수도 불필요하다. 이 두 속성은 numberOfSides의 값에 의해 결정될 것이다.
여기서는 정규 다각형(regular polygon)만 만들것임으로 각도(angles)의 값은 모두 똑같을 것이다.


7. name속성도 @synthesize 옵션을 사용할 필요가 없다. (인스턴스 변수도 필요없다.)
면의 갯수로부터 다각형의 이름을 출력하게 될 것이다.
<예>
면이 3일 경우: “Triangle”
면이 4일 경우: “Square”


8. PolygonShape 클래스의 -description 메소드를 아래 예와 같이 나오도록 구현하라.
Hello I am a 4-sided polygon (aka a Square) with angles of 90 degrees (1.570796 radians).


9. dealloc메소드를 사용하여 메모리 관리를 하고, dealloc이 불리워졌을때 로그를 출력하도록 하여라.


<힌트>


•다각형의 이름은 위키에서 찾을 수 있다.
•내각(angleInDegrees)을 구하기 위한 식은 다음과 같다. (180 * (numberOfSides - 2) / numberOfSides)
•삼각법(trigonometry): 360° 는 2π(파이) 이다.
•π(파이)의 값은 M_PI에 정의되어 있다.

Section 6. 생성한 클래스 사용

WhatATool.m 파일에 #import "PolygonShape.h" 를 삽입한다.


중요!!! 여기서는 PolygonShape를 생성하기 위해 +alloc과 -init을 사용하도록 한다. 생성된 오브젝트는 배열에 넣도록 하고
사용이 끝난 후엔 메모리 관리 기술을 이용하여 오브젝트를 릴리스 하도록 한다.


1. alloc/init를 사용하여 mutable array를 생성하라.


2. 아래 값을 사용하여 3개 또는 그 이상의 PolygonShape 오브젝트를 생성하라.

Min number of sides Max number of sides Number of sides
 3  7  4
 5  9  6
 9  12  12

3. 생성한 오브젝트를 배열에 추가하고 description을 이용하여 로그를 출력하라. 최소한 3줄의 로그가 찍여야 한다.

4. polygon 오브젝트의 제약을 테스트 해본다.
루프를 돌며 numberOfSides에 10을 세팅해보라. 위의 테이블을 이용해 만든 오브젝트라면 두줄의 로그가 찍힐것이다.

5. polygon 오브젝트가 메모리로부터 릴리스 되었는지 확인한다.
주어진 규칙대로 생성한 클래스라면 dealloc이 불리면서 3번의 로그가 찍힐 것이다.


<시도>

우선 name의 getter를 구현하기 위해 다각형의 이름을 찾아봤다.

Polygon names

Name Edges
digon 2
triangle (or trigon) 3
quadrilateral (or quadrangle or tetragon) 4
pentagon 5
hexagon 6
heptagon 7
octagon 8
enneagon (or nonagon) 9
decagon 10
hendecagon 11
dodecagon 12

<구현한 소스>

PolygonShape.h +-----+-----+-----+-----+-----+

//

//  PolygonShape.h

//  WhatATool

//

//  Created on 09. 12. 14.

//  Copyright 2009 __MyCompanyName__. All rights reserved.

//

#import

@interface PolygonShape : NSObject {

intnumberOfSides;

intminimumNumberOfSides;

intmaximumNumberOfSides;

}

@propertyintnumberOfSides;

@propertyintminimumNumberOfSides;

@propertyintmaximumNumberOfSides;

@property (readonly) float angleInDegrees;

@property (readonly) float angleInRadians;

@property (readonly) NSString *name;

//헤더에 이 메소드를 추가하는걸 까먹어서 에러가 났었다.

- (id)initWithNumberOfSides:(int)sides minimumNumberOfSides:(int)min maximumNumberOfSides:(int)max;

@end

PolygonShape.m +-----+-----+-----+-----+-----+

//

//  PolygonShape.m

//  WhatATool

//

//  Created on 09. 12. 14.

//  Copyright 2009 __MyCompanyName__. All rights reserved.

//

#import "PolygonShape.h"

@implementation PolygonShape

@synthesize numberOfSides;

@synthesize minimumNumberOfSides;

@synthesize maximumNumberOfSides;

//synthesize선언한변수지만 setter존재하면 getter생성됨으로마음놓고써도된다.

-(void)setNumberOfSides:(int)newNumberOfSides {

    //numberOfSides최소값과최대값의사이값만가질수있다

    if(newNumberOfSides > maximumNumberOfSides) {

        //maximumNumberOfSides 5설정되어있는데 numberOfSides 9세팅하려고한다면에러로그를출력하라.

        NSLog(@"Invalid number of sides: %d is greater than the maximum of %d allowed", newNumberOfSides, maximumNumberOfSides);

    } elseif (newNumberOfSides < minimumNumberOfSides) {

        NSLog(@"Invalid number of sides: %d is less than the minimum of %d allowed", newNumberOfSides, minimumNumberOfSides);

    } else {

        numberOfSides = newNumberOfSides;

    }

}

//minimumNumberOfSides 2보다커야한다.

-(void)setMinimumNumberOfSides:(int)newMinimumNumberOfSides {

    if (newMinimumNumberOfSides < 2) {

    NSLog(@"Invalid minumum number of sides: %d is less than 2 allowed", newMinimumNumberOfSides);

} else {

    minimumNumberOfSides = newMinimumNumberOfSides;

}

}

//maximumNumberOfSides 12보다작아야한다.

-(void)setMaximumNumberOfSides:(int)newMaximumNumberOfSides {

    if (newMaximumNumberOfSides > 12) {

NSLog(@"Invalid maximum number of sides: %d is greater than 12 allowed", newMaximumNumberOfSides);

} else {

maximumNumberOfSides = newMaximumNumberOfSides;

}

}

//4. 초기화메소드를생성하라.

//주의! numberOfSides를 Max Min보다 먼저 세팅하려고 Max Min값이 0으로 인식되어 조건에서 튕겨나간다.

-(id)initWithNumberOfSides:(int)sides minimumNumberOfSides:(int)min maximumNumberOfSides:(int)max {

[selfsetMinimumNumberOfSides:min];

[selfsetMaximumNumberOfSides:max];

[selfsetNumberOfSides:sides];

returnself;

}

//5. 슈퍼클래스인 NSObject init메소드를오버라이드하여아래와같은디폴트값을설정하는커스텀 init생성하라.

-(id)init {

if (self = [superinit]) {

    self = [selfinitWithNumberOfSides:5minimumNumberOfSides:3maximumNumberOfSides:10];

}

returnself;

}

//내각

-(float)angleInDegrees {

return (180 * (self.numberOfSides - 2) / self.numberOfSides);

}

//라디안

-(float)angleInRadians {

returnM_PI / 180 * self.angleInDegrees;

}

//7. 면의갯수로부터다각형의이름을출력하게것이다.

-(NSString *)name {

    switch ([selfnumberOfSides]) {

case2: return@"digon"; break;

case3: return@"triangle"; break;

case4: return@"quadrilateral"; break;

case5: return@"pentagon"; break;

case6: return@"hexagon"; break;

case7: return@"heptagon"; break;

case8: return@"octagon"; break;

case9: return@"enneagon"; break;

case10: return@"decagon"; break;

case11: return@"hendecagon"; break;

case12: return@"dodecagon"; break;

default: return@"";

}

}

//8. description오버라이드

//: Hello I am a 4-sided polygon (aka a Square) with angles of 90 degrees (1.570796 radians).

-(NSString *)description {

return [NSStringstringWithFormat: @"Hello I am a %d-sided polygon (aka a %@) with angles of %.0f degrees (%.6f radians)."

self.numberOfSides, self.name, self.angleInDegrees, self.angleInRadians];

}

//9. dealloc메소드를사용하여메모리관리를하고, dealloc불리워졌을때로그를출력하도록하여라.

- (void)dealloc {

NSLog(@"dealloc called");

[superdealloc];

}

@end

WhatATool.m의 함수(Section 6) 부분 +-----+-----+-----+-----+-----+

//#import "PolygonShape.h" 를 잊지말자


//Section 6

void PrintPolygonInfo() {

    NSLog(@"----- Section 6 -----");


    //배열 생성

NSMutableArray *array = [[NSMutableArrayalloc] init];

PolygonShape *polygon1 = [[PolygonShapealloc] initWithNumberOfSides:4minimumNumberOfSides:3maximumNumberOfSides:7];

PolygonShape *polygon2 = [[PolygonShapealloc] initWithNumberOfSides:6minimumNumberOfSides:5maximumNumberOfSides:9];

PolygonShape *polygon3 = [[PolygonShapealloc] initWithNumberOfSides:12minimumNumberOfSides:9maximumNumberOfSides:12];

    //생성한 다각형 정보를 로그에 출력하고 배열에 다각형 오브젝트를 추가한다.

NSLog([polygon1 description]);

[array addObject:polygon1];

NSLog([polygon2 description]);

[array addObject:polygon2];

NSLog([polygon3 description]);

[array addObject:polygon3];

//제약을 테스트하기 위해 numberOfSides에 10을 넣어본다.

for (PolygonShape *polygon in array) {

polygon.numberOfSides = 10;

}

[polygon1 dealloc];

[polygon2 dealloc];

[polygon3 dealloc];

[array dealloc];

}

<결과>

2009-12-17 14:54:31.297 WhatATool[1125:10b] ----- Section 6 -----

2009-12-17 14:54:31.297 WhatATool[1125:10b] Hello I am a 4-sided polygon (aka a quadrilateral) with angles of 90 degrees (1.570796 radians).

2009-12-17 14:54:31.297 WhatATool[1125:10b] Hello I am a 6-sided polygon (aka a hexagon) with angles of 120 degrees (2.094395 radians).

2009-12-17 14:54:31.297 WhatATool[1125:10b] Hello I am a 12-sided polygon (aka a dodecagon) with angles of 150 degrees (2.617994 radians).

2009-12-17 14:54:31.298 WhatATool[1125:10b] Invalid number of sides: 10 is greater than the maximum of 7 allowed

2009-12-17 14:54:31.298 WhatATool[1125:10b] Invalid number of sides: 10 is greater than the maximum of 9 allowed

2009-12-17 14:54:31.298 WhatATool[1125:10b] dealloc called

2009-12-17 14:54:31.299 WhatATool[1125:10b] dealloc called

2009-12-17 14:54:31.299 WhatATool[1125:10b] dealloc called

The Debugger has exited with status 0.



출처 : http://blog.naver.com/PostView.nhn?blogId=katchup00&logNo=10076162791
Posted by 오늘마감