iOS 스킨 케 어 기능 을 위 한 간단 한 처리 프레임 워 크(소스 코드)

머리말
스킨 케 어 기능 은 앱 개발 과정 에서 만 나 는 비교적 많은 장면 으로 더 나 은 사용자 체험 을 제공 하기 위해 많은 앱 이 사용자 에 게 테 마 를 전환 하 는 기능 을 제공한다.테마 색상 관리 와 관련 된 절차 는
색상 설정
사용 색상
UI 요소 의 동적 변경 능력동적 수정 설정
테마 패키지 관리
어떻게 실시 합 니까?
최적화
효 과 는 다음 과 같 습 니 다:

DEMO 코드:https://gitee.com/dhar/iosdemos/tree/master/YTThemeManagerDemo
색상 설정
다양한 설정 과 관련 되 어 있 기 때문에 코드 로 색상 실천 과 유 지 를 정의 하 는 것 이 어렵 습 니 다.적당 한 방안 은-색상 설정 은 설정 파일 형식 으로 가 져 옵 니 다.설정 파일 은 변환 절 차 를 거 쳐 최종 적 으로 코드 등급 의 설정 을 형성 하고 전역 적 인 방식 으로 각 모듈 에 제공 합 니 다.여 기 는 하나의 색상 관리자 의 개념 과 관련 됩 니 다.일반적으로 이 는 하나의 사례 대상 으로 전체 방문 인 터 페 이 스 를 제공 합 니 다.같은 APP 에서 서로 다른 모듈 에 서로 다른 테마 색상 설정 을 저장 하고 서로 다른 등급 에서 도 서로 다른 테마 색상 설정 이 존재 할 수 있 습 니 다.등급 간 의 설정 차이 와 관련 되 기 때문에 색상 의 설정 은 하나의 등급 의 개념 을 도입 해 야 합 니 다.보통 고 층 색상 의 설정 등급 은 낮은 등급 보다 높 습 니 다.같은 설정 이 존재 합 니 다.높 은 등급 의 설정 은 낮은 등급 의 설정 을 덮어 씁 니 다.
우리 가 사용 하 는 색상 설정 의 파일 형 은 아래 와 같 습 니 다.왜 json 파일 의 colorkey 아래 에 있 습 니까?미래의 확장 성 을 고려 하기 위해 서 입 니 다.만약 에 서로 다른 주제 가 사이즈 값 의 차별 화 와 관련 될 경우 dimensionskey 를 추가 하여 확장 설정 을 할 수 있 습 니 다.

{
 "color": {
 "Black_A":"323232",
 "Black_AT":"323232",
 "Black_B":"888888",
 "Black_BT":"888888",

 "White_A":"ffffff",
 "White_AT":"ffffff",
 "White_AN":"ffffff",

 "Red_A":"ff87a0",
 "Red_AT":"ff87a0",
 "Red_B":"ff5073",
 "Red_BT":"ff5073",

 "Colour_A":"377ce4",
 "Colour_B":"6aaafa",
 "Colour_C":"ff8c55",
 "Colour_D":"ffa200",
 "Colour_E":"c4a27a",
 }
}
이상 의 설정 이 있 습 니 다.색상 설정 작업 은 주로 이 프로필 을 분석 하고 설정 을 하나의 단일 대상 에 저장 하면 됩 니 다.이 부분의 주요 절 차 는 다음 과 같 습 니 다.
설정 파일 클래스 표 는 등급 에 따라 정렬 됩 니 다
  • 각 프로필 의 설정 을 가 져 와 저장 합 니 다
  • 외부 테마 색상 설정 변경 알림대응 하 는 코드 는 다음 과 같 습 니 다.여기 서 주의해 야 할 점 은 설정 파일 을 불 러 올 때 파일 읽 기와 쓰기 자 물 쇠 를 사용 하여 읽 기와 쓰기 잠 금 작업 을 하여 더러 운 데 이 터 를 읽 는 것 을 방지 하고 설정 파일 로드 가 완 료 될 때 까지 읽 기와 쓰기 자 물 쇠 를 풀 었 습 니 다.이때 읽 기 프로 세 스 는 계속 할 수 있 습 니 다.
    
    - (void)loadConfigWithFileName:(NSString *)fileName level:(NSInteger)level {
     if (fileName.length == 0) {
     return;
     }
     
     pthread_rwlock_wrlock(&_rwlock);
     __block BOOL finded = NO;
     [self.configFileQueue enumerateObjectsUsingBlock:^(YTThemeConfigFile *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
     if ([obj.fileName isEqualToString:fileName]) {
      finded = YES;
      *stop = YES;
     }
     }];
     if (!finded) {
     //       
     YTThemeConfigFile *file = [[YTThemeConfigFile alloc] init];
     file.fileName = fileName;
     file.level = level;
     [self.configFileQueue addObject:file];
     //      
     [self.configFileQueue sortUsingComparator:^NSComparisonResult(YTThemeConfigFile *_Nonnull obj1, YTThemeConfigFile *_Nonnull obj2) {
      if (obj1.level > obj2.level) {
      return NSOrderedDescending;
      }
      return NSOrderedAscending;
     }];
     [self setupConfigFilesContainDefault:YES];
     }
     pthread_rwlock_unlock(&_rwlock);
    }
    
    - (void)setupConfigFilesContainDefault:(BOOL)containDefault {
     NSMutableDictionary *defaultColorDict = nil, *currentColorDict = nil;
     
     //       
     if (containDefault) {
     defaultColorDict = [NSMutableDictionary dictionary];
     [self loadConfigDataWithColorMap:defaultColorDict valueMap:nil isDefault:YES];
     
     self.defaultColorMap = defaultColorDict;
     }
     
     //       
     if (_themePath.length > 0) {
     currentColorDict = [NSMutableDictionary dictionary];
     [self loadConfigDataWithColorMap:currentColorDict valueMap:nil isDefault:NO];
     
     self.currentColorMap = currentColorDict;
     }
     
     //           
     [self notifyThemeDidChange];
    }
    
    - (void)notifyThemeDidChange {
     NSArray *allActionObjects = self.actionMap.objectEnumerator.allObjects;
     for (YTThemeAction *action in allActionObjects) {
     [action notifyThemeDidChange];
     }
    }
    
    - (void)loadConfigDataWithColorMap:(NSMutableDictionary *)colorMap valueMap:(NSMutableDictionary *)valueMap isDefault:(BOOL)isDefault {
     //            ,              ,            
     [self.configFileQueue enumerateObjectsUsingBlock:^(YTThemeConfigFile *_Nonnull obj, NSUInteger idx, BOOL *_Nonnull stop) {
     NSDictionary *dict = nil;
     if (isDefault) {
      dict = obj.defaultDict;
     } else {
      dict = obj.currentDict;
     }
     if (dict.count > 0) {
      [self loadThemeColorTo:colorMap from:dict]; //         color        colorMap 
     }
     }];
    }
    
    - (void)loadThemeColorTo:(NSMutableDictionary *)dictionary from:(NSDictionary *)from {
     NSDictionary<NSString *, NSString *> *colors = from[@"color"];
     [colors enumerateKeysAndObjectsUsingBlock:^(NSString *_Nonnull key, NSString *_Nonnull obj, BOOL *_Nonnull stop) {
     //          UIColor
     UIColor *color = [UIColor yt_nullcolorWithHexString:obj];
     if (color) {
      [dictionary setObject:color forKey:key];
     } else {
      [dictionary setObject:obj forKey:key];
     }
     }];
    }
    관리자 가 처리 설정 을 처리 하 는 동시에 외부 인 터 페 이 스 를 클 라 이언 트 에 노출 시 켜 서로 다른 주제 에 대응 하 는 색상 값,이미지 자원,사이즈 정보 등 주제 와 관련 된 정 보 를 얻 을 수 있 도록 해 야 합 니 다.예 를 들 어 저 희 는 colorForKey 방법 을 제공 하여 서로 다른 주제 에서 같은 key 에 대응 하 는 색상 값 을 얻 습 니 다.색상 값 을 얻 는 대략적인 절 차 는 다음 과 같 습 니 다.
    현재 테마 설정 에서 가 져 오기기본 테마 설정 에서 가 져 오기
  • 미리 남 겨 진 테마 설정 에서 가 져 오기
  • 방향 을 바 꾸 는 설정 이 있 으 면 재 귀적 으로 처리 합 니 다
  • 이상 의 절차 가 완료 되 었 지만 기본 검은색 으로 돌아 갈 수 없습니다
  • 읽 기와 쓰기 자물쇠 의 쓰기 자 물 쇠 를 사 용 했 습 니 다.쓰기 동작 이 동시에 이 자 물 쇠 를 가 져 오 면 쓰기 작업 이 끝 날 때 까지 읽 기 프로 세 스 가 막 힙 니 다.
    
    /**
          
     */
    - (UIColor *)colorForKey:(NSString *)key {
     pthread_rwlock_rdlock(&_rwlock);
     UIColor *color = [self colorForKey:key isReserveKey:NO redirectCount:0];
     pthread_rwlock_unlock(&_rwlock);
     return color;
    }
    
    - (UIColor *)colorForKey:(NSString *)key isReserveKey:(BOOL)isReserveKey redirectCount:(NSInteger)redirectCount {
     if (key == nil) {
     return nil;
     }
     
     ///      
     id colorObj = [_currentColorMap objectForKey:key];
     if (colorObj == nil) {
     colorObj = [_defaultColorMap objectForKey:key];
     }
     
     if (isReserveKey && colorObj == nil) {
     return nil;
     }
     
     ///       key
     if (colorObj == nil) {
     NSString *reserveKey = [_reserveKeyMap objectForKey:key];
     if (reserveKey) {
      colorObj = [self colorForKey:reserveKey isReserveKey:YES redirectCount:redirectCount];
     }
     }
     
     ///    key      color
     if (colorObj == nil) {
     colorObj = [UIColor yt_colorWithHexString:key];
     }
     
     if ([colorObj isKindOfClass:[UIColor class]]) {
     ///              key  color         colorDict   
     //         :"Red_A":"Red_B",
     if (redirectCount > 0 || isReserveKey) {
      [_currentColorMap ?: _defaultColorMap setObject:colorObj forKey:key];
     }
     return colorObj;
     } else {
     if (redirectCount < 3) { //      
      return [self colorForKey:colorObj isReserveKey:NO redirectCount:redirectCount + 1];
     } else {
      return [UIColor blackColor];
     }
     }
    }
    색상 사용
    색상 의 사용 도 관리자 의 편 의 를 위해 색상 매크로 를 정의 하여 클 라 이언 트 에 게 제공 합 니 다.
    
    #define YTThemeColor(key) ([[YTThemeManager sharedInstance] colorForKey:key])
    클 라 이언 트 가 사용 하 는 코드 는 다음 과 같 습 니 다.
    
    UILabel *label = [[UILabel alloc] initWithFrame:CGRectMake(0, 20, 200, 40)];
    label.text = @"Text";
    label.textColor = YTThemeColor(kCK_Red_A);
    label.backgroundColor = YTThemeColor(kCK_Black_H);
    [self.view addSubview:label];
    또한,색상 설정 키 는 문자열 형식 이기 때문에 문자열 상수 를 직접 사용 하 는 것 은 좋 은 방법 이 아니 므 로 해당 하 는 문자열 을 매크로 로 정의 하 는 것 이 좋 은 방법 입 니 다.첫 번 째 는 사용 하기 편리 하고 코드 알림 을 사용 할 수 있 습 니 다.두 번 째 는 실수 가 쉽 지 않 습 니 다.특히 긴 문자열 입 니 다.세 번 째 도 어느 정도 효율 을 높 일 수 있다.
    YTColorDefine 클래스 의 매크로 정의
    
    // .h     
    ///Black
    FOUNDATION_EXTERN NSString *kCK_Black_A;
    FOUNDATION_EXTERN NSString *kCK_Black_AT;
    FOUNDATION_EXTERN NSString *kCK_Black_B;
    FOUNDATION_EXTERN NSString *kCK_Black_BT;
    
    // .m     
    NSString *kCK_Black_A = @"Black_A";
    NSString *kCK_Black_AT = @"Black_AT";
    NSString *kCK_Black_B = @"Black_B";
    NSString *kCK_Black_BT = @"Black_BT";
    테마 패키지 관리
    실제 착지 항목 에서 테마 패키지 관리 와 관련 된 사항 은 테마 패키지 다운로드 와 압축 해제,동적 로드 테마 패키지 등 내용 을 포함 합 니 다.마지막 단 계 는 테마 프로필 이 있 는 설정 경 로 를 바 꾸 는 것 입 니 다.프 리 젠 테 이 션 의 편 의 를 위해 서로 다른 테마 자원 을 bundle 의 특정한 폴 더 에 두 겠 습 니 다.관리자 의 테마 경로 설정 을 전환 하여 테마 전환 효 과 를 얻 습 니 다.동적 다운로드 로 테 마 를 바 꾸 는 절차 와 같 습 니 다.
    관리 자 는 테마 설정 의 설정 경 로 를 설정 하 는 방법 을 제공 합 니 다.이 방법 에서 설정 경 로 를 바 꾸 는 동시에 설정 을 다시 불 러 오 면 됩 니 다.코드 는 다음 과 같 습 니 다.
    
    /**
              
     @param themePath      
     */
    - (void)setupThemePath:(NSString *)themePath {
     pthread_rwlock_wrlock(&_rwlock);
     
     _themePath = [themePath copy];
     
     self.currentColorMap = nil;
     
     if ([_themePath.lowercaseString isEqualToString:[[NSBundle mainBundle] resourcePath].lowercaseString]) {
     _themePath = nil;
     }
     
     self.currentThemePath = _themePath;
     
     for (int i = 0; i < self.configFileQueue.count; i++) {
     YTThemeConfigFile *obj = [self.configFileQueue objectAtIndex:i];
     [obj resetCurrentDict];
     }
     [self setupConfigFilesContainDefault:NO];
     
     pthread_rwlock_unlock(&_rwlock);
    }
    어떻게 실시 합 니까?
    이상 의 절 차 는 iOS 플랫폼 아래 의 기술 솔 루 션 과 관련 되 고 실제 실천 과정 에서 안 드 로 이 드 플랫폼,웹 페이지,UI 에서 그림 을 표시 하 는 것 과 관련 될 수 있 습 니 다.이런 것들 은 통일 적 으로 처리 해 야 각 부분 에서 일치 하 는 체험 을 할 수 있 습 니 다.첫 번 째 단 계 는 합 리 적 인 색채 규범 을 제정 하고 규범 을 각 측의 이해관계 자 에 게 동기 화 하 는 것 이다.두 번 째 부분 은 UI 그림 색상 이 규범 화 된 색상 정의 값 입 니 다.예 를 들 어\#ffff 와 같은 색상 이 아 닙 니 다.예 를 들 어 White 가 필요 합 니 다.A.이렇게 규범 화 된 색상 정의 값 을 사용 하면 클 라 이언 트 가 처리 하 는 것 은 White 입 니 다.A.이 값 은 서로 다른 주제 에서 서로 다른 색채 표현 형식 에 신경 쓰 지 않 아 도 됩 니 다.
    최적화 하 다.
    loadConfigData With ColorMap 방법 호출 최적화
    모듈 이 많 으 면 모듈 마다 loadConfigWith FileName 을 호출 하여 프로필 을 불 러 옵 니 다.loadConfigData With ColorMap 방법 으로 파일 을 처리 하 는 시간 복잡 도 는 O(N*N)입 니 다.불필요 한 작업 을 반복 적 으로 처리 합 니 다.이상 적 인 방법 은 기본 에 공유 색상 설정 을 저장 한 다음 에 APP 층 에 맞 춤 형 설정 을 불 러 오 는 것 입 니 다.모듈 에 테마 설정 파일 을 더 이상 불 러 오지 않 아 도 효율 을 높 일 수 있 습 니 다.
    첨부:읽 기와 쓰기 자물쇠 pthreadrwlock_t 의 사용
    읽 기와 쓰기 자 물 쇠 는 독자 의 문 제 를 해결 하 는 데 쓰 이 는 것 이다.읽 기 동작 은 공유 할 수 있 고 쓰기 동작 은 배타 적 이다.읽 기 동작 은 여러 개 만 읽 을 수 있 고 쓰 기 는 유일 하 게 쓰 고 쓸 때 읽 을 수 없다.
    강 한 독자 동기 화 와 강 한 쓰기 자 동기 화 두 가지 형식 을 가지 고 있다.
    강 한 독자 동기 화:작성 자가 쓰기 조작 을 하지 않 으 면 독자 가 방문 할 수 있다.
    강 한 작성 자 동기 화:모든 작성 자가 다 쓴 후에 야 읽 기 작업 을 할 수 있 고 독 자 는 최신 정 보 를 필요 로 한다.일부 사실 성 이 높 은 시스템 은 이 곳,예 를 들 어 예약 표 와 같은 것 을 사용 할 수 있다.
    자물쇠 읽 기 동작:
    읽 기와 쓰기 자물쇠 의 초기 화:
            정의 읽 기와 쓰기 잠 금:          pthread_rwlock_t  m_rw_lock;
            함수 원형:              pthread_rwlock_init(pthread_rwlock_t * ,pthread_rwattr_t *);
            반환 값:0,성공 표시,0 이 아 닌 오류 코드
    읽 기와 쓰기 자물쇠 의 소각:
            함수 원형:             pthread_rwlock_destroy(pthread_rwlock_t* );
            반환 값:0,성공 표시,0 이 아 닌 오류 표시
    읽 기와 쓰기 자 물 쇠 를 가 져 오 는 읽 기 자 물 쇠 를 가 져 옵 니 다.읽 기와 쓰기 자 물 쇠 를 한 쓰기 자가 가지 고 있 으 면 쓰기 자 물 쇠 를 풀 때 까지 읽 기 스 레 드 가 막 힙 니 다.
            차단 식:
                                함수 원형:pthreadrwlock_rdlock(pthread_rwlock_t*);
            비 차단 식:
                                함수 원형:pthreadrwlock_tryrdlock(pthread_rwlock_t*);
           반환 값:0,성공 을 표시 합 니 다.0 이 아 닌 오류 코드 를 표시 합 니 다.차단 되 지 않 으 면 ebusy 로 돌아 가 스 레 드 를 기다 리 지 않 습 니 다.
    읽 기와 쓰기 자 물 쇠 를 가 져 오 는 쓰기 동작:차단 과 비 차단 으로 나 뉘 는데 해당 하 는 읽 기와 쓰기 자 물 쇠 를 다른 작성 자가 가지 고 있 거나 읽 기와 쓰기 자 물 쇠 를 독자 가 가지 고 있 으 면 이 스 레 드 는 기다 리 는 것 을 막 습 니 다.
          차단 식:
                               함수 원형:pthreadrwlock_wrlock(pthread_rwlock_t*);
          비 차단 식:
                               함수 원형:pthreadrwlock_trywrlock(pthread_rwlock_t*);
           반환 값:0,성공 표시
    읽 기와 쓰기 잠 금 해제:
                             함수 원형:pthreadrwlock_unlock(pthread_rwlock_t*);
    요약(전환):
    상호 배척 자물쇠 와 읽 기와 쓰기 자물쇠 의 차이 점:
    임계 구역 자원 에 접근 할 때(방문 의 의 미 는 모든 조작:읽 기와 쓰기 포함)상호 배척 자물쇠 가 필요 합 니 다.
    데이터(상호 배척 자물쇠 의 임계 구역 자원)를 읽 을 때 읽 기 자 물 쇠 를 올 려 야 합 니 다.데 이 터 를 기록 할 때 자 물 쇠 를 올 려 야 합 니 다.
    읽 기와 쓰기 자물쇠 의 장점:
    읽 기 데이터 가 수정 데이터 보다 빈번 한 응용 에 대해 서 는 상호 배척 잠 금 대신 읽 기 쓰기 잠 금 을 사용 하면 효율 을 높 일 수 있다.상호 배척 자 물 쇠 를 사용 할 때 데 이 터 를 읽 는 것(임계 구역 자원 을 조작 하 는 것 과 같 음)도 서로 배척 하 는 자 물 쇠 를 사용 해 야 하기 때문에 읽 기와 쓰기 자 물 쇠 를 사용 하면 어느 순간 에 여러 읽 는 사람 이 존재 하도록 허용 하고 더 높 은 병행 도 를 높 일 수 있 으 며 특정한 기록 자가 데 이 터 를 수정 하 는 동안 이 데 이 터 를 보호 하여 다른 읽 는 사람 이나 기록 자의 간섭 을 피 할 수 있 기 때문이다.
    읽 기 및 쓰기 잠 금 설명:
    읽 기 및 쓰기 자 물 쇠 를 가 져 오 는 것 을 공유 자물쇠 라 고 합 니 다.읽 기 및 쓰기 자 물 쇠 를 가 져 오 는 것 을 독점 자물쇠 라 고 합 니 다.따라서 주어진 자원 에 대한 공유 접근 을 공유-독점 자물쇠 라 고도 합 니 다.
    이러한 유형의 문제(여러 읽 기 및 쓰기 자)에 대한 다른 설 은 읽 기 및 쓰기 자 문제 및 다 중 읽 기-단일 쓰기 자 잠 금 이 있 습 니 다.
    총결산
    이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

    좋은 웹페이지 즐겨찾기