[Edward 연금방] MJextension 읽기 노트.
지식 포인트:
설계에서 전환 효율을 높이기 위해 캐시를 대량으로 사용했는데 프로젝트에서 캐시를 사용하는 방안은 두 가지가 있다.
MJProperty
류에서 이 기교를 사용했다.같은 속성objc_property_t
에서 생성된 MJProperty
대상의 내용이 모두 같기 때문에 저자는 이를 캐시하여 중복된 실행 생성 논리를 피했다.저자는 속성property
을 교묘하게 이용key
했다.속성은 구조체 포인터입니다.클래스의 속성 주소는 컴파일러에 의해 결정되고 유일합니다.그것은 key
의 역할을 잘 충당할 수 있다.+ (instancetype)cachedPropertyWithProperty:(objc_property_t)property
{
MJProperty *propertyObj = objc_getAssociatedObject(self, property);
if (propertyObj == nil) {
propertyObj = [[self alloc] init];
propertyObj.property = property;
objc_setAssociatedObject(self, property, propertyObj, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
return propertyObj;
}
+initialize
또는 +load
에서 정적 사전 대상을 초기화합니다.저자는 이 방안으로 서로 다른 종류의 정보를 캐시하는데, 이 사전의 key
은 클래스 이름 문자열이고, value
는 그 내용이다.마찬가지로 NSObject+MJClass.h
에 속성이 필요한 흑백 명단을 저장하면 백명단의 속성은 사전과 모델의 전환을 하고 흑명단의 속성은 무시된다.화이트리스트는 모두 전환에 참여한다는 뜻이다.//
static NSMutableDictionary *allowedPropertyNamesDict_;
static NSMutableDictionary *ignoredPropertyNamesDict_;
@implementation NSObject (MJClass)
+ (void)load
{
allowedPropertyNamesDict_ = [NSMutableDictionary dictionary];
ignoredPropertyNamesDict_ = [NSMutableDictionary dictionary];
}
#pragma mark -
+ (void)mj_setupAllowedPropertyNames:(MJAllowedPropertyNames)allowedPropertyNames;
{
NSMutableArray *array = allowedPropertyNamesDict_[NSStringFromClass(self)];
if (array) return array;
// 、
allowedPropertyNamesDict_[NSStringFromClass(self)] = array = [NSMutableArray array];
....
return array;
}
+ (NSMutableArray *)mj_totalAllowedPropertyNames
{
NSMutableArray *array = ignoredPropertyNamesDict_[NSStringFromClass(self)];
if (array) return array;
// 、
ignoredPropertyNamesDict_[NSStringFromClass(self)] = array = [NSMutableArray array];
....
return array;
}
@end
매크로 정의를 사용하여 클래스를 압축하는 역할을 합니다
저자는 매크로
MJExtensionCodingImplementation
를 썼습니다. 압축 파일을 지원하려면 실현 함수에 이 매크로를 추가하면 됩니다.@implementation MJBag
// NSCoding
MJExtensionCodingImplementation
@end
작가님은 어떻게 하셨을까요?우리는 이 거대한 것을 펼치기만 하면 알 수 있다.이 매크로는 우리
- (id)initWithCoder:(NSCoder *)decoder
와 - (void)encodeWithCoder:(NSCoder *)encoder
방법을 실현시켰다.이 두 가지 방법 중, 각각 저자가 쓴 인코딩과 디코딩 방법을 호출하였으며, 방법에서 모든 속성을 두루 훑어보며 조작하였다.#define MJCodingImplementation \
- (id)initWithCoder:(NSCoder *)decoder \
{ \
if (self = [super init]) { \
[self mj_decode:decoder]; \
} \
return self; \
} \
\
- (void)encodeWithCoder:(NSCoder *)encoder \
{ \
[self mj_encode:encoder]; \
}
#define MJExtensionCodingImplementation MJCodingImplementation
속성에 대한 문자열 설명(the attribute string of a property)
우리는
runtime
라이브러리const char *property_getAttributes(objc_property_t property)
방법을 통해 속성의 유형 설명과 속성 이름을 얻을 수 있다.우리는 문자열의 글자 크기 방법 @()
을 사용하여 c 문자열을 NSString
형식으로 바꿀 수 있다. :T + + + V +
공식 연결: Property Type String, Type Encodings
부족한 점:
존재하는 다중 루틴 문제
MJExtension
는 다중 루틴의 전환을 지원하지 않는 것 같아서 원본 코드를 읽는 과정에서 두 개의 다중 루틴 문제를 발견했다.//
후에 인쇄 결과를 제시했습니다.- (void)testMutilThread1
{
dispatch_async(dispatch_queue_create(NULL, NULL), ^{
NSDictionary *dict = @{
@"name":@"name",
@"price":@(2)
};
[MJBag mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
return @{
@"price":@"price"
};
}];
MJBag *bag = [MJBag mj_objectWithKeyValues:dict];
NSLog(@"%@",bag); // name:name,price:0.000000
});
dispatch_async(dispatch_queue_create(NULL, NULL), ^{
NSDictionary *dict = @{
@"name":@"name",
@"price2":@(3)
};
[MJBag mj_setupReplacedKeyFromPropertyName:^NSDictionary *{
return @{
@"price":@"price2"
};
}];
MJBag *bag = [MJBag mj_objectWithKeyValues:dict];
NSLog(@"%@",bag); //name:name,price:3.000000
});
}
우리는 첫 번째 대상의 결과가 틀렸다는 것을 볼 수 있다.그 이유는 같은 종류의 속성과 사전의 映射 관계표가 프로그램에 한 부만 존재하기 때문이다.우리는 첫 번째 라인에서 映射 관계를 설정하고 실행 변환을 실행하는 사이에 두 번째 라인에서 映射 관계를 다시 설정하였는데, 이로 인해 첫 번째 사전이 두 번째 사전의 映射 관계를 사용하여 변환이 잘못되었다.
하나의 모델은 여러 사전의 효율이 떨어지는 문제에 대응한다
앞서 말했듯이 저자는 사전을 캐시로 사용하여 모델 사전의 전환 효율을 가속화시킨다.그 중 중요한 캐시 중 하나는 클래스의 속성 목록과 사전과의 映射 관계이다.저자는 사전을 캐시 용기로 사용하는데, 종류마다 캐시 데이터가 하나밖에 없다.이로 인해 하나의 모델이 서로 다른 위치에 사용되어야 하고, 서로 다른 사전을 사용하여 변환해야 한다. 그러면 매번 변환할 때마다 맵 관계를 다시 설정해야 하기 때문에 캐시가 효력을 잃게 된다.더 심각한 것은 작가가 캐시를 일률적으로 정리하는 방식을 채택했다는 것이다.맵 관계를 설정하는 코드를 살펴보겠습니다.하나의 클래스가 맵 관계를 다시 설정하면 모든 캐시가 정리됩니다.이것은 결코 총명한 방법이 아니다.
+ (void)mj_setupReplacedKeyFromPropertyName:(MJReplacedKeyFromPropertyName)replacedKeyFromPropertyName
{
//
[self mj_setupBlockReturnValue:replacedKeyFromPropertyName key:&MJReplacedKeyFromPropertyNameKey];
//
[[self dictForKey:&MJCachedPropertiesKey] removeAllObjects];
}
의심스럽다
서로 다른 분류에는 같은 유방명이 있는데, 왜 충돌하는 상황이 나타나지 않습니까?
뒤에
runtime
의 원본을 찾아서 원인을 찾아라.@implementation NSObject (MJClass)
+ (NSMutableDictionary *)dictForKey:(const void *)key
{
@synchronized (self) {
if (key == &MJAllowedPropertyNamesKey) return allowedPropertyNamesDict_;
if (key == &MJIgnoredPropertyNamesKey) return ignoredPropertyNamesDict_;
if (key == &MJAllowedCodingPropertyNamesKey) return allowedCodingPropertyNamesDict_;
if (key == &MJIgnoredCodingPropertyNamesKey) return ignoredCodingPropertyNamesDict_;
return nil;
}
}
......
@end
@implementation NSObject (Property)
+ (NSMutableDictionary *)dictForKey:(const void *)key
{
@synchronized (self) {
if (key == &MJReplacedKeyFromPropertyNameKey) return replacedKeyFromPropertyNameDict_;
if (key == &MJReplacedKeyFromPropertyName121Key) return replacedKeyFromPropertyName121Dict_;
if (key == &MJNewValueFromOldValueKey) return newValueFromOldValueDict_;
if (key == &MJObjectClassInArrayKey) return objectClassInArrayDict_;
if (key == &MJCachedPropertiesKey) return cachedPropertiesDict_;
return nil;
}
}
......
@end
총결산
MJExtension
는 캐시를 사용하여 전환 효율을 가속화시켰다. 두 가지 캐시 방법을 사용했다. 첫 번째는 관련 대상을 사용하는 방법이고 두 번째는 정적 사전을 사용하는 방법이다.MJExtension
宏 정의를 사용하여 클래스를 압축하는 역할을 한다.MJExtension
속성의 문자열 설명(the attribute string of a property)을 사용하여 속성의 유형을 얻기;MJExtension
을 피하고 문제가 발생하지 않도록 권장한다.+mj_setupReplacedKeyFromPropertyName:
, +mj_setupReplacedKeyFromPropertyName121:
등을 최대한 많이 사용하지 마세요.이 방법을 사용하면 모든 종류의 캐시를 정리해서 전환 효율을 떨어뜨릴 수 있습니다.이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
다양한 언어의 JSONJSON은 Javascript 표기법을 사용하여 데이터 구조를 레이아웃하는 데이터 형식입니다. 그러나 Javascript가 코드에서 이러한 구조를 나타낼 수 있는 유일한 언어는 아닙니다. 저는 일반적으로 '객체'{}...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.