Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use iOS to realize the simple processing Framework of skin-changing function

2025-02-24 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/03 Report--

This article mainly shows you "how to use iOS to achieve skin change function of the simple processing framework", the content is easy to understand, clear, hope to help you solve your doubts, the following let the editor lead you to study and learn "how to use iOS to achieve skin change function of the simple processing framework" this article.

Preface

Skinning function is a lot of scenarios encountered in the process of APP development. In order to provide a better user experience, many APP will provide users with the ability to switch themes. The steps involved in theme color management are

Color configuration using the ability to dynamically change color UI elements dynamically modify configuration topic package management how to implement optimization

Color configuration

Because a variety of configurations are involved, it is difficult to define color practices and maintain them in a coded way, and an appropriate solution is to import color configurations in the form of configuration files. The configuration file will go through the conversion steps to form a code-level configuration, which will be provided to each module in a global way. This involves the concept of a color manager, which is generally a singleton object that provides an interface for global access. In the same APP in different modules to save different theme color configuration, in different levels can also exist different theme color configuration, because involves the configuration differences between levels, so the color configuration needs to introduce a level concept, generally higher level color configuration level is higher than the lower level, there is the same configuration higher level configuration will cover the lower level configuration.

The file shape of the color configuration we use is shown below, why is it under the colorkey of a json file, in order to take into account the future expansibility, if different topics will involve some differences in size values, we can add dimensionskey to expand the configuration.

{"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",}}

With the above configuration, the main task of the color configuration is to parse the configuration file and save the configuration in a singleton object. The main steps of this part are as follows:

The profile class table obtains the configuration in each profile according to the ranking, and saves the notification that the external theme color configuration has changed.

The corresponding code is as follows. One thing to note here is that when loading the configuration file, a file read-write lock is used to prevent dirty data from being read until the configuration file is loaded and the read-write lock is released. At this point, the read process can continue.

-(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) {/ / New profile YTThemeConfigFile * file = [[YTThemeConfigFile alloc] init]; file.fileName = fileName; file.level = level; [self.configFileQueue addObject:file]; / / prioritization [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; / / load default configuration if (containDefault) {defaultColorDict = [NSMutableDictionary dictionary]; [self loadConfigDataWithColorMap:defaultColorDict valueMap:nil isDefault:YES]; self.defaultColorMap = defaultColorDict;} / / load theme configuration if (_ themePath.length > 0) {currentColorDict = [NSMutableDictionary dictionary]; [self loadConfigDataWithColorMap:currentColorDict valueMap:nil isDefault:NO]; self.currentColorMap = currentColorDict } / / send notification of body color change [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 {/ / each time a new configuration file is added, all configuration files have to be recalculated. There is a lot of redundant work [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]; / put the data of all color fields in the configuration table into colorMap}}];}-(void) loadThemeColorTo: (NSMutableDictionary *) dictionary from: (NSDictionary *) from {NSDictionary * colors = from [@ "color"] [colors enumerateKeysAndObjectsUsingBlock: ^ (NSString * _ Nonnull key, NSString * _ Nonnull obj, BOOL * _ Nonnull stop) {/ / hexadecimal string to UIColor UIColor * color = [UIColor yt_nullcolorWithHexString:obj]; if (color) {[dictionary setObject:color forKey:key];} else {[dictionary setObject:obj forKey:key];}];}

In addition to processing the configuration, the manager also needs to expose the external interface to the client to obtain the corresponding color values, picture resources, size information and other theme-related information under different themes. For example, we will provide a colorForKey method to obtain the color value of the same key under different themes. The general steps to obtain the color value are as follows:

Get from the current theme configuration from the default theme configuration get the configuration if redirected from the reserved theme configuration, recursive processing the above steps have not been found to return to the default black

The write lock of the read-write lock is used here, and if the lock is acquired by a write operation at the same time, the read process blocks until the completion of the write operation to release the lock.

/ * * get color value * /-(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;} / / normal get color value id colorObj = [_ currentColorMap objectForKey:key] If (colorObj = = nil) {colorObj = [_ defaultColorMap objectForKey:key];} if (isReserveKey & & colorObj = = nil) {return nil;} / / see if there is a replacement key if (colorObj = = nil) {NSString * reserveKey = [_ reserveKeyMap objectForKey:key]; if (reserveKey) {colorObj = [self colorForKey:reserveKey isReserveKey:YES redirectCount:redirectCount];}} / / check whether the current key can be converted to color if (colorObj = = nil) {colorObj = [UIColor yt_colorWithHexString:key] } if ([colorObj isKindOfClass: [UIColor class]]) {/ / if the color of the redirect or replacement key is set to the current colorDict / / the configuration of the redirection is like: "Red_A": "Red_B", if (redirectCount > 0 | | isReserveKey) {[_ currentColorMap?: _ defaultColorMap setObject:colorObj forKey:key];} return colorObj } else {if (redirectCount < 3) {/ / redirect Recursive return [self colorForKey:colorObj isReserveKey:NO redirectCount:redirectCount + 1];} else {return [UIColor blackColor];}

Use Color

The use of color is also through the manager. For convenience, define a color macro to provide to the client.

# define YTThemeColor (key) ([[YTThemeManager sharedInstance] colorForKey:key])

The code used by the client is as follows:

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]

In addition, because the key of the color configuration is a string type, it is not a good idea to use string constants directly, so converting the corresponding string to a macro definition is a relatively good idea. The first is easy to use, you can use code hints; the second is not error-prone, especially long strings; the third will also improve efficiency to some extent.

Macro definition of the YTColorDefine class

The definition NSString * kCK_Black_A = @ "Black_A" in the declaration / BlackFOUNDATION_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_AT = @ "Black_AT"; NSString * kCK_Black_B = @ "Black_B"; NSString * kCK_Black_BT = @ "Black_BT"

Topic package management

In the actual landing project, the items involved in the theme package management include downloading and decompressing the theme package and dynamically loading the theme package. The last step is to change the configuration path where the theme configuration file is located. For the convenience of demonstration, we will put the resources of different topics under a specific folder in the bundle, and achieve the effect of switching the theme by switching the theme path configuration in the manager. The steps are the same as dynamically downloading and changing themes.

The manager provides a method to set the configuration path of the theme configuration. In this method, the configuration can be reloaded while the configuration path is changed. The code is as follows

/ * * set the path to the theme file @ param themePath file * /-(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) YTThemeConfigFile +) {YTThemeConfigFile * obj = [self.configFileQueue objectAtIndex:i]; [obj resetCurrentDict];} [self setupConfigFilesContainDefault:NO]; pthread_rwlock_unlock (& _ rwlock);}

How to implement

The above process only involves a technical solution under the iOS platform. The real practice will involve the annotations of the Android platform, Web pages and UI graphics, which need to be handled uniformly in order to have a consistent experience on all sides. The first step is to develop a reasonable color specification and synchronize the specification to the stakeholders at all ends; the second part is that the UI color is the standard color definition value, rather than the color such as # ffffff, it needs to be a standard color definition value such as White_A, so that the client processing uses the White_A value, regardless of the different color expressions under different themes.

Optimize

Optimization of loadConfigDataWithColorMap method call

If there are many modules, each module will call loadConfigWithFileName to load the configuration file, then the time complexity of the loadConfigDataWithColorMap method to deal with the file is O (NumberN), it will repeat a lot of redundant work, the ideal practice is to save a public color configuration at the bottom, and then load a customized configuration in the app layer, without having to load the theme configuration file in the module, which will improve efficiency.

Attachment: the use of read-write lock pthread_rwlock_t

The read-write lock is used to solve the reader-writer problem, the read operation can be shared, the write operation is exclusive, there can be multiple reading, only one is writing, and reading is not allowed when writing at the same time.

There are two forms of strong reader synchronization and strong writer synchronization.

Strong reader synchronization: when the writer does not write, the reader can access the

Forced writer synchronization: when all the writers have finished writing, the reader needs the latest information, and some factual systems may use the institute, such as booking tickets.

Read-write lock operation:

Initialization of read-write locks:

Define read-write locks: pthread_rwlock_t m_rw_lock

Function prototype: pthread_rwlock_init (pthread_rwlock_t *, pthread_rwattr_t *)

Return value: 0: successful. Non-0 means an error code.

Destruction of read-write locks:

Function prototype: pthread_rwlock_destroy (pthread_rwlock_t*)

Return value: 0: successful; non-0: error code

The read lock operation of acquiring a read-write lock: it is divided into blocking acquisition and non-blocking acquisition. If the read-write lock is held by a writer, the read thread blocks until the writer releases the read-write lock.

Blocking type:

Function prototype: pthread_rwlock_rdlock (pthread_rwlock_t*)

Non-blocking type:

Function prototype: pthread_rwlock_tryrdlock (pthread_rwlock_t*)

Return value: 0: successful, non-0: error code, non-blocking will return ebusy without keeping the thread waiting

The write lock operation of acquiring a read-write lock: it is divided into blocking and non-blocking. If the corresponding read-write lock is held by another writer, or if the read-write lock is held by the reader, the thread will block waiting.

Blocking type:

Function prototype: pthread_rwlock_wrlock (pthread_rwlock_t*)

Non-blocking type:

Function prototype: pthread_rwlock_trywrlock (pthread_rwlock_t*)

Return value: 0, indicating success

Release the read-write lock:

Function prototype: pthread_rwlock_unlock (pthread_rwlock_t*)

Summary (transfer):

The difference between mutexes and read-write locks:

When accessing critical section resources (access means all operations: read and write), a mutex is required

When the data (the critical section resource in the mutex) is read, the read lock is needed, and when the data is written, the write lock is required.

Advantages of read-write locks:

For applications where reading data is more frequent than modifying data, using read-write locks instead of mutexes can improve efficiency. Because when using a mutex lock, even the read data (equivalent to the operation critical area resource) must be on the mutex lock, while the read-write lock can allow multiple readers to exist at any time, improving the concurrency degree. At the same time, the data is protected during the modification of the data by a writer, so as to avoid interference from any other readers or writers.

Read-write lock description:

Acquiring a read-write lock for reading is called a shared lock, and acquiring a read-write lock for writing is called an exclusive lock, so this shared access to a given resource is also called a shared-exclusive lock.

Other statements about this type of problem (multiple readers and one writer) include reader and writer problems and multi-reader-single writer locks.

The above is all the contents of this article entitled "how to use iOS to achieve a simple framework for skin replacement". Thank you for reading! I believe we all have a certain understanding, hope to share the content to help you, if you want to learn more knowledge, welcome to follow the industry information channel!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report