Objective-C 및 Cocoa를 작성할 때 사용하는 모범 사례는 무엇입니까? [닫은]


346

HIG (아주 편리합니다!) 에 대해 알고 있지만 Objective-C를 작성할 때, 특히 Cocoa (또는 CocoaTouch)를 사용할 때 어떤 프로그래밍 방식을 사용합니까?


이 블로그 게시물을 참조하십시오. ironwolf.dangerousgames.com/blog/archives/913
user392412

답변:


398

내가 생각하기 시작한 몇 가지가 표준이라고 생각하지 않습니다.

1) 속성의 출현으로 더 이상 "_"를 사용하여 "비공개"클래스 변수를 접두사로 사용하지 않습니다. 결국 다른 클래스에서 변수에 액세스 할 수 있다면 속성이 없어야합니까? 나는 코드를 더 못 생기게 만들기 위해 항상 "_"접두어를 싫어했고 이제는 생략 할 수있다.

2) 개인적인 것들에 관해서는, 개인 메소드 정의를 .m 파일 내에 클래스 확장으로 배치하는 것을 선호합니다.

#import "MyClass.h"

@interface MyClass ()
- (void) someMethod;
- (void) someOtherMethod;
@end

@implementation MyClass

외부인이 신경 써서는 안되는 것들로 .h 파일을 어지럽히는 이유는 무엇입니까? empty ()는 .m 파일의 개인 범주에 대해 작동하며 선언 된 메소드를 구현하지 않으면 컴파일 경고를 발행합니다.

3) dealloc을 @synthesize 지시문 바로 아래의 .m 파일 상단에 두었습니다. 당신이 다루고있는 것이 당신이 수업에서 생각하고 싶은 것들 목록의 최상위에 있지 않아야합니까? iPhone과 같은 환경에서 특히 그렇습니다.

3.5) 표 셀에서 성능을 위해 모든 요소 (셀 자체 포함)를 불투명하게 만듭니다. 그것은 모든 것에 적절한 배경색을 설정하는 것을 의미합니다.

3.6) NSURLConnection을 사용할 때 델리게이트 메소드를 구현하는 것이 좋습니다.

- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
                  willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
      return nil;
}

대부분의 웹 호출은 매우 독특하며 특히 웹 서비스 호출의 경우 응답을 캐시하려는 규칙보다 예외입니다. 표시된대로 방법을 구현하면 응답 캐싱이 비활성화됩니다.

Joseph Mattiello (iPhone 메일 링리스트에서 수신)의 유용한 iPhone 관련 팁도 있습니다. 더 많은 것이 있지만 이것들은 내가 생각한 가장 일반적으로 유용했습니다 (응답에 제공된 세부 사항을 포함하기 위해 원본에서 약간의 비트가 약간 편집되었습니다).

4) CoreLocation으로 작업 할 때와 같이 필요한 경우에만 배정 밀도를 사용하십시오. gcc가 부동 소수점으로 저장하도록 상수를 'f'로 끝내십시오.

float val = someFloat * 2.2f;

이것은 someFloat실제로 두 배가 될 때 가장 중요 합니다. 저장소에서 'val'의 정밀도를 잃기 때문에 혼합 모드 수학이 필요하지 않습니다. 부동 소수점 숫자는 iPhone의 하드웨어에서 지원되지만 단 정밀도와는 달리 배정 밀도 산술을 수행하는 데 여전히 더 많은 시간이 걸릴 수 있습니다. 참고 문헌 :

구형 전화에서는 계산 속도가 동일하지만 두 배보다 레지스터에 더 많은 단 정밀도 구성 요소를 가질 수 있으므로 많은 계산에서 단 정밀도가 더 빨라집니다.

5) 속성을로 설정하십시오 nonatomic. 그것들은 atomic기본적으로 있으며 합성시 멀티 스레딩 문제를 방지하기 위해 세마포어 코드가 생성됩니다. 99 %의 사람들은 아마도 이것에 대해 걱정할 필요가 없으며 비 원자로 설정하면 코드가 훨씬 덜 부풀어지고 메모리 효율적입니다.

6) SQLite는 대용량 데이터 세트를 캐시하는 매우 빠르고 빠른 방법입니다. 예를 들어지도 응용 프로그램은 타일을 SQLite 파일로 캐시 할 수 있습니다. 가장 비싼 부분은 디스크 I / O입니다. 큰 블록 을 보내 BEGIN;거나 COMMIT;큰 블록 사이 에 많은 작은 쓰기를 피하십시오 . 예를 들어 새로운 제출마다 재설정되는 2 초 타이머를 사용합니다. 만료되면 COMMIT를 보냅니다. 모든 쓰기가 하나의 큰 덩어리로 진행됩니다. SQLite는 트랜잭션 데이터를 디스크에 저장하고이 시작 / 종료 래핑을 수행하면 많은 트랜잭션 파일을 만들지 않고 모든 트랜잭션을 하나의 파일로 그룹화 할 수 있습니다.

또한 SQL이 기본 스레드에 있으면 GUI가 차단됩니다. 쿼리가 매우 긴 경우 쿼리를 정적 개체로 저장하고 별도의 스레드에서 SQL을 실행하는 것이 좋습니다. 쿼리 문자열에 대한 데이터베이스를 @synchronize() {}블록 단위로 수정하는 모든 항목을 래핑하십시오 . 짧은 쿼리의 경우 주 스레드에 물건을두면 더 편리합니다.

더 많은 SQLite 최적화 팁이 여기 있지만, 문서가 구식으로 보이지만 많은 점이 여전히 아마도 좋습니다.

http://web.utk.edu/~jplyon/sqlite/SQLite_optimization_FAQ.html


3
이중 산술에 대한 좋은 팁입니다.
Adam Ernst

8
클래스 확장은 이제 개인 메소드에 선호되는 방법입니다. developer.apple.com/Mac/library/documentation/Cocoa/Conceptual/…
Casebash

9
iPhone의 복식에 대한 귀하의 조언이 구식입니다 stackoverflow.com/questions/1622729/…
Casebash

3
구식이 아닙니다. 완전히 잘못된 것 : 원래의 iPhone 지원은 거의 같은 속도로 하드웨어에서 플로팅되고 두 배가됩니다. SQLite는 또한 트랜잭션을 메모리에 보관하지 않습니다. 그들은 디스크에 저널링됩니다. 긴 쿼리 만 UI를 차단합니다. 메인 스레드에서 모든 것을 실행하고 더 빠른 쿼리를 사용하는 것이 덜 복잡합니다.
tc.

1
@ tc : 거래에 관한 SQL 항목을 수정했습니다. 나 자신은 마지막 4 개 정도의 항목을 쓰지 않았습니다. 또한 쿼리를 백그라운드로 이동하는 것에 대한 부분은 매우 긴 쿼리에만 해당되는 경우가 있음을 분명히했습니다 (때로는 더 짧게 얻을 수없는 경우도 있음). 그러나 몇 가지 점 때문에 모든 것을 "잘못된"것으로 부르는 것은 오히려 극단적 인 느낌입니다. 또한 위의 답변은 이미 "구형 전화에서 계산이 동일한 속도로 작동한다고 가정합니다."라고 말했지만 더 많은 수의 단 정밀도 레지스터에 대해서는 여전히 선호합니다.
Kendall Helmstetter Gelner

109

알 수없는 문자열을 형식 문자열로 사용하지 마십시오

메서드 나 함수가 형식 문자열 인수를 사용할 때는 형식 문자열의 내용을 제어 할 수 있어야합니다.

예를 들어, 문자열을 로깅 할 때 문자열 변수를 유일한 인수로 NSLog다음 과 같이 전달하려고합니다 .

    NSString *aString = // get a string from somewhere;
    NSLog(aString);

이에 대한 문제점은 문자열에 형식 문자열로 해석되는 문자가 포함될 수 있다는 것입니다. 이로 인해 잘못된 출력, 충돌 및 보안 문제가 발생할 수 있습니다. 대신 문자열 변수를 형식 문자열로 대체해야합니다.

    NSLog(@"%@", aString);

4
나는 전에 이것에 물린 적이있다.
Adam Ernst

이것은 모든 프로그래밍 언어에 대한 좋은 조언이다
톰 Fobear

107

다른 환경에서 익숙하지 않은 표준 Cocoa 이름 지정 및 형식 지정 규칙과 용어를 사용하십시오. 많은 Cocoa 개발자 가 있으며 다른 개발자가 코드 작업을 시작할 때 다른 Cocoa 코드와 비슷하게 보이고 느껴지면 훨씬 더 접근하기 쉽습니다.

해야 할 것과하지 말아야 할 것의 예 :

  • id m_something;객체의 인터페이스에서 선언하지 말고 그것을 멤버 변수 또는 필드 라고 부릅니다 . something또는 _something이름을 사용 하여 인스턴스 변수 라고합니다 .
  • 게터의 이름을 지정하지 마십시오 -getSomething. 적절한 코코아 이름은 -something입니다.
  • 세터의 이름을 지정하지 마십시오 -something:. 그것은해야한다-setSomething:
  • 메소드 이름은 인수와 함께 배치되며 콜론을 포함합니다. 그건 -[NSObject performSelector:withObject:]아니고 NSObject::performSelector.
  • 밑줄 (밑줄) 대신 메소드 이름, 매개 변수, 변수, 클래스 이름 등에 인터 캡 (CamelCase)을 사용하십시오.
  • 클래스 이름은 대문자, 변수 및 메소드 이름으로 소문자로 시작합니다.

무엇을 하든지 Win16 / Win32 스타일 헝가리어 표기법을 사용 하지 마십시오 . 마이크로 소프트조차도 .NET 플랫폼으로 전환하면서 포기했습니다.


5
나는 setSomething : / something을 전혀 사용하지 말고 대신 속성을 사용한다고 주장한다. 이 시점에서 정말 타이거 (사용하지 않는 속성에 대한 유일한 이유) 대상으로해야한다는 소수의 사람들이있다
켄달 Helmstetter Gelner

18
속성은 여전히 ​​접근 자 메서드를 생성하며 속성의 getter = / setter = 속성을 사용하면 메서드 이름을 지정할 수 있습니다. 또한 속성이있는 foo.something 구문 대신 [foo something] 구문을 사용할 수 있습니다. 따라서 접근 자 이름은 여전히 ​​관련이 있습니다.
Chris Hanson

3
이것은 C ++에서 온 누군가를위한 훌륭한 참고 자료입니다.
클린턴 블랙 모어

4
setter가 데이터베이스에 무언가를 저장하지 않아야합니다. 코어 데이터가 설정자가 즉시 업데이트를 생성하지 않고 NSManagedObjectContext에서 -save : 메소드를 갖는 이유가 있습니다.
Chris Hanson

2
옵션이 아닌지 의심 스럽지만 앱 아키텍처를 다시 방문해야 할 수도 있습니다. (명확하게 말하면 : "핵심 데이터를 사용해야했습니다."라는 말이 아닙니다. "설정자는 데이터베이스에 저장해서는 안됩니다." 사실상 항상 가능하고 더 나은 솔루션입니다.
Chris Hanson

106

IB 아울렛

역사적으로, 콘센트의 메모리 관리는 열악했습니다. 현재 모범 사례는 콘센트를 속성으로 선언하는 것입니다.

@interface MyClass :NSObject {
    NSTextField *textField;
}
@property (nonatomic, retain) IBOutlet NSTextField *textField;
@end

속성을 사용하면 메모리 관리 의미가 명확 해집니다. 또한 인스턴스 변수 합성을 사용하는 경우 일관된 패턴을 제공합니다.


1
펜촉의 로딩이 두 번 유지되지 않습니까? (1 번 펜촉, 2 번 속성 지정). 내가 dealloc에있는 사람들을 풀어 주어야합니까?
Kornel 2016 년

6
누출을 피하려면 viewDidUnload (iPhone OS 3.0 이상) 또는 사용자 정의 setView : 메소드에서 콘센트를 제거해야합니다. 분명히 당신은 또한 dealloc에서 해제해야합니다.
Frank Szczerba

2
: 모든 사람이 스타일에 동의 있다는 사실을 숙지 weblog.bignerdranch.com/?p=95
마이클

이것이 애플도하는 방식이다. "iPhone 3 개발 시작"은 이전 버전의 변경 사항도 언급합니다.
ustun

나는 이것을 다른 의견으로 언급했지만 여기에 배치해야합니다 .iOS 앱에서 동적 ivar 합성이 시작되면 (있는 경우?) iBOutlet을 속성 대 ivar에 배치하게되어 기쁩니다!
Joe D' Andrea

97

LLVM / Clang 정적 분석기 사용

참고 : Xcode 4에서는 이제 IDE에 내장되어 있습니다.

Clang Static Analyzer 를 사용하여 Mac OS X 10.5에서 C 및 Objective-C 코드 (아직 C ++ 없음)를 놀랍게도 분석 할 수 있습니다. 설치하고 사용하는 것은 간단합니다.

  1. 이 페이지 에서 최신 버전을 다운로드 하십시오 .
  2. 명령 행에서 cd프로젝트 디렉토리로.
  3. 실행합니다 scan-build -k -V xcodebuild.

(추가 제약 사항 등이 있습니다. 특히 "디버그"구성에서 프로젝트를 분석해야 합니다. 자세한 내용 은 http://clang.llvm.org/StaticAnalysisUsage.html 을 참조하십시오 . 그것은 무엇으로 귀결됩니다.)

그런 다음 분석기는 메모리 관리 및 컴파일러가 감지 할 수없는 기타 기본 문제를 보여주는 일련의 웹 페이지를 생성합니다.


1
다음 지침을 따를 때까지이 작업을 수행하는 데 문제가있었습니다. oiledmachine.com/posts/2009/01/06/…
bbrown

15
Snow Leopard의 XCode 3.2.1에는 이미 내장되어 있습니다. Run-> Build and Analyze를 사용하여 수동으로 실행 하거나 "Static Analyzer 실행"빌드 설정을 통해 모든 빌드에 대해이를 활성화 할 수 있습니다. 이 도구는 현재 C 및 Objective-C 만 지원하지만 C ++ / Objective-C ++는 지원하지 않습니다.
oefe

94

이것은 미묘하지만 편리한 것입니다. 다른 객체의 대리자로 자신을 전달하는 경우 먼저 해당 객체의 대리자를 재설정하십시오 dealloc.

- (void)dealloc
{
self.someObject.delegate = NULL;
self.someObject = NULL;
//
[super dealloc];
}

이렇게하면 더 이상 대리자 메서드가 전송되지 않습니다. 당신에 대해이야으로 dealloc에테르로 사라 당신은 확실히 아무 실수로 당신에게 더 이상 메시지를 보낼 수 없음을 만들고 싶어. self.someObject는 다른 객체 (단일 또는 오토 릴리즈 풀 등)에 보관 될 수 있으며 "메시지를 보내지 마십시오!"라고 말할 때까지는 단지 해제 할 대상이라고 생각합니다. 공정한 게임입니다.

이 습관에 들어가면 디버그하기 힘든 이상한 충돌을 피할 수 있습니다.

동일한 보안 주체가 키 값 관찰 및 NSNotifications에도 적용됩니다.

편집하다:

훨씬 더 방어적인 변화 :

self.someObject.delegate = NULL;

으로:

if (self.someObject.delegate == self)
    self.someObject.delegate = NULL;

8
이것에 대해 미묘한 것은 없습니다. 문서에 따르면이 작업을 수행해야한다고 명시되어 있습니다. 보낸 사람 Memory Management Programming Guide for Cocoa: Additional cases of weak references in Cocoa include, but are not restricted to, table data sources, outline view items, notification observers, and miscellaneous targets and delegates. In most cases, the weak-referenced object is aware of the other object’s weak reference to it, as is the case for circular references, and is responsible for notifying the other object when it deallocates.
johne

NULL은 메모리를 비우지 않기 때문에 NULL 대신 nil을 사용하는 것이 좋습니다.
Naveen Shan

@NaveenShan nil == NULL. 즉 제외하고 그들은 정확히 동일 nil입니다 idNULL입니다 void *. 당신의 진술은 사실이 아닙니다.

@WTP yep, nil == NULL이지만, nil을 사용하는 것이 분명히 선호되는 방법입니다. 애플 예제 코드 조각을 살펴보면 어디서나 nil을 사용하고 있으며, nil은 id이므로 void보다 선호됩니다. ID를 보내는 경우, 즉
Ahti

1
@Ahti 정확하게, Nil(대문자)는 유형 Class*입니다. 모두 동일하지만 잘못된 것을 사용하면 특히 Objective-C ++에서 작은 버그가 발생할 수 있습니다.

86

@kendell

대신에:

@interface MyClass (private)
- (void) someMethod
- (void) someOtherMethod
@end

사용하다:

@interface MyClass ()
- (void) someMethod
- (void) someOtherMethod
@end

Objective-C 2.0의 새로운 기능.

클래스 확장은 Apple의 Objective-C 2.0 참조에 설명되어 있습니다.

"클래스 확장을 사용하면 기본 클래스 @interface 블록 이외의 위치에 클래스에 대한 추가 필수 API를 선언 할 수 있습니다."

따라서 이들은 실제 수업의 일부이며 수업 외에 (비공개) 카테고리가 아닙니다. 미묘하지만 중요한 차이점.


당신은 그렇게 할 수는 있지만, .m 파일에있는 것으로부터 이미 분명하지만 "개인"섹션 (기능보다 많은 문서)으로 명시 적으로 라벨링하고 싶습니다.
Kendall Helmstetter Gelner

2
개인 범주와 클래스 확장 사이에 차이 있는 경우를 제외하고 : "클래스 확장을 사용하면 다음 예제에 설명 된대로 기본 클래스 @interface 블록 이외의 위치에서 클래스에 대한 추가 필수 API를 선언 할 수 있습니다."편집의 링크를 참조하십시오.
schwa

CE 메서드를 구현하지 않은 경우 컴파일러에서 경고하는 차이점이 있지만 모든 메서드가 동일한 파일에 있고 모든 개인 경우에는 그 측면이 중요하지 않다는 데 동의합니다. 난 아직도 전방 참조 블록이 개인 표시의 유지 보수 측면 선호
켄달 Helmstetter Gelner을

3
나는 (Private)를 ()보다 유지 관리하기 쉬운 것으로 보지 않습니다. 걱정이 되시면, 많은 의견이 도움이 될 것입니다. 그러나 분명히 살고 살자. YMMV 등
schwa

17
()대신에 (Private)(또는 다른 카테고리 이름) 대신 사용하는 것이 중요한 이점이 있습니다 . 일반인에게만 읽기 전용 인 속성을 읽기 / 쓰기로 다시 선언 할 수 있습니다. :)
Pascal

75

자동 릴리스를 피하십시오

일반적으로 (1) 수명을 직접 제어 할 수 없기 때문에 자동 해제 된 객체는 비교적 오랫동안 지속될 수 있으며 응용 프로그램의 메모리 공간을 불필요하게 증가시킬 수 있습니다. 데스크톱에서는 이것이 별다른 영향을 미치지 않지만,보다 제한된 플랫폼에서는 중요한 문제가 될 수 있습니다. 따라서 모든 플랫폼, 특히보다 제한적인 플랫폼에서는 자동 릴리스 된 객체로 이어질 방법을 사용하지 않는 것이 좋습니다. 대신 alloc / init 패턴을 사용하는 것이 좋습니다.

따라서 다음보다는

aVariable = [AClass convenienceMethod];

가능한 경우 대신 다음을 사용해야합니다.

aVariable = [[AClass alloc] init];
// do things with aVariable
[aVariable release];

새로 작성된 객체를 리턴하는 고유 한 메소드를 작성할 때 Cocoa의 이름 지정 규칙 을 사용하여 메소드 이름 앞에 "new"를 붙여서 해제해야 함을 수신자에게 플래그 지정할 수 있습니다 .

따라서 다음 대신

- (MyClass *)convenienceMethod {
    MyClass *instance = [[[self alloc] init] autorelease];
    // configure instance
    return instance;
}

당신은 쓸 수 있습니다 :

- (MyClass *)newInstance {
    MyClass *instance = [[self alloc] init];
    // configure instance
    return instance;
}

메소드 이름은 "new"로 시작하므로 API 소비자는 수신 된 오브젝트를 해제 할 책임이 있음을 알고 있습니다 (예 : NSObjectController의 newObject메소드 참조 ).

(1) 자체 로컬 자동 릴리스 풀을 사용하여 제어 할 수 있습니다. 이에 대한 자세한 내용은 자동 릴리스 풀을 참조하십시오 .


6
오토 릴리즈를 사용 하지 않는 것의 이점이 비용을 능가한다는 것을 알았습니다 (즉, 더 많은 메모리 누수 버그). 메인 스레드의 코드는 어쨌든 상당히 짧게 실행되어야하며 (그렇지 않으면 UI가 정지 될 수 있음), 더 오래 실행되고 메모리 집약적 인 백그라운드 코드의 경우 항상 메모리 집약적 부분을 로컬 자동 릴리스 풀에 랩핑 할 수 있습니다.
adib

56
동의하지 않습니다. 가능하면 자동 릴리스 된 개체를 사용해야합니다. 메모리 공간을 너무 많이 늘리면 다른 메모리 공간을 사용해야합니다 NSAutoreleasePool. 그러나 이것이 실제로 문제임을 확인한 후에 만 ​​가능합니다. 조기 최적화 및 그 모든 것
Sven

3
나는 40 초 미만을 보낸다. 새로운 객체를 인스턴스화 할 때 [someObject release]를 입력하고 "추가 라인"을 읽는 하루가있었습니다. 그러나 특별한 경우에만 표시되고 콘솔에 일관된 오류가없는 자동 릴리스 버그를 찾기 위해 17 시간 동안 불에 탔습니다. 그래서 나는 "오토 릴리즈를 사용하지 않는 것의 이점이 그 비용보다 크다"고 말했을 때 adib에 동의합니다.
RickiG

7
나는 Sven에 동의합니다. 주요 목표는 필요한 경우에만 메모리 최적화를 통해 코드 명확성과 코딩 오류를 줄이는 것입니다. [[[Foo alloc] init] autorelease]를 입력하는 것이 빠르며이 새로운 객체의 릴리스 문제를 즉시 처리합니다. 코드를 읽을 때 누출이 발생하지 않도록 해당 릴리스를 찾아 다닐 필요가 없습니다.
Mike Weller

3
자동 릴리스 된 객체의 수명주기는 잘 정의되고 충분한 수준에서 결정 가능합니다.
Eonil

69

이것들 중 일부는 이미 언급되었지만 다음은 내 머리 꼭대기에서 생각할 수있는 것입니다.

  • KVO 명명 규칙을 따르십시오. 지금 KVO를 사용하지 않더라도 종종 내 경험에 따르면 미래에도 여전히 도움이됩니다. KVO 또는 바인딩을 사용하는 경우 예상대로 작동하는 것을 알아야합니다. 여기에는 접근 자 메서드와 인스턴스 변수뿐만 아니라 많은 관계, 유효성 검사, 자동 알림 종속 키 등이 포함됩니다.
  • 개인 메서드를 범주에 넣습니다. 인터페이스뿐만 아니라 구현도 마찬가지입니다. 사적인 방법과 사적인 방법 사이에 개념적으로 약간의 거리를 두는 것이 좋습니다. 내 .m 파일에 모든 것을 포함시킵니다.
  • 백그라운드 스레드 메소드를 카테고리에 넣습니다. 같은 상기와. 메인 스레드에 무엇이 있고 무엇이 아닌지에 대해 생각할 때 명확한 개념적 장벽을 유지하는 것이 좋습니다.
  • 사용하십시오 #pragma mark [section]. 일반적으로 나는 내 자신의 메서드, 각 하위 클래스의 재정의 및 정보 또는 공식 프로토콜별로 그룹화합니다. 이것은 내가 찾고있는 것을 정확하게 건너 뛸 수있게 해줍니다. 같은 주제에서 비슷한 방법 (예 : 테이블 뷰의 대리자 메서드)을 함께 그룹화하지 마십시오.
  • 개인 메소드 및 ivar 앞에 _를 접 두부로 추가하십시오. 나는 모양이 마음에 들며 우연히 재산을 의미 할 때 ivar를 사용할 가능성이 적습니다.
  • init & dealloc에서 뮤 테이터 메소드 / 속성을 사용하지 마십시오. 나는 그로 인해 나쁜 일이 없었지만 객체의 상태에 따라 무언가를 수행하도록 메소드를 변경하면 논리를 볼 수 있습니다.
  • 속성에 IBOutlets를 넣습니다. 저는이 책을 실제로 읽었지만 시작하겠습니다. 메모리 이점에 관계없이 문체 적으로 (적어도 나에게는) 더 나은 것처럼 보입니다.
  • 꼭 필요한 코드를 작성하지 마십시오. 이것은 실제로 #define유언장을 할 때 ivar를 만들 거나 데이터가 필요할 때마다 정렬하는 대신 배열을 캐싱하는 것과 같은 많은 것들을 다룹니다 . 내가 이것에 대해 말할 수있는 많은 것이 있지만, 결론은 필요할 때까지 코드를 작성하지 않거나 프로파일 러가 지시합니다. 장기적으로 유지 관리가 훨씬 쉽습니다.
  • 시작한 것을 끝내십시오.반제품이 많은 버그가있는 코드는 프로젝트를 죽이는 가장 빠른 방법입니다. 괜찮은 스터브 방법이 필요한 경우 NSLog( @"stub" )안에 넣어서 표시 하거나 물건을 추적하고 싶습니다.

3
클래스 연속에 개인 메서드를 넣어야한다고 제안합니다. (예 : @interface MyClass () ... @end in .m)
Jason Medeiros

3
#PRAGMA 대신 // Mark : [Section] 주석을 사용하면보다 이식성이 뛰어나고 동일하게 작동합니다.
aleemb 2016 년

내가 빠뜨린 특별한 문법이 없다면, // Mark : Xcode의 함수 드롭 다운 메뉴에 레이블을 추가하지 않습니다. 실제로 사용하는 이유의 절반입니다.
Marc Charbonneau 2016 년

6
드롭 다운에 표시되도록 대문자 "// MARK : ..."를 사용해야합니다.
Rhult

3
관련 하여 드롭 다운에 표시되는 완료 코드를 표시 Finish what you start하는 // TODO:데 사용할 수도 있습니다 .
iwasrobbed

56

단위 테스트를 작성하십시오. Cocoa에서는 다른 프레임 워크에서 더 어려울 수 있는 많은 것들을 테스트 할 수 있습니다 . 예를 들어, UI 코드를 사용하면 일반적으로 사물이 연결되어 있는지 확인하고 사용할 때 작동한다는 것을 신뢰할 수 있습니다. 상태를 설정하고 델리게이트 메소드를 쉽게 호출하여 테스트 할 수 있습니다.

또한 내부 테스트를 작성하는 데 방해가되는 공개 vs. 보호 vs. 개인 분석법 가시성이 없습니다.


어떤 테스트 프레임 워크를 권장합니까?
melfar

13
Xcode에는 Objective-C 단위 테스트 프레임 워크 인 OCUnit이 포함되어 있으며 빌드 프로세스의 일부로 단위 테스트 번들 실행을 지원합니다.
Chris Hanson

55

황금률 : 당신이 alloc 그렇다면 당신 release!

업데이트 : ARC를 사용하지 않는 한


26
또한 경우 copy, mutableCopy, new또는 retain.
Sven

54

Objective-C를 마치 Java / C # / C ++ / etc 인 것처럼 작성하지 마십시오.

한때 Java EE 웹 응용 프로그램을 작성하는 데 사용되는 팀이 Cocoa 데스크탑 응용 프로그램을 작성하는 것을 보았습니다. 마치 Java EE 웹 애플리케이션 인 것처럼. Foo 클래스와 Fooable 프로토콜 만 있으면 필요할 때 AbstractFooFactory와 FooFactory와 IFoo와 Foo가 많이 날았습니다.

이것을하지 않는 것의 일부는 언어의 차이점을 진정으로 이해하는 것입니다. 예를 들어 Objective-C 클래스 메소드는 인스턴스 메소드처럼 동적으로 전달되며 서브 클래스에서 재정의 될 수 있으므로 위의 추상 팩토리 및 팩토리 클래스가 필요하지 않습니다.


10
Objective-C에서 추상 팩토리를 작성한 Java 개발자로서 나는이 흥미로운 것을 발견했다. 이것이 어떻게 작동하는지 좀 더 설명해 주시겠습니까?
teabot

2
이 답변을 게시 한 이후로 항상 추상 팩토리 클래스가 필요하지 않다고 생각하십니까?
kirk.burleson

50

디버깅 매직 을 즐겨 찾기에 추가하십시오 페이지 하십시오. 이것은 코코아 버그의 원인을 찾으려고 벽에 머리를 두드리는 첫 번째 장소입니다.

예를 들어, 나중에 충돌을 일으키는 메모리를 처음 할당 한 방법 (예 : 앱 종료 중)을 찾는 방법을 알려줍니다.


1
이제 iOS 전용 버전의 디버깅 매직 페이지가 있습니다.
Jeethu

38

내가 지금 Newbiecategoryaholism이라고 부르기로 결정한 것을 피하십시오. Objective-C를 처음 사용하는 사람들은 카테고리를 발견 할 때 종종 존재하는 모든 클래스에 유용한 작은 카테고리를 추가하여 카테고리를 찾는다 ( "무엇입니까? 숫자를 로마 숫자로 변환하여 NSNumber로 변환하는 방법을 추가 할 수 있습니다!" ).

이러지 마

20 가지 기초 클래스 위에 뿌려진 수십 가지의 작은 범주 메소드를 통해 코드를보다 이식 가능하고 이해하기 쉽게 만들 수 있습니다.

대부분의 경우 코드를 간소화하는 데 도움이되는 카테고리 방법이 필요하다고 생각할 때 메소드를 재사용하지 않는 경우가 많습니다.

범주 방법의 이름을 지정하지 않는 한 (그리고 완전히 미친 ddribin 외에 누가 있는가?) Apple이나 플러그인 또는 주소 공간에서 실행되는 다른 항목도 동일한 범주를 정의 할 가능성이 있습니다. 약간 다른 부작용을 가진 같은 이름의 방법 ....

확인. 경고를 받으면 "이 부분을 수행하지 마십시오"를 무시하십시오. 그러나 극단적 인 구속을 행사하십시오.


귀하의 답변이 마음에 듭니다. 여러 곳에서 일부 코드를 복제하려고하지 않고 코드를 분류하려는 클래스에 명확하게 속하지 않는 한 유틸리티 코드를 저장하기 위해 카테고리를 사용하지 않는 것이 좋습니다.
Kendall Helmstetter Gelner

이름을 바꾸는 범주 방법에 대한 지원을 시작하고 말하고 싶습니다. 그것은 옳은 일처럼 보입니다.
Michael Buckley

로마 숫자 만있는 경우 +1 나는 완전히 그렇게 할 것입니다!
Brian Postow

14
반론 : 지난 1 년 반 동안 나는 "반복적으로 구현 될 수 있다면 그렇게하는 것"과 정반대의 정책을 따랐다. 결과적으로 내 코드는 Apple이 제공하는 자세한 샘플 코드보다 훨씬 간결하고 표현력이 뛰어나고 읽기 쉽습니다. 네임 스페이스 충돌로 약 10 분이 소요되었으며 아마도 내가 만든 효율성으로 인해 수개월이 걸렸을 것입니다. 나는 각자 자신에게 위험을 알고있는이 정책을 채택했으며, 그 일을 매우 기쁘게 생각합니다.
cduhn

7
동의하지 않습니다. 그것이 함수가되고 Foundation 객체에 적용되고, 좋은 이름을 생각할 수 있다면, 범주에 붙이십시오. 코드가 더 읽기 쉽습니다. 여기서 중요한 점은 모든 것을 적당히 수행하는 것입니다.
mxcl

37

세계의 서브 클래스 저항. Cocoa에서는 다른 프레임 워크에서 서브 클래 싱을 통해 수행되는 기본 런타임을 위임하고 사용하여 많은 작업을 수행합니다.

예를 들어 Java에서는 익명 인스턴스를 사용합니다. *Listener 서브 클래스 많이 사용하고 .NET에서는 EventArgs서브 클래스를 많이 사용합니다 . 코코아에서는 타겟 액션이 대신 사용됩니다.


6
그렇지 않으면 "상속 구성"이라고도합니다.
Andrew Ebling

37

사용자가 원하는대로 문자열 정렬

사용자에게 표시 할 문자열을 정렬 할 때는 간단한 compare:방법을 사용하지 않아야합니다 . 대신 항상 다음과 같은 현지화 된 비교 방법을 사용해야합니다.localizedCompare: 또는localizedCaseInsensitiveCompare: 합니다.

자세한 내용은 문자열 검색, 비교 및 ​​정렬을 참조하십시오 .


31

선언 된 속성

일반적으로 모든 특성에 Objective-C 2.0 선언 특성 기능을 사용해야합니다. 공개되지 않은 경우 클래스 확장에 추가하십시오. 선언 된 속성을 사용하면 메모리 관리 시맨틱이 즉시 명확 해지며 할당 해제 방법을보다 쉽게 ​​확인할 수 있습니다. 속성 선언을 함께 그룹화하면 해당 속성을 빠르게 스캔하고 할당 취소 방법의 구현과 비교할 수 있습니다.

속성을 '비 원자'로 표시하지 않기 전에 열심히 생각해야합니다. 으로 언어 가이드 프로그래밍 목적 C 노트, 속성은 기본적으로 원자이며, 발생 상당한 오버 헤드. 또한 모든 속성을 원 자성으로 만들면 응용 프로그램이 스레드로부터 안전하지 않습니다. 물론 '비 원자'를 지정하지 않고 자신의 접근 자 메소드를 구현하지 않고 구현하는 경우 원자 방식으로 구현해야합니다.


26

nil 값을 생각하십시오

이 질문에서 알 수 있듯이 메시지 nil는 Objective-C에서 유효합니다. 이 기능은 종종 더 깨끗하고 자연스러운 코드로 이끄는 이점 인 반면, nil예상치 못한 가치가있을 경우이 기능으로 인해 독특하고 추적하기 어려운 버그가 발생할 수 있습니다.


나는이있다 : #define SXRelease(o); o = nil과에 대해 동일 CFRelease하고 free. 이것은 모든 것을 단순화합니다.

26

NSAssert와 친구를 사용하십시오. 나는 항상 nil을 유효한 객체로 사용합니다 ... 특히 nil로 메시지를 보내는 것은 Obj-C에서 완벽하게 유효합니다. 그러나 변수의 상태를 실제로 확인하려면 NSAssert와 NSParameterAssert를 사용하면 문제를 쉽게 추적 할 수 있습니다.



23

간단하지만 잊혀진 것. 사양에 따르면 :

일반적으로 동일한 선택기 (같은 이름)를 가진 다른 클래스의 메소드도 동일한 리턴 및 인수 유형을 공유해야합니다. 이 제약 조건은 동적 바인딩을 허용하기 위해 컴파일러에 의해 부과됩니다.

이 경우 다른 클래스에 있더라도 동일한 명명 된 선택기 는 모두 동일한 반환 / 인수 유형을 갖는 것으로 간주됩니다. 다음은 간단한 예입니다.

@interface FooInt:NSObject{}
-(int) print;
@end

@implementation FooInt
-(int) print{
    return 5;
}
@end

@interface FooFloat:NSObject{}
-(float) print;
@end

@implementation FooFloat
-(float) print{
    return 3.3;
}
@end

int main (int argc, const char * argv[]) {

    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];    
    id f1=[[FooFloat alloc]init];
    //prints 0, runtime considers [f1 print] to return int, as f1's type is "id" and FooInt precedes FooBar
    NSLog(@"%f",[f1 print]);

    FooFloat* f2=[[FooFloat alloc]init];
    //prints 3.3 expectedly as the static type is FooFloat
    NSLog(@"%f",[f2 print]);

    [f1 release];
    [f2 release]
    [pool drain];

    return 0;
}   

잊기 쉬운 것입니다. 그럼에도 불구하고 중요
Brock Woolf

3
이것은 정적 타이핑을 자제 할 때만 걱정됩니다. 컴파일러가 형식을 알고 있으면 인수 및 반환 형식이 문제없이 달라질 수 있습니다. 개인적으로, 나는 이것이 종종 문제가되지 않는다는 것을 안다. Apple은 이름은 같지만 반환 유형이 다른 많은 메소드를 가지고 있습니다. 마지막으로, 모호한 경우에 경고하는 컴파일러 플래그가 있습니다.
Nikolai Ruhe

우리가 Apple의 명명 규칙 지침을 따르면,이 상황은 일어나지 않을 것입니다 :)
Eonil

22

Leopard (Mac OS X 10.5) 이상을 사용하는 경우 계측기 응용 프로그램을 사용하여 메모리 누수를 찾고 추적 할 수 있습니다. Xcode에서 프로그램을 빌드 한 후 실행> 성능 도구로 시작> 누출을 선택하십시오.

앱에 누수가 표시되지 않더라도 물건을 너무 오래 보관할 수 있습니다. 인스트루먼트에서이를 위해 ObjectAlloc 인스트루먼트를 사용할 수 있습니다. 인스트루먼트 문서에서 ObjectAlloc 인스트루먼트를 선택하고보기> 디테일을 선택하여 인스트루먼트의 세부 사항을 표시하십시오 (표시되지 않은 경우) (옆에 확인 표시가 있어야 함). ObjectAlloc 세부 사항의 "할당 수명"아래에서 "생성 및 여전히 생활"옆에있는 단일 선택 단추를 선택하십시오.

이제 응용 프로그램 기록을 중지 할 때마다 ObjectAlloc 도구를 선택하면 "# Net"열에 응용 프로그램의 각 여전히 존재하는 개체에 대한 참조 수가 표시됩니다. 자신의 클래스뿐만 아니라 NIB 파일의 최상위 객체 클래스도 살펴보십시오. 예를 들어, 화면에 창이없고 여전히 살아있는 NSWindow에 대한 참조가 있으면 코드에서 해제하지 않았을 수 있습니다.


21

dealloc에서 정리하십시오.

이것은 가장 잊어 버리는 것 중 하나입니다-esp. 150mph로 코딩 할 때. 항상, 항상, 할당 해제에서 속성 / 구성원 변수를 정리하십시오.

나는 새로운 점 표기법 과 함께 Objc 2 속성을 사용하고 싶습니다 . 종종 다음과 같이 간단합니다.

- (void)dealloc
{
    self.someAttribute = NULL;
    [super dealloc];
}

이것은 당신의 릴리스를 돌봐 및 NULL에 대한 속성을 설정합니다 (드물게는하지만 방어 프로그래밍을 고려 - - 경우에 다른 방법을 더 아래의 dealloc에서 다시 멤버 변수를 액세스 할 수있는 일이).

10.5에서 GC를 사용하도록 설정하면 더 이상 필요하지 않지만 생성 한 다른 리소스를 정리해야 할 수도 있습니다. 대신 finalize 메소드에서이를 수행 할 수 있습니다.


12
일반적으로 당신은해야 하지 접근 방법의 dealloc (또는 초기화)에서 사용합니다.
mmalc

1
성능상의 이유 (접근자가 직접 액세스보다 약간 느림)와는 별도로, 접근을 해제하거나 초기화 할 때 접근자를 사용하지 않아야하는 이유는 무엇입니까?
schwa

1
(a) 성능상의 이유는 그 자체로 특히 완벽한 이유입니다 (특히 접근자가 원자적인 경우). (b) 접근자가 가질 수있는 부작용을 피해야합니다. 후자는 클래스가 서브 클래 싱 될 수있는 경우 특히 문제가됩니다.
mmalc

3
합성 ivar을 사용 하여 최신 런타임에서 실행하는 경우 접근 제한에서 접근 자를 사용해야합니다 . 많은 최신 런타임 코드는 GC이지만 전부는 아닙니다.
루이스 Gerbarg

1
접근 자 메소드 / 속성 -init-dealloc메소드 사용 여부에 대한 확장 된 뷰는 mikeash.com/?page=pyblog/…
Johan Kool

17

이 모든 의견은 훌륭하지만 얼마 전에 출판 된 Google의 Objective-C 스타일 가이드 를 언급 한 사람이 아무도 없습니다 . 나는 그들이 매우 철저한 일을했다고 생각합니다.


7
흠, 첫 번째 예는 이미 헛소리로 가득합니다. 언어 관용구를 문서화하지 마십시오. 헤더 파일에서 이러한 종류의 주석을 찾으면 읽지 않아도됩니다.
Stephan Eggermont

5
오 내 눈 !!!!! 내가 본 것을 믿을 수 없습니다.
Eonil


13

NSWindowController와 NSViewController는 그들이 관리하는 NIB 파일의 최상위 객체를 릴리즈한다는 것을 잊지 마십시오.

NIB 파일을 수동으로로드하는 경우, NIB의 최상위 레벨 오브젝트를 완료하면 해당 오브젝트를 릴리스해야합니다.


12

초보자가 사용할 수있는 확실한 방법 중 하나는 코드에 Xcode의 자동 들여 쓰기 기능을 사용하는 것입니다. 다른 소스에서 복사 / 붙여 넣기하는 경우에도 코드를 붙여 넣은 후에는 전체 코드 블록을 선택하고 마우스 오른쪽 단추를 클릭 한 다음 해당 블록 내의 모든 항목을 다시 들여 쓰는 옵션을 선택할 수 있습니다.

Xcode는 실제로 해당 섹션을 구문 분석하고 대괄호, 루프 등을 기반으로 들여 쓰기합니다. 각 줄마다 스페이스 바 또는 탭 키를 누르는 것보다 훨씬 효율적입니다.


들여 쓰기로 Tab을 설정 한 다음 Cmd-A 및 Tab을 수행 할 수도 있습니다.
Plumenator

10

Cocoa 프로그래밍을 처음 접했을 때 이것을 간과했습니다.

NIB 파일과 관련된 메모리 관리 책임을 이해해야합니다. 로드 한 NIB 파일에서 최상위 레벨 객체를 배포 할 책임이 있습니다. 주제에 관한 Apple의 설명서 를 읽으십시오 .


6
사실이 아닙니다. 최상위 개체를 릴리스 할 책임이 있는지 여부는 상속 한 클래스와 사용중인 플랫폼에 따라 다릅니다. 무엇보다도 developer.apple.com/documentation/Cocoa/Conceptual/MemoryMgmt/…를 참조하십시오 .
mmalc

10

모든 GCC 경고를 켠 다음, 소음을 줄이기 위해 Apple 헤더에서 정기적으로 발생하는 경고를 끄십시오.

또한 Clang 정적 분석을 자주 실행하십시오. "Run Static Analyzer"빌드 설정을 통해 모든 빌드에 대해 활성화 할 수 있습니다.

단위 테스트를 작성하고 각 빌드마다 실행하십시오.


가능하면“치료 경고를 오류로 설정”하십시오. 경고가 존재하지 않도록하십시오.
Peter Hosey

2
권장되는 경고로 프로젝트를 설정하는 편리한 스크립트는 여기에서 볼 수 있습니다 : rentzsch.tumblr.com/post/237349423/hoseyifyxcodewarnings-scpt
Johan Kool

10

변수와 속성

1 / 헤더를 깨끗하게 유지하고 구현 숨기기 헤더에
인스턴스 변수를 포함시키지 마십시오. 개인 변수는 클래스 연속에 속성으로 사용됩니다. 공용 변수는 헤더에서 공용 속성으로 선언합니다. 읽기 전용이어야하는 경우 읽기 전용으로 선언하고 클래스 연속에서 읽기 쓰기로 덮어 씁니다. 기본적으로 변수를 전혀 사용하지 않고 속성 만 사용합니다.

2 / 속성에 기본이 아닌 변수 이름을 지정하십시오 (예 :


@synthesize property = property_;

이유 1 : "자기"를 잊어 버린 오류를 발견하게됩니다. 속성을 할당 할 때 이유 2 : 내 실험에서 계측기의 누출 분석기에 기본 이름으로 누수 속성을 감지하는 데 문제가 있습니다.

3 / 재산에서 직접 유지 또는 방출을 사용하지 마십시오 (또는 예외적 인 상황에서만). 당신의 dealloc에서 그들에게 nil을 할당하십시오. 유지 속성은 자체적으로 유지 / 해제를 처리하기위한 것입니다. 세터가 관찰자를 추가 또는 제거하지 않는지 여부는 알 수 없습니다. 변수는 setter 및 getter 내에서만 직접 사용해야합니다.

견해

1 / 가능하면 모든 뷰 정의를 xib에 넣으십시오 (일반적으로 동적 컨텐츠 및 레이어 설정은 예외). 시간을 절약하고 (코드를 작성하는 것보다 쉽습니다) 변경하기 쉽고 코드를 깨끗하게 유지합니다.

2 / 뷰 수를 줄여 뷰를 최적화하지 마십시오. 하위 뷰를 추가하기 위해 xib 대신 UIImageView를 코드에 작성하지 마십시오. 대신 UIImageView를 배경으로 사용하십시오. 뷰 프레임 워크는 문제없이 수백 개의 뷰를 처리 할 수 ​​있습니다.

3 / IBOutlet을 항상 유지할 필요는 없습니다. 대부분의 IBOutlet은 뷰 계층의 일부이므로 암시 적으로 유지됩니다.

4 / viewDidUnload에서 모든 IBOutlet을 해제하십시오.

5 / dealloc 메소드에서 viewDidUnload를 호출하십시오. 암시 적으로 호출되지는 않습니다.

기억

1 / Autorelease 객체를 만들 때. 릴리스 호출을 하나의 if-else 브랜치 또는 return 문 다음으로 이동하면 많은 버그가 발생합니다. 자동 릴리스 대신 릴리스는 예외적 인 상황에서만 사용해야합니다. 예를 들어 런 루프를 기다리는 동안 개체를 너무 빨리 자동 릴리스하지 않으려는 경우.

2 / Authomatic Reference Counting을 사용하더라도 유지 해제 방법이 어떻게 작동하는지 완벽하게 이해해야합니다. 수동으로 유지 릴리스를 사용하는 것이 ARC보다 복잡하지는 않습니다. 두 경우 모두 누출 및 유지주기에 관한 것입니다. 큰 프로젝트 나 복잡한 객체 계층에서 수동으로 유지 릴리스를 사용하는 것이 좋습니다.

코멘트

1 / 코드를 자동 문서화하십시오. 모든 변수 이름과 메소드 이름은 무엇을하고 있는지 알려야합니다. 코드가 올바르게 작성되면 (여기에 많은 연습이 필요함) 코드 주석이 필요하지 않습니다 (문서 주석과 동일하지 않음). 알고리즘은 복잡 할 수 있지만 코드는 항상 단순해야합니다.

2 / 때로는 의견이 필요합니다. 일반적으로 명백하지 않은 코드 동작 또는 해킹을 설명합니다. 주석을 작성해야한다고 생각되면 먼저 코드를 간단하고 주석없이 다시 작성하십시오.

들여 쓰기

1 / 들여 쓰기를 너무 많이 늘리지 마십시오. 대부분의 분석법 코드는 분석법 수준에서 들여 쓰기해야합니다. 중첩 된 블록 (있는 경우 등)은 가독성을 감소시킵니다. 중첩 된 블록이 세 개인 경우 내부 블록을 별도의 방법으로 넣어야합니다. 네 개 이상의 중첩 블록을 사용해서는 안됩니다. 대부분의 메소드 코드가 if 내부에있는 경우 if 조건을 부정하십시오 (예 :


if (self) {
   //... long initialization code ...
}

return self;

if (!self) {
   return nil;
}

//... long initialization code ...

return self;

C 코드, 주로 C 구조체 이해

Obj-C는 C 언어보다 가벼운 OOP 레이어 일뿐입니다. C의 기본 코드 구조 (열거, 구조체, 배열, 포인터 등)가 어떻게 작동하는지 이해해야합니다. 예:


view.frame = CGRectMake(view.frame.origin.x, view.frame.origin.y, view.frame.size.width, view.frame.size.height + 20);

와 같다:


CGRect frame = view.frame;
frame.size.height += 20;
view.frame = frame;

그리고 더 많은

자체 코딩 표준 문서를 관리하고 자주 업데이트하십시오. 당신의 버그에서 배우십시오. 버그가 발생한 이유를 이해하고 코딩 표준을 사용하여 버그를 피하십시오.

우리의 코딩 표준은 현재 약 20 페이지, Java 코딩 표준, Google Obj-C / C ++ 표준 및 자체 추가 기능이 혼합되어 있습니다. 올바른 장소에 코드를 문서화하고 표준 표준 들여 쓰기, 공백 및 빈 줄을 사용하십시오.


9

기능적 입니다.

Objective-C는 객체 지향 언어이지만 Cocoa 프레임 워크는 기능적 스타일을 인식하며 많은 경우 기능적 스타일로 설계되었습니다.

  1. 가변성의 분리가 있습니다. 불변 클래스를 기본으로 사용하고 가변 객체를 보조로 사용하십시오 . 예를 들어 NSArray를 주로 사용하고 필요할 때만 NSMutableArray를 사용하십시오.

  2. 순수한 기능이 있습니다. 그리 많지 않은 많은 API를 구입하면 순수한 기능처럼 설계됩니다. CGRectMake()또는 과 같은 기능을 살펴보십시오 CGAffineTransformMake(). 분명히 포인터 형식이 더 효율적으로 보입니다. 그러나 포인터를 사용한 간접적 인 주장은 부작용이 없습니다. 가능한 한 순수하게 구조를 설계하십시오. 짝수 상태 객체를 분리하십시오. 다른 객체에 값을 전달할 때 -copy대신 사용하십시오 -retain. 공유 상태는 다른 객체의 가치에 대한 돌연변이에 자동으로 영향을 줄 수 있기 때문입니다. 따라서 부작용이 없어야합니다. object에서 external의 값이 있으면 복사하십시오. 따라서 가능한 한 공유 상태를 설계하는 것도 중요합니다.

그러나 불순한 기능을 사용하는 것을 두려워하지 마십시오.

  1. 게으른 평가가 있습니다. -[UIViewController view]재산 과 같은 것을보십시오 . 객체가 생성 될 때 뷰가 생성되지 않습니다. 발신자 view가 처음 속성을 읽을 때 생성됩니다 . UIImage실제로 그려 질 때까지로드되지 않습니다. 이 디자인과 같은 많은 구현이 있습니다. 이러한 종류의 디자인은 리소스 관리에 매우 도움이되지만 지연 평가의 개념을 모르면 해당 동작을 이해하기가 쉽지 않습니다.

  2. 폐쇄가 있습니다. C 블록을 가능한 많이 사용하십시오. 이것은 당신의 인생을 크게 단순화시킬 것입니다. 그러나 사용하기 전에 블록 메모리 관리에 대해 한 번 더 읽으십시오.

  3. 반자동 GC가 있습니다. NSAutoreleasePool. -autorelease기본을 사용하십시오 . -retain/-release필요할 때 수동 보조를 사용하십시오 . (예 : 메모리 최적화, 명시 적 리소스 삭제)


2
3) 반대 방법을 제안합니다. 가능하면 수동 유지 / 해제를 사용하십시오! 이 코드가 어떻게 사용 될지 누가 알겠는가-타이트한 루프에서 사용될 경우 불필요하게 메모리 사용량이 늘어날 수 있습니다.
Eiko

@Eiko 그것은 단지 조기 최적화 일 뿐이며 일반적인 지침이 될 수 없습니다.
Eonil

1
특히 모델 클래스에서 작업 할 때 디자인이 더 중요하다고 생각합니다. 나는 부작용으로 기억을 키우는 것을 고려하고 있는데, 그것이 자주 나타나고 싶지는 않습니다. 더 나쁜 것은, 내 코드를 사용하는 다른 개발자는 고가의 호출을 자동 릴리스 풀로 래핑 할 수밖에 없습니다 (가능한 경우 모든 개체가 다른 라이브러리 코드로 전송 될 수 있음). 이러한 문제는 나중에 진단하기는 어렵지만 처음에는 피하는 것이 좋습니다. 전달 된 객체를 복사 / 자동 해제하면 예상보다 훨씬 큰 객체가 손실 될 수 있습니다. 그래도 GUI 코드가 더 편합니다.
에이코

@Eiko 나는 autorelease일반적으로 메모리를 더 오래 보유 할 것이며, 수동 retain/release은이 경우 메모리 소비를 줄일 수 있다고 동의합니다 . 그러나 특별한 경우 최적화에 대한 지침이어야합니다 (항상 기분이 좋습니다!) . 조기 최적화를 연습 으로 일반화하는 이유는 아닙니다 . 사실, 당신의 제안은 저와 반대가 아닙니다. 나는 그것을 정말로 필요한 경우로 언급했다 :)
Eonil
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.