Objective-C의 문법 설탕 @{} 도대체 무엇인지 상세히 설명합니다.

최근 기술군에서 한 친구가 문제를 제기했다. 왜 아래 코드가 인쇄된 결과가 다른가?

NSMutableDictionary *mDic1 = [NSMutableDictionary dictionaryWithDictionary:@{@"a":@1, @"a":@2}];
//'a': 1
NSMutableDictionary *mDic2 = [NSMutableDictionary dictionary];
[mDic2 setObject:@(1) forKey:@"a"];
[mDic2 setObject:@(2) forKey:@"a"];
 //'a': 2
이에 대해 필자는 약간의 연구를 하였는데, 여기에서 나는 이유를 논술하고 실험 절차를 약술하였다

@{} 도대체 뭐예요?


이 데이터의 결과를 초래할 가능성 중 하나는

@{@"a":@1, @"a":@2}
그 자체가 키가 a이고 값이 1인 사전이다.
테스트 코드는 다음과 같습니다.

NSDictionary *dic = @{@"a":@1, @"a":@2};
NSLog(@"%@", dic);
그 자체가 키가 a이고 값이 1인 사전이라는 것을 발견했다.
그럼 @{}는 도대체 무엇일까요?사실 어떻게 조작했죠?그의 분배 방식은 도대체 무엇입니까?

실험 절차


인터넷에서 찾은 NSDictionary의 위조 코드를 기반으로 하여, 어쨌든 우리가 사전을 만들 때, 그 코드는 최종적으로 실행될 것이다

- (id)initWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt
그러면 만약에 우리가 훅을 통해 이 방법을 감청한다면 초기화할 때 전송된objects와keys가 도대체 무엇인지 알 수 있습니다.하지만 안타깝게도 훅이 살지 않았다.
설마 내 방법에 문제가 있는 건 아니겠지?
필자는 @{}를 사용할 때 이 절차를 전혀 실행하지 않는 것을 발견했다.다른 건가요?
그리고 필자는 기호 단점 +[NSDictionary dictionaryWithObjects:forKeys:count:] 을 추가함으로써 우리가 값을 부여할 때 기호 단점이 연결된다는 것을 발견했다.
우리는 @{} 사전을 만들 때 이 방법을 사용합니까?해볼만해?
hook을 통해 사전의 이 방법을 사용했습니다. 우리는 분류에서 받아들일 것입니다. 시스템이 호출될 때 단점을 걸어 둡니다.

+ (id)xxx_dictionaryWithObjects:(const id [])objects forKeys:(const id <NSCopying> [])keys count:(NSUInteger)cnt{
 for (NSUInteger i = 0; i < cnt; i++) {
 id key = keys[i];
 id obj = objects[i];
 NSLog(@"key = %@", key);
 NSLog(@"obj = %@", obj);
 }
 return [[NSDictionary class] xxx_dictionaryWithObjects:objects forKeys:keys count:cnt];
}
2021-03-30 17:13:40.971674+0800 suspenseRoad[28886:413231] key = a
2021-03-30 17:13:40.971743+0800 suspenseRoad[28886:413231] obj = 1
2021-03-30 17:13:40.971814+0800 suspenseRoad[28886:413231] key = a
2021-03-30 17:13:40.971896+0800 suspenseRoad[28886:413231] obj = 2
다음 결과를 기다립니다. 설정을 초기화할 때 전송된 값은 코드에 들어갔지만 결과는 없습니다.
계속 탐구하는 방법 +[NSDictionary dictionaryWithObjects:forKeys:count:]

+ (id)dictionaryWithDictionary:(NSDictionary *)dict
{
 size_t count = [dict count];
 id *objects = NULL;
 id *keys = NULL;

 if (count > 0) {
 objects = malloc(sizeof(id) * count);
 if (UNLIKELY(objects == NULL)) {
  return NULL;
 }
 keys = malloc(sizeof(id) * count);
 if (UNLIKELY(keys == NULL)) {
  free(objects);
  return NULL;
 }
 }
 
 [dict getObjects:objects andKeys:keys];
 id obj = [[self alloc] initWithObjects:objects forKeys:keys count:count];

 if (objects != NULL) {
 free(objects);
 }
 if (keys != NULL) {
 free(keys);
 }

 return [obj autorelease];
}


추측


이때 데이터를 바꿀 수 있는 곳은 두 곳뿐이다.

 [dict getObjects:objects andKeys:keys];
// 
 id obj = [[self alloc] initWithObjects:objects forKeys:keys count:count];
상술한 두 가지 문제 때문에 필자는 모두 단도할 방법이 없다. 만약에 독자가 큰 방법이 있다면 독자가 크게 시도하기를 바란다.필자는 두 가지 방법의 코드에 근거하여 자신의 대담한 추측을 진행하였다. 즉, 멋대로 추측한 것이다.
안타깝게도 고치지 못했다.코드에서objects와keys에 대한 선택을 반복할 수 있는 어떤 방법도 보지 못했다.

CFBasicHashAddValue 및 CFBasicHashSetValue


초기화 방법의 문제가 아닌 것 같다. 그리고 필자는 사전의 set Object:forKey의 실현을 비교했다.다음과 같은 두 가지 방법을 찾습니다.

CF_PRIVATE Boolean CFBasicHashAddValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value) {
 ・・・
 CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key);
 if (0 < bkt.count) {
  ht->bits.mutations++;
  if (ht->bits.counts_offset && bkt.count < LONG_MAX) { // if not yet as large as a CFIndex can be... otherwise clamp and do nothing
   __CFBasicHashIncSlotCount(ht, bkt.idx);
   return true;
  }
 } else {
  __CFBasicHashAddValue(ht, bkt.idx, stack_key, stack_value);
  return true;
 }
 return false;
}

CF_PRIVATE void CFBasicHashSetValue(CFBasicHashRef ht, uintptr_t stack_key, uintptr_t stack_value) {
 ・・・
 CFBasicHashBucket bkt = __CFBasicHashFindBucket(ht, stack_key);
 if (0 < bkt.count) {
  __CFBasicHashReplaceValue(ht, bkt.idx, stack_key, stack_value);
 } else {
  __CFBasicHashAddValue(ht, bkt.idx, stack_key, stack_value);
 }
}

승리가 멀지 않은 것 같아, 왜냐하면__CFBasicHashReplaceValue는 의미상 대체입니다.그러면 그 본질은 바로 CFBasicHashAddValue이다. 같은 값의 키가 존재할 때 다시 가입하지 않고 최종 결과는 앞의 값으로 설정하는 것이지 뒤의 값으로 설정하는 것이 아니다.
마찬가지로 당신도 아래의 값을 얻을 수 있습니다. 답을 평론 구역에 쓰는 것을 환영합니다.

[NSDictionary dictionaryWithObjects:@[@1,@2,@3,@4,@5,@6,@7,@8,@9,@0] forKeys:@[@"a",@"b", @"a", @"b", @"a", @"a", @"b", @"b", @"a", @"b"]]

기타


hook 사전 자체의dictionary With Objects:for Keys:count: 시스템의 상태 표시줄에 국한되지 않는 정보를 포함하여 최종적으로 하나의 사전에 저장해야 합니다. 그 저장 시기는 프로젝트가 실행될 때입니다. NSDictionary *dic = @{@'a': @1, @'a': @2};이전에 인터럽트를 걸고 dictionary With Objects: for Keys:count: 인터럽트를 놓습니다.
Objective-C의 문법당 @{}가 무엇인지에 관한 이 글은 여기까지 소개합니다. 더 많은 Objective-C 문법당 @{} 내용은 저희 이전의 글을 검색하거나 아래의 관련 글을 계속 훑어보십시오. 앞으로 많은 응원 부탁드립니다!

좋은 웹페이지 즐겨찾기