programing

왜 아이바를 사용합니까?

telecom 2023. 5. 20. 10:06
반응형

왜 아이바를 사용합니까?

는 보통 모든 ivar가 속성이어야 하는가와 같은 질문을 반대로 하는 것을 봅니다.(그리고 저는 이 Q에 대한 bbum의 대답이 좋습니다.)

나는 내 코드에서 거의 독점적으로 속성을 사용합니다.하지만 가끔 저는 iOS에서 오랫동안 개발해온 전통적인 게임 프로그래머인 계약자와 함께 일합니다.그는 거의 어떤 속성도 선언하지 않고 ivar에 의존하는 코드를 작성합니다.그가 이렇게 하는 이유는 1.) 목표 C 2.0(2007년 10월 및 2.)까지 속성이 항상 존재하지 않았기 때문에 게터/세터를 거치지 않음으로써 얻는 최소한의 성능 향상을 위해 익숙하기 때문이라고 생각합니다.

그가 유출되지 않는 코드를 작성하는 동안, 나는 여전히 그가 ivar보다 속성을 사용하는 것을 선호합니다.우리는 그것에 대해 이야기했고 그는 우리가 KVO를 사용하지 않았고 그는 메모리 문제를 처리한 경험이 있기 때문에 자산을 사용할 이유가 거의 없다고 생각합니다.

제 질문은 더...경험이 있든 없든 ivar 기간을 사용하려는 이유는 무엇입니까?아이바를 사용하는 것이 정당화될 정도로 성능 차이가 정말로 그렇게 큰가요?

또한 설명을 위해 필요에 따라 세터와 게터를 재정의하고 게터/세터 내부의 해당 속성과 관련된 아이바를 사용합니다.하지만, 게터/세터 또는 init 밖에서는 항상 다음을 사용합니다.self.myProperty통사론


편집 1

좋은 답변에 감사드립니다.제가 틀린 것처럼 보이는 것 중 하나를 말씀드리고 싶은 것은 아이바를 사용하면 캡슐화가 되지만 속성을 사용하면 캡슐화가 된다는 것입니다.클래스 연속에서 속성을 정의합니다.이것은 외부 사람들로부터 재산을 숨길 것입니다.또한 다음과 같이 인터페이스에서 속성을 읽기 전용으로 선언하고 구현에서 읽기 쓰기로 재정의할 수 있습니다.

// readonly for outsiders
@property (nonatomic, copy, readonly) NSString * name;

강의를 계속합니다.

// readwrite within this file
@property (nonatomic, copy) NSString * name;

완전히 "비공개"하려면 클래스 계속에서 선언해야 합니다.

캡슐화

만약 아이바가 비공개라면, 프로그램의 다른 부분들은 그것을 쉽게 얻을 수 없습니다.신고된 속성으로 영리한 사람들은 접근자를 통해 꽤 쉽게 접근하고 변형할 수 있습니다.

성능

예, 이것은 경우에 따라 달라질 수 있습니다.일부 프로그램에는 프로그램의 특정 부분에서 개체 메시징을 사용할 수 없는 제약 조건이 있습니다(실시간으로 생각).다른 경우에는 속도를 위해 직접 액세스할 수 있습니다.다른 경우에는 objc 메시징이 최적화 방화벽 역할을 하기 때문입니다.마지막으로, 참조 카운트 작업을 줄이고 최대 메모리 사용량을 최소화할 수 있습니다(올바르게 수행된 경우).

중요하지 않은 유형

예:만약 당신이 C++ 타입을 가지고 있다면, 직접적인 접근은 때때로 더 나은 접근법입니다.형식을 복사할 수 없거나 복사하기에 사소한 것이 아닐 수 있습니다.

멀티스레딩

당신의 많은 아이바들은 공의존적입니다.멀티스레드 컨텍스트에서 데이터 무결성을 보장해야 합니다.따라서 중요한 섹션에서 여러 구성원에게 직접 액세스할 수 있습니다.상호의존적인 데이터를 위한 접근자를 고수하는 경우, 잠금 장치는 일반적으로 재입력되어야 하며 종종 더 많은 정보를 수집하게 될 것입니다(때로는 훨씬 더 많은 정보를 수집하게 될 것입니다.

프로그램 정확성

하위 클래스는 모든 메서드를 재정의할 수 있으므로 결국 인터페이스에 쓰는 것과 상태를 적절하게 관리하는 것 사이에 의미론적 차이가 있을 수 있습니다.프로그램 수정을 위한 직접 액세스는 특히 부분적으로 구성된 상태에서 일반적입니다. 이니셜라이저와dealloc직접 액세스를 사용하는 것이 가장 좋습니다.당신은 또한 접근자, 편의 건설자의 구현에서 이것이 공통적이라는 것을 발견할 수 있습니다.copy,mutableCopy및 아카이빙/최소화 구현이 필요로 합니다.

또한 모든 이 공개 읽기 쓰기 액세스 방식에서 구현 세부 정보/데이터를 잘 숨기는 방식으로 이동함에 따라 빈도가 높아집니다.때로는 올바른 작업을 수행하기 위해 하위 클래스의 오버라이드가 초래할 수 있는 부작용을 올바르게 처리해야 합니다.

이진 크기

기본적으로 모든 항목을 읽기 쓰기로 선언하면 프로그램 실행을 잠시 고려할 때 일반적으로 필요하지 않은 많은 액세스 또는 메서드가 생성됩니다.따라서 프로그램에 지방을 추가하고 로드 시간도 늘릴 수 있습니다.

복잡성 최소화

어떤 경우에는, 한 방법으로 쓰여지고 다른 방법으로 읽히는 사설 풍선과 같은 간단한 변수를 위해 +type+유지보수를 추가하는 것이 완전히 불필요합니다.


그렇다고 해서 속성이나 액세스 도구를 사용하는 것이 나쁘다는 것은 아닙니다. 각각 중요한 이점과 제한이 있습니다.많은 OO 언어 및 설계 접근 방식과 마찬가지로 ObjC에서 적절한 가시성을 갖춘 액세스 권한도 선호해야 합니다.당신이 일탈해야 할 때가 있을 것입니다.것이 가장 합니다(예: ivar로 합니다).@private).


편집 1:

우리 대부분은 숨겨진 접근자를 동적으로 호출하는 방법을 기억하고 있습니다.한편, 우리 대부분은 보이지 않는 (KVC를 넘어) 아이바에 제대로 접근하는 방법을 기억하지 못했습니다.클래스를 계속하면 도움이 되지만 취약성이 발생합니다.

이 해결 방법은 분명합니다.

if ([obj respondsToSelector:(@selector(setName:)])
  [(id)obj setName:@"Al Paca"];

이제 KVC 없이 아이바만 사용해 보십시오.

저에게 그것은 보통 공연입니다.객체의 아이바에 액세스하는 것은 이러한 구조체를 포함하는 메모리에 대한 포인터를 사용하여 C의 구조체 멤버에 액세스하는 것만큼 빠릅니다.사실 Objective-C 객체는 기본적으로 동적으로 할당된 메모리에 위치한 C 구조입니다.이것은 일반적으로 코드가 얻을 수 있는 한 빠릅니다. 손으로 최적화된 어셈블리 코드도 그보다 빠를 수 없습니다.

게터/설정을 통해 아이바에 액세스하는 것은 목표-C 메서드 호출을 포함하는데, 이는 "일반" C 함수 호출보다 훨씬 느리고(최소 3-4배), 심지어 일반 C 함수 호출도 구조 구성원에 액세스하는 것보다 이미 몇 배 더 느립니다. 속의속게따컴성에라파러세의터/▁c게▁the▁depending▁function▁involve▁another▁to▁call다속▁the C 함수에 대한 또 다른 C 함수 호출을 포함할 수 있습니다.objc_getProperty/objc_setProperty이들이 해야 할 것처럼retain/copy/autorelease필요에 따라 물체를 조정하고 필요한 경우 원자 특성에 대한 스핀 잠금을 추가로 수행합니다.이것은 쉽게 매우 비싸질 수 있고 50% 더 느리다는 것을 말하는 것이 아닙니다.

시도해 보겠습니다.

CFAbsoluteTime cft;
unsigned const kRuns = 1000 * 1000 * 1000;

cft = CFAbsoluteTimeGetCurrent();
for (unsigned i = 0; i < kRuns; i++) {
    testIVar = i;
}
cft = CFAbsoluteTimeGetCurrent() - cft;
NSLog(@"1: %.1f picoseconds/run", (cft * 10000000000.0) / kRuns);

cft = CFAbsoluteTimeGetCurrent();
for (unsigned i = 0; i < kRuns; i++) {
    [self setTestIVar:i];
}
cft = CFAbsoluteTimeGetCurrent() - cft;
NSLog(@"2: %.1f picoseconds/run", (cft * 10000000000.0) / kRuns);

출력:

1: 23.0 picoseconds/run
2: 98.4 picoseconds/run

이것은 4.28배 더 느리고 이것은 원자가 아닌 원시적인 int였고, 거의 대부분의 다른 경우들은 훨씬 더 심각합니다. (원자를 시도해 보세요.NSString * 느리다는 할 수 을 사용하는 는) 저하를 할 수 없는 .따라서 각 ivar 액세스 속도가 가능한 것보다 4-5배 느리다는 사실을 감수할 수 있다면, 속성을 사용하는 것은 괜찮지만(최소한 성능 면에서는) 이러한 성능 저하를 완전히 수용할 수 없는 상황이 많이 발생합니다.

2015-10-20 업데이트

어떤 사람들은 이것이 실제 세계의 문제가 아니며, 위의 코드는 순수하게 합성된 것이며 실제 응용 프로그램에서는 결코 그것을 알아차리지 못할 것이라고 주장합니다.좋아요, 그럼, 실제 세계의 샘플을 시도해 보겠습니다.

아래 코드는 다음을 정의합니다.Account에는 이름이름)을 설명하는 속성이 .NSString *(), 성()enum(), 나이()unsigned소유자의 ) 및 잔액(int64_t). 에는 )가 init과 a 방과acompare:방법.compare:방법은 다음과 같이 정의됩니다. 남성보다 여성 주문, 이름이 알파벳 순으로, 오래되기 전의 젊은 주문, 낮은 순서에서 높은 순서로 균형 주문.

계정 클래스는 두 .AccountA그리고.AccountB이러한 구현을 살펴보면 다음과 같은 한 가지 예외를 제외하고는 거의 완전히 동일하다는 것을 알 수 있습니다.compare:방법. AccountA객체는 메서드(게터)로 자체 속성에 액세스하는 동안AccountB개체는 ivar를 통해 자체 속성에 액세스합니다.그것이 정말 유일한 차이점입니다!둘 다 다른 개체의 속성에 액세스하여 비교합니다(아이바를 통해 액세스하는 것은 안전하지 않습니다!).다른 개체가 하위 클래스이고 게터를 재정의한 경우에는 어떻게 됩니까?).또한 ivar로 자신의 속성에 액세스해도 캡슐화가 중단되지 않습니다(ivar는 여전히 공개되지 않음).

테스트 설정은 매우 간단합니다. 1 Mio 랜덤 계정을 만들고, 이를 배열에 추가한 다음 배열을 정렬합니다.바로 그겁니다. 두 의 배열이 , 는 물론어, 개가이레, 는나하입니다.AccountA에 대한 objects와 .AccountB개체와 두 배열 모두 동일한 계정(동일한 데이터 원본)으로 채워집니다.배열을 정렬하는 데 걸리는 시간을 측정합니다.

다음은 제가 어제 몇 차례 실행한 결과입니다.

runTime 1: 4.827070, 5.002070, 5.014527, 5.019014, 5.123039
runTime 2: 3.835088, 3.804666, 3.792654, 3.796857, 3.871076

시피배정의 을 정렬하는 것.AccountB객체는 항상 배열을 정렬하는 것보다 훨씬 빠릅니다.AccountA물건들.

런타임 차이가 최대 1.32초라고 주장하는 사람은 UI 프로그래밍을 절대 하지 않는 것이 좋습니다.예를 들어 큰 테이블의 정렬 순서를 변경하려는 경우 이러한 시간 차이는 사용자에게 큰 차이(허용 가능한 UI와 느린 UI의 차이)를 만듭니다.

또한 이 경우 샘플 코드가 여기서 수행되는 유일한 실제 작업이지만, 얼마나 자주 당신의 코드가 복잡한 시계 장치의 작은 기어에 불과합니까?만약 모든 기어가 이와 같이 전체 과정의 속도를 늦춘다면, 그것은 결국 전체 시계의 속도에 어떤 의미가 있을까요?특히 한 작업 단계가 다른 작업 단계의 출력에 의존하는 경우, 이는 모든 비효율성이 요약된다는 것을 의미합니다.대부분의 비효율성은 그 자체로 문제가 되는 것이 아니라 전체 프로세스에 문제가 되는 것은 순전히 그들의 합계입니다.프로파일러가 중요한 핫 스팟을 찾는 것이기 때문에 이러한 문제는 프로파일러가 쉽게 보여줄 수 있는 것이 아닙니다. 하지만 이러한 비효율성은 그 자체로 핫 스팟이 아닙니다.CPU 시간은 일반적으로 CPU 간에 분산되어 있지만 각 CPU 시간은 극히 일부에 불과하기 때문에 이를 최적화하는 데는 시간 낭비가 심한 것으로 보입니다.그리고 그 중 하나만 최적화해도 전혀 도움이 되지 않고, 모든 것을 최적화해도 극적으로 도움이 될 수 있다는 것은 사실입니다.

CPU 시간의 측면에서 생각하지 않더라도 CPU 시간을 낭비하는 것은 전적으로 용인할 수 있다고 생각하기 때문에 결국 "공짜"이므로 전력 소비로 인한 서버 호스팅 비용은 어떻습니까?모바일 기기의 배터리 런타임은 어떻습니까?만약 당신이 동일한 모바일 앱을 두 번 쓴다면, 한 번은 모든 클래스가 게터로만 자신의 속성에 액세스하는 버전이고 한 번은 모든 클래스가 아이바로만 액세스하는 버전입니다. 첫 번째 앱을 지속적으로 사용하는 것은 두 번째 앱을 사용하는 것보다 훨씬 더 빨리 배터리를 소모할 것입니다.기능적으로 동등하고 사용자에게 두 번째 것은 아마도 조금 더 빠르게 느껴질 것입니다.

이제 여기 당신의 코드가 있습니다.main.m하며 완전한 위해 시.):file(파일 이름: ARC 파일 이름:

#import <Foundation/Foundation.h>

typedef NS_ENUM(int, Gender) {
    GenderMale,
    GenderFemale
};


@interface AccountA : NSObject
    @property (nonatomic) unsigned age;
    @property (nonatomic) Gender gender;
    @property (nonatomic) int64_t balance;
    @property (nonatomic,nonnull,copy) NSString * name;

    - (NSComparisonResult)compare:(nonnull AccountA *const)account;

    - (nonnull instancetype)initWithName:(nonnull NSString *const)name
        age:(const unsigned)age gender:(const Gender)gender
        balance:(const int64_t)balance;
@end


@interface AccountB : NSObject
    @property (nonatomic) unsigned age;
    @property (nonatomic) Gender gender;
    @property (nonatomic) int64_t balance;
    @property (nonatomic,nonnull,copy) NSString * name;

    - (NSComparisonResult)compare:(nonnull AccountB *const)account;

    - (nonnull instancetype)initWithName:(nonnull NSString *const)name
        age:(const unsigned)age gender:(const Gender)gender
        balance:(const int64_t)balance;
@end


static
NSMutableArray * allAcocuntsA;

static
NSMutableArray * allAccountsB;

static
int64_t getRandom ( const uint64_t min, const uint64_t max ) {
    assert(min <= max);
    uint64_t rnd = arc4random(); // arc4random() returns a 32 bit value only
    rnd = (rnd << 32) | arc4random();
    rnd = rnd % ((max + 1) - min); // Trim it to range
    return (rnd + min); // Lift it up to min value
}

static
void createAccounts ( const NSUInteger ammount ) {
    NSArray *const maleNames = @[
        @"Noah", @"Liam", @"Mason", @"Jacob", @"William",
        @"Ethan", @"Michael", @"Alexander", @"James", @"Daniel"
    ];
    NSArray *const femaleNames = @[
        @"Emma", @"Olivia", @"Sophia", @"Isabella", @"Ava",
        @"Mia", @"Emily", @"Abigail", @"Madison", @"Charlotte"
    ];
    const NSUInteger nameCount = maleNames.count;
    assert(maleNames.count == femaleNames.count); // Better be safe than sorry

    allAcocuntsA = [NSMutableArray arrayWithCapacity:ammount];
    allAccountsB = [NSMutableArray arrayWithCapacity:ammount];

    for (uint64_t i = 0; i < ammount; i++) {
        const Gender g = (getRandom(0, 1) == 0 ? GenderMale : GenderFemale);
        const unsigned age = (unsigned)getRandom(18, 120);
        const int64_t balance = (int64_t)getRandom(0, 200000000) - 100000000;

        NSArray *const nameArray = (g == GenderMale ? maleNames : femaleNames);
        const NSUInteger nameIndex = (NSUInteger)getRandom(0, nameCount - 1);
        NSString *const name = nameArray[nameIndex];

        AccountA *const accountA = [[AccountA alloc]
            initWithName:name age:age gender:g balance:balance
        ];
        AccountB *const accountB = [[AccountB alloc]
            initWithName:name age:age gender:g balance:balance
        ];

        [allAcocuntsA addObject:accountA];
        [allAccountsB addObject:accountB];
    }
}


int main(int argc, const char * argv[]) {
    @autoreleasepool {
        @autoreleasepool {
            NSUInteger ammount = 1000000; // 1 Million;
            if (argc > 1) {
                unsigned long long temp = 0;
                if (1 == sscanf(argv[1], "%llu", &temp)) {
                    // NSUIntegerMax may just be UINT32_MAX!
                    ammount = (NSUInteger)MIN(temp, NSUIntegerMax);
                }
            }
            createAccounts(ammount);
        }

        // Sort A and take time
        const CFAbsoluteTime startTime1 = CFAbsoluteTimeGetCurrent();
        @autoreleasepool {
            [allAcocuntsA sortedArrayUsingSelector:@selector(compare:)];
        }
        const CFAbsoluteTime runTime1 = CFAbsoluteTimeGetCurrent() - startTime1;

        // Sort B and take time
        const CFAbsoluteTime startTime2 = CFAbsoluteTimeGetCurrent();
        @autoreleasepool {
            [allAccountsB sortedArrayUsingSelector:@selector(compare:)];
        }
        const CFAbsoluteTime runTime2 = CFAbsoluteTimeGetCurrent() - startTime2;

        NSLog(@"runTime 1: %f", runTime1);
        NSLog(@"runTime 2: %f", runTime2);
    }
    return 0;
}



@implementation AccountA
    - (NSComparisonResult)compare:(nonnull AccountA *const)account {
        // Sort by gender first! Females prior to males.
        if (self.gender != account.gender) {
            if (self.gender == GenderFemale) return NSOrderedAscending;
            return NSOrderedDescending;
        }

        // Otherwise sort by name
        if (![self.name isEqualToString:account.name]) {
            return [self.name compare:account.name];
        }

        // Otherwise sort by age, young to old
        if (self.age != account.age) {
            if (self.age < account.age) return NSOrderedAscending;
            return NSOrderedDescending;
        }

        // Last ressort, sort by balance, low to high
        if (self.balance != account.balance) {
            if (self.balance < account.balance) return NSOrderedAscending;
            return NSOrderedDescending;
        }

        // If we get here, the are really equal!
        return NSOrderedSame;
    }

    - (nonnull instancetype)initWithName:(nonnull NSString *const)name
        age:(const unsigned)age gender:(const Gender)gender
        balance:(const int64_t)balance
    {
        self = [super init];
        assert(self); // We promissed to never return nil!

        _age = age;
        _gender = gender;
        _balance = balance;
        _name = [name copy];

        return self;
    }
@end


@implementation AccountB
    - (NSComparisonResult)compare:(nonnull AccountA *const)account {
        // Sort by gender first! Females prior to males.
        if (_gender != account.gender) {
            if (_gender == GenderFemale) return NSOrderedAscending;
            return NSOrderedDescending;
        }

        // Otherwise sort by name
        if (![_name isEqualToString:account.name]) {
            return [_name compare:account.name];
        }

        // Otherwise sort by age, young to old
        if (_age != account.age) {
            if (_age < account.age) return NSOrderedAscending;
            return NSOrderedDescending;
        }

        // Last ressort, sort by balance, low to high
        if (_balance != account.balance) {
            if (_balance < account.balance) return NSOrderedAscending;
            return NSOrderedDescending;
        }

        // If we get here, the are really equal!
        return NSOrderedSame;
    }

    - (nonnull instancetype)initWithName:(nonnull NSString *const)name
        age:(const unsigned)age gender:(const Gender)gender
        balance:(const int64_t)balance
    {
        self = [super init];
        assert(self); // We promissed to never return nil!

        _age = age;
        _gender = gender;
        _balance = balance;
        _name = [name copy];

        return self;
    }
@end

의미론

  • 무엇을@property할 수 것을 할 수 : ivar가 할수것표수있현습니다할을는다없▁can있습다.nonatomic그리고.copy.
  • 그 를 표현할 수 있나요?@property할 수 없음:
    • @protected하위 클래스에는 공개, 외부에는 비공개.
    • @package64비트의 프레임워크에서는 퍼블릭, 외부에서는 프라이빗.과 동일@public32비트로.Apple의 64비트 클래스인스턴스 변수 액세스 제어를 참조하십시오.
    • 를 들어과 같습니다: 예를들어객, 한참조배다같열은습.id __strong *_objs.

성능

짧은 이야기: 아이바가 더 빠르지만 대부분의 용도에는 문제가 되지 않습니다. nonatomic속성은 잠금을 사용하지 않지만 다이렉트바는 접근자 호출을 건너뛰기 때문에 더 빠릅니다.자세한 내용은 lists.apple.com 의 다음 이메일을 참조하십시오.

Subject: Re: when do you use properties vs. ivars?
From: John McCall <email@hidden>
Date: Sun, 17 Mar 2013 15:10:46 -0700

속성은 여러 가지 방식으로 성능에 영향을 미칩니다.

  1. 이미 설명했듯이 로드/스토어를 수행하기 위해 메시지를 보내는 것은 로드/스토어를 인라인으로 수행하는 것보다 느립니다.

  2. 로드/스토어를 수행하기 위해 메시지를 보내는 것은 i-cache에 보관해야 하는 코드이기도 합니다. getter/setter가 로드/스토어 외에 추가 명령어를 0개 추가하더라도 메시지 전송을 설정하고 결과를 처리하기 위해 호출자에게 6개의 확실한 추가 명령어가 있을 것입니다.

  3. 메시지를 보내면 해당 선택기의 항목이 메서드 캐시에 유지되고 메모리는 일반적으로 d-캐시에 고정됩니다.이는 시작 시간을 늘리고, 앱의 정적 메모리 사용량을 증가시키며, 컨텍스트 전환을 더욱 힘들게 합니다.메서드 캐시는 개체의 동적 클래스에만 한정되므로, 이 문제는 개체에 KVO를 더 많이 사용할수록 증가합니다.

  4. 메시지를 보내면 함수의 모든 값이 강제로 스택으로 유출됩니다(또는 다른 시간에 유출됨을 의미하는 수신자 저장 레지스터에 유지됨).

  5. 메시지를 보내는 것은 임의의 부작용을 가질있으며 따라서

    • 컴파일러가 로컬이 아닌 메모리에 대한 모든 가정을 재설정하도록 강제합니다.
    • 들어 올리거나 가라앉거나, 다시 정렬하거나, 병합하거나, 제거할 수 없습니다.

  6. ARC에서 메시지 전송 결과는 +0 반환 시에도 수신자 또는 발신자에 의해 항상 유지됩니다. 메서드가 결과를 유지/자동으로 해제하지 않더라도 발신자는 이를 알지 못하며 결과가 자동으로 해제되지 않도록 조치를 취해야 합니다.메시지 전송은 정적으로 분석할 수 없으므로 이 문제를 제거할 수 없습니다.

  7. ARC에서, 세터 방법은 일반적으로 +0에서 인수를 취하기 때문에, 위에서 논의한 바와 같이, ARC가 ivar로 해당 객체의 보유를 "전송"할 방법이 없기 때문에, 값은 일반적으로 유지/해제되어야 합니다.

물론 이 모든 것이 항상 나쁘다는 것을 의미하는 것은 아닙니다. 속성을 사용해야 하는 많은 좋은 이유가 있습니다.다른 많은 언어 기능과 마찬가지로 무료가 아닙니다.


존, 존.

가장 중요한 이유는 정보 숨기기의 OOP 개념입니다.속성을 통해 모든 것을 노출하여 외부 개체가 다른 개체의 내부를 엿보게 하면 이러한 내부를 사용하여 구현을 복잡하게 변경할 수 있습니다.

"최소 성능" 향상은 빠르게 요약되어 문제가 될 수 있습니다.저는 경험을 통해 알고 있습니다. 저는 iDevices를 한계에 이르게 하는 앱을 개발하고 있기 때문에 불필요한 메서드 호출을 피해야 합니다(물론 가능한 한 합리적으로 가능한 경우에만).이. 몇이 이 목 위 표 메 또 호 드 소 의 출 수 를 보 어 눈 있 기 게 만 다 렵 니 습 피 고 구 하 도 을 문 때 해 트 들 에 우 문 기 리 는 한 에 지 첫 를 기 원 하 ion ▁to ▁since ▁the ▁many 예를 들어, 표현식을 수행하는 메소드 호출의 수.self.image.size.width방아쇠?대조적으로, 당신은 즉시 알 수 있습니다.[[self image] size].width.

또한, 올바른 아이바 명명으로 속성 없이 KVO가 가능합니다(IIRC, 저는 KVO 전문가가 아닙니다).

속성 대 인스턴스 변수는 트레이드오프이며, 결국 선택은 애플리케이션에 달려 있습니다.

캡슐화/정보 숨기기 이것은 설계 관점에서 볼 때 좋은 것(TM)이며, 좁은 인터페이스와 최소한의 연결은 소프트웨어를 유지 관리하고 이해할 수 있게 해줍니다.Obj-C에서는 어떤 것도 숨기는 것이 매우 어렵지만, 구현에서 선언된 인스턴스 변수는 당신이 얻을 수 있는 것만큼 가깝습니다.

성능 "조기 최적화"는 나쁜 일이지만, 단지 할 수 있다는 이유만으로 나쁜 성능의 코드를 작성하는 것은 적어도 나쁜 일입니다.메소드 호출이 로드나 스토어보다 더 비싸다는 것에 반대하기는 어려우며 계산 집약적인 코드에서는 비용이 곧 추가됩니다.

C#과 같은 속성이 있는 정적 언어에서 세터/게터 호출은 컴파일러에 의해 최적화될 수 있습니다.그러나 Obj-C는 동적이며 이러한 호출을 제거하는 것이 훨씬 어렵습니다.

추상화 Obj-C의 인스턴스 변수에 대한 인수는 전통적으로 메모리 관리였습니다.MRC 인스턴스 변수를 사용할 경우 유지/해제/자동 해제 호출이 코드 전체에 분산되어야 합니다. 속성은 MRC 코드를 한 곳에 유지(합성 여부와 상관없이)합니다. 즉, 추상화 원리는 좋은 것(TM)입니다. 그러나 GC 또는 ARC를 사용하면 이 인수는 사라집니다.따라서 메모리 관리를 위한 추상화는 더 이상 인스턴스 변수에 대한 인수가 아닙니다.

속성은 변수를 다른 클래스에 표시합니다.작성 중인 클래스에만 관련된 변수가 필요한 경우 인스턴스 변수를 사용합니다.여기 작은 예가 있습니다. RSS와 유사한 주기를 여러 대리자 메소드 등을 통해 구문 분석하기 위한 XML 클래스입니다.NSMutableString 인스턴스를 사용하여 각 구문 분석 경로의 결과를 저장하는 것이 실용적입니다.외부 클래스가 해당 문자열에 액세스하거나 조작해야 할 이유가 없습니다.따라서 헤더나 개인적으로 선언하고 클래스 전체에서 액세스할 수 있습니다.self.mutableString을 사용하여 getter/setters를 호출하여 메모리 문제가 없는지 확인하는 경우에만 속성을 설정하는 것이 유용할 수 있습니다.

이전 버전과의 호환성이 저에게 한 요인이었습니다.요구 사항의 일부로 Mac OS X 10.3에서 작동해야 하는 소프트웨어와 프린터 드라이버를 개발하는 중이었기 때문에 Objective-C 2.0 기능을 사용할 수 없었습니다.당신의 질문이 iOS를 목표로 하는 것처럼 보였지만, 저는 여전히 속성을 사용하지 않는 이유를 공유해야 한다고 생각했습니다.

언급URL : https://stackoverflow.com/questions/9086736/why-would-you-use-an-ivar

반응형