iOS开发-实现获取下载主题配置动态切换主题
iOS开发-实现获取下载主题配置动态切换主题
iOS开发-实现获取下载主题配置更切换主题,主要是通过请求服务端配置的主题配置、下载主题、解压保存到本地。通知界面获取对应的图片及颜色等。
比如新年主题风格,常见的背景显示红色氛围图片、tabbar显示新年风格的按钮样式、导航条显示红色样式等。
一、主题Json对应的model
这里使用JsonModel将主题转成model
model代码如下
SDAppThemeConfigViewModel.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>/**Navigation主题样式*/
@interface SDAppThemeConfigNavViewModel : NSObject@property (nonatomic, strong) NSString *backgroundColor;
@property (nonatomic, strong) NSString *backgroundImage;@property (nonatomic, strong) UIImage *t_backgroundImage;@property (nonatomic, strong) NSString *btnImageColor;
@property (nonatomic, strong) NSString *btnTitleColor;
@property (nonatomic, strong) NSString *navTitleColor;@property (nonatomic, strong) NSString *showLine;
@property (nonatomic, strong) NSString *lineColor;@end/**单个tab按钮样式*/
@interface SDAppThemeConfigTabItemViewModel : NSObject@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSString *titleColor;
@property (nonatomic, strong) NSString *selectedTitleColor;
@property (nonatomic, strong) NSString *icon;
@property (nonatomic, strong) NSString *selectedIcon;@property (nonatomic, strong) UIImage *t_icon;
@property (nonatomic, strong) UIImage *t_selectedIcon;@end/**tabbar样式*/
@interface SDAppThemeConfigTabViewModel : NSObject@property (nonatomic, strong) NSString *backgroundColor;
@property (nonatomic, strong) NSString *backgroundImage;
@property (nonatomic, strong) NSString *showLine;
@property (nonatomic, strong) NSString *lineColor;
@property (nonatomic, strong) NSString *badgeBgColor;@property (nonatomic, strong) UIImage *t_backgroundImage;@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *lianlian;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *guangguang;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *message;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *shop;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *mine;@end/**将本地的主题config.json转成viewmodel*/
@interface SDAppThemeConfigViewModel : NSObject@property (nonatomic, strong) NSString *globalColor;
@property (nonatomic, strong) NSString *globalImage;
@property (nonatomic, strong) SDAppThemeConfigNavViewModel *navigation;
@property (nonatomic, strong) SDAppThemeConfigTabViewModel *tabbar;@property (nonatomic, strong) UIImage *t_globalImage;+ (SDAppThemeConfigViewModel *)themeViewModel:(NSString *)themeJson;+ (SDAppThemeConfigViewModel *)defautThemeViewModel;@end
SDAppThemeConfigViewModel.m
#import "SDAppThemeConfigViewModel.h"
#import <NSObject+YYModel.h>/**Navigation主题样式*/
@implementation SDAppThemeConfigNavViewModel@end/**单个tab按钮样式*/
@implementation SDAppThemeConfigTabItemViewModel@end/**tabbar样式*/
@implementation SDAppThemeConfigTabViewModel@end/**将本地的主题config.json转成viewmodel*/
@implementation SDAppThemeConfigViewModel+ (SDAppThemeConfigViewModel *)themeViewModel:(NSString *)themeJson {return [SDAppThemeConfigViewModel modelWithJSON:themeJson];
}+ (SDAppThemeConfigViewModel *)defautThemeViewModel {SDAppThemeConfigViewModel *viewModel = [[SDAppThemeConfigViewModel alloc] init];SDAppThemeConfigNavViewModel *navConfigViewModel = [[SDAppThemeConfigNavViewModel alloc] init];navConfigViewModel.backgroundColor = @"171013";navConfigViewModel.btnImageColor = @"ffffff";navConfigViewModel.btnTitleColor = @"ffffff";navConfigViewModel.navTitleColor = @"ffffff";viewModel.navigation = navConfigViewModel;return viewModel;
}@end
二、实现下载解压主题
2.1 AFNetworking下载
下载使用的是AFNetworking下载功能。AFNetworking是一个轻量级的iOS网络通信类库。
下载代码:
#pragma mark - Http download
/**请求下载@param aUrl aurl@param aSavePath aSavePath@param aFileName aFileName@param aTag aTag@param downloadprogress downloadprogress@param success success@param failure failure*/
- (void)downloadFileURL:(NSString *)aUrlsavePath:(NSString *)aSavePathfileName:(NSString *)aFileNametag:(NSInteger)aTagdownloadProgress:(void(^)(CGFloat progress))downloadprogresssuccess:(void(^)(NSURLResponse *response,NSString *filePath))successfailure:(void(^)(HttpError * e))failure {NSFileManager *fileManger = [NSFileManager defaultManager];if ([fileManger fileExistsAtPath:[aSavePath stringByAppendingPathComponent:aFileName]]) {//文件存在return;}//2.确定请求的URL地址NSString *requestUrl = [self requestUrlWithPath:aUrl clientType:HttpClientTypeWithOut];NSMutableURLRequest *request = [self.httpManager.requestSerializer requestWithMethod:@"GET" URLString:requestUrl parameters:nil error:nil];__block NSURLSessionDownloadTask *downloadTask = nil;downloadTask = [self.httpManager downloadTaskWithRequest:request progress:^(NSProgress * _Nonnull downloadProgress) {dispatch_async(dispatch_get_main_queue(), ^{downloadprogress(1.0 * downloadProgress.completedUnitCount / downloadProgress.totalUnitCount);});} destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {return [NSURL fileURLWithPath:aSavePath];} completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {if(error == nil) {success(response,[filePath path]);} else {//下载失败NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;HttpError *e = [self httpRequestFailure:httpResponse error:error];failure(e);}}];[downloadTask resume];
}
2.2 判断主题版本是否已经下载
在获取主题版本时候,需要判断主题是否存在,如果存在,则直接获取保存的地址。不存在,下载解压当前版本的主题包。
//判断当前主题版本号下是否存在资源文件夹BOOL curThemeExist = [self hasAppThemeVersion:themeModel.curVersion];if (!curThemeExist) {//如果不存在,重新下载解压__block NSString *saveZipPath = [self saveThemeTargetBasePath:themeModel.curVersion];__block NSString *themeUnZipPath = [self saveThemeDirBasePath:themeModel.curVersion];__block NSString *curDownloadurl = themeModel.curDownloadurl;//下载成功NSString *afileName = [[NSURL URLWithString:curDownloadurl] lastPathComponent];__block NSString *afilePath = [NSString pathWithComponents:@[saveZipPath, afileName]];[[INHttpClientUtil sharedInstance] downloadFileURL:curDownloadurl savePath:afilePath fileName:afilePath tag:[afilePath hash] downloadProgress:^(CGFloat progress) {} success:^(NSURLResponse *response, NSString *filePath) {//下载成功NSString *fileName = [[NSURL URLWithString:curDownloadurl] lastPathComponent];NSString *selFilePath = [NSString pathWithComponents:@[saveZipPath, fileName]];//准备执行解压方法[self onFileSelected:selFilePath unZipPath:themeUnZipPath];} failure:^(HttpError *e) {NSLog(@"failure request :%@",e);}];} else {//如果存在,直接显示__block NSString *saveZipPath = [self saveThemeTargetBasePath:themeModel.curVersion];__block NSString *themeUnZipPath = [self saveThemeDirBasePath:themeModel.curVersion];__block NSString *curDownloadurl = themeModel.curDownloadurl;//下载成功NSString *fileName = [[NSURL URLWithString:curDownloadurl] lastPathComponent];NSString *filePath = [NSString pathWithComponents:@[saveZipPath, fileName]];//准备执行解压方法[self unzipCompltion:themeUnZipPath];}
2.2 解压zip主题包
将下载的主题包解压,zip包进行解压。
// 解压
- (void)releaseZipFilesWithUnzipFileAtPath:(NSString *)zipPath destination:(NSString *)unzipPath {NSError *error;// 如果解压成功if ([SSZipArchive unzipFileAtPath:zipPath toDestination:unzipPath overwrite:YES password:nil error:&error delegate:self]) {// 存储主题的色调[self unzipCompltion:unzipPath];} else {NSLog(@"%@",error);}
}
解压完成后得到解压的目录。
2.3 获取到解压的目录地址,将配置的json文件转成对应的model
获取到解压的目录地址,将配置的json文件转成对应的model
/**调用解压文件@param unzipPath 获取地址*/
- (void)unzipCompltion:(NSString *)unzipPath {// 存储主题的色调// 已经存储主题tabbar图片、navigationbar图片、配置文件等等资源NSArray *folders = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:unzipPath error:NULL];NSString *selectedFilePath = unzipPath;NSString *aPath = [folders lastObject];NSString *fullPath = [unzipPath stringByAppendingPathComponent:aPath];selectedFilePath = fullPath;NSString *configPath = [NSString stringWithFormat:@"%@/config.json",selectedFilePath];NSFileHandle *fh = [NSFileHandle fileHandleForReadingAtPath:configPath];NSData *data = [fh readDataToEndOfFile];NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:[SDJsonUtil dictionaryWithJsonString:jsonStr]];NSLog(@"theme config.json:%@",dict);SDAppThemeConfigViewModel *themeViewModel = [SDAppThemeConfigViewModel themeViewModel:jsonStr];themeViewModel.t_globalImage = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.globalImage];themeViewModel.navigation.t_backgroundImage = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.navigation.backgroundImage];themeViewModel.tabbar.t_backgroundImage = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.backgroundImage];themeViewModel.tabbar.lianlian.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.lianlian.icon];themeViewModel.tabbar.lianlian.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.lianlian.selectedIcon];themeViewModel.tabbar.guangguang.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.guangguang.icon];themeViewModel.tabbar.guangguang.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.guangguang.selectedIcon];themeViewModel.tabbar.message.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.message.icon];themeViewModel.tabbar.message.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.message.selectedIcon];themeViewModel.tabbar.mine.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.mine.icon];themeViewModel.tabbar.mine.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.mine.selectedIcon];//配置全局主题[SDAppThemeManager shareInstance].configViewModel = themeViewModel;[[NSNotificationCenter defaultCenter] postNotificationName:K_APP_THEME_CHANGED object:nil userInfo:nil];
}
之后通知界面切换对应的图片及风格图。
2.4 界面添加通知Observer
界面接收到通知后,更新到对应的图片及颜色。
我这里是就写一个切换Tabbar新年主题风格图片。
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(systemAppThemeChanged:) name:K_APP_THEME_CHANGED object:nil];
切换Tabbar新年主题风格图片
- (void)updateThemeConfig {//主题,可以更改tabbar样式SDAppThemeConfigViewModel *themeConfigViewModel = [SDAppThemeManager shareInstance].configViewModel;UIImage *backgroundImage;if (themeConfigViewModel.tabbar.t_backgroundImage) {backgroundImage = themeConfigViewModel.tabbar.t_backgroundImage;} else {NSString *bgColor = themeConfigViewModel.tabbar.backgroundColor;backgroundImage = [UIImage imageWithColor:[UIColor colorWithHexString:bgColor] size:CGSizeMake(20.0, 20.0)];backgroundImage = [backgroundImage stretchableImageWithLeftCapWidth:backgroundImage.leftCapWidth*0.5 topCapHeight:backgroundImage.topCapHeight*0.5];}self.sdTabbar.bgroundImage = backgroundImage;NSString *showLine = themeConfigViewModel.tabbar.showLine;self.sdTabbar.showLine = [showLine boolValue];self.sdTabbar.lineColor = [UIColor colorWithHexString:themeConfigViewModel.tabbar.lineColor];UIColor *badgeBGColor = [UIColor colorWithHexString:themeConfigViewModel.tabbar.badgeBgColor];SDTabbarItem *homeItem = [self themeTabbarItem:themeConfigViewModel.tabbar.lianlian];homeItem.identifier = @"home";homeItem.badgeColor = badgeBGColor;SDTabbarItem *addressbookItem = [self themeTabbarItem:themeConfigViewModel.tabbar.message];addressbookItem.identifier = @"addressbook";addressbookItem.badgeColor = badgeBGColor;SDTabbarItem *discoveryItem = [self themeTabbarItem:themeConfigViewModel.tabbar.guangguang];discoveryItem.identifier = @"discovery";discoveryItem.badgeColor = badgeBGColor;SDTabbarItem *mineItem = [self themeTabbarItem:themeConfigViewModel.tabbar.mine];mineItem.identifier = @"mine";mineItem.badgeColor = badgeBGColor;[self.sdTabbar updateTabbarStyle:homeItem];[self.sdTabbar updateTabbarStyle:addressbookItem];[self.sdTabbar updateTabbarStyle:discoveryItem];[self.sdTabbar updateTabbarStyle:mineItem];
}- (void)systemAppThemeChanged:(NSNotification *)notification {[self updateThemeConfig];
}- (SDTabbarItem *)themeTabbarItem:(SDAppThemeConfigTabItemViewModel *)itemViewModel {SDTabbarItem *tabbarItem = [[SDTabbarItem alloc] init];tabbarItem.title = itemViewModel.title;tabbarItem.titleColor = [UIColor colorWithHexString:itemViewModel.titleColor];tabbarItem.selectedTitleColor = [UIColor colorWithHexString:itemViewModel.selectedTitleColor];tabbarItem.image = itemViewModel.t_icon;tabbarItem.selectedImage = itemViewModel.t_selectedIcon;return tabbarItem;
}
tabbar的按钮更新:根据对应的identifier切换到对应的图片及颜色配置。
/**更新tabbar样式@param tabbarItem item*/
- (void)updateTabbarStyle:(SDTabbarItem *)tabbarItem {for (UIView *subView in self.subviews) {if ([subView isKindOfClass:[SDTabbarButton class]]) {SDTabbarButton *tabbarButton = (SDTabbarButton *)subView;SDTabbarItem *item = tabbarButton.tabbarItem;if (tabbarItem.identifier && [tabbarItem.identifier isEqualToString:item.identifier]) {//更新tabbar[item copyClone:tabbarItem];tabbarButton.tabbarItem = item;break;}}}
}
三、将model序列化存储到本地目录
将主题数据序列号存储到本地目录,方便下次打开APP进行获取。
SDAppThemeConfigDbManager.h
#import <Foundation/Foundation.h>
#import "SDAppThemeManager.h"@interface SDAppThemeConfigDbManager : NSObject+ (id)shareInstance;- (SDAppThemeViewModel *)getAppThemeViewModelFromDb;- (void)saveAppThemeViewModelToDb:(SDAppThemeViewModel *)info;@end
SDAppThemeConfigDbManager.m
#import "SDAppThemeConfigDbManager.h"static NSString *appThemeConfigPath = @"sdAppThemeConfigPath";
static SDAppThemeConfigDbManager *instance = nil;@implementation SDAppThemeConfigDbManager+ (id)shareInstance
{static dispatch_once_t predicate;dispatch_once(&predicate,^{instance = [[self alloc] init];});return instance;
}- (NSString *)getAppThemeConfigPath
{NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);NSString *documentPath = [paths objectAtIndex:0];NSString *path = [documentPath stringByAppendingPathComponent:appThemeConfigPath];return path;
}- (SDAppThemeViewModel *)getAppThemeViewModelFromDb {NSString *dataFile = [self getAppThemeConfigPath];@try {SDAppThemeViewModel *viewModel = [NSKeyedUnarchiver unarchiveObjectWithFile:dataFile];if (viewModel) {return viewModel;}} @catch (NSException *e) {}return nil;
}- (void)saveAppThemeViewModelToDb:(SDAppThemeViewModel *)info {NSData *data = [NSKeyedArchiver archivedDataWithRootObject:info];NSString *dataFile = [self getAppThemeConfigPath];BOOL isSave = [data writeToFile:dataFile atomically:YES];if (isSave) {NSLog(@"存储成功");} else {NSLog(@"存储失败");}
}@end
四、完整实现代码
- 需要用到主题Manager:SDAppThemeManager
SDAppThemeManager.h
#import <Foundation/Foundation.h>
//#import "SDThemeConfigRequest.h"
#import "SDAppThemeConfigViewModel.h"/**获取的app主题model,app主题颜色版本号*/
@interface SDAppThemeViewModel : NSObject<NSCoding>@property (nonatomic, strong) NSString *curDownloadurl; //当前版本的下载地址
@property (nonatomic, strong) NSString *curVersion; //当前app主题颜色版本号@property (nonatomic, strong) NSString *nextDownloadurl; //下一版本的下载地址
@property (nonatomic, strong) NSString *nextVersion; //下一版本app主题颜色版本号@end@interface SDAppThemeManager : NSObject+ (instancetype)shareInstance;@property (nonatomic, strong) SDAppThemeConfigViewModel *configViewModel; //当前版本控制文件/**从服务器端加载APP主题接口*/
- (void)loadAppThemeConfig;/**加载系统主题资源*/
- (void)loadCacheThemeResource;@end
SDAppThemeManager.m
#import "SDAppThemeManager.h"
#import "SDAppThemeConfigDbManager.h"
#import "SDAppThemeDownloadManager.h"
#import "INHttpClientUtil.h"@implementation SDAppThemeViewModel- (id)init {self = [super init];if (self) {}return self;
}- (id)initWithCoder:(NSCoder *)aDecoder
{self = [super init];if (self) {self.curDownloadurl = [aDecoder decodeObjectForKey:@"kAppThemeCurDownloadurl"];self.curVersion = [aDecoder decodeObjectForKey:@"kAppThemeCurVersion"];self.nextDownloadurl = [aDecoder decodeObjectForKey:@"kAppThemeNextDownloadurl"];self.nextVersion = [aDecoder decodeObjectForKey:@"kAppThemeNextVersion"];}return self;
}- (void)encodeWithCoder:(NSCoder *)aCoder
{[aCoder encodeObject:_curDownloadurl forKey:@"kAppThemeCurDownloadurl"];[aCoder encodeObject:_curVersion forKey:@"kAppThemeCurVersion"];[aCoder encodeObject:_nextDownloadurl forKey:@"kAppThemeNextDownloadurl"];[aCoder encodeObject:_nextVersion forKey:@"kAppThemeNextVersion"];
}- (void)clear {self.curDownloadurl = nil;self.curVersion = nil;self.nextDownloadurl = nil;self.nextVersion = nil;
}@endstatic SDAppThemeManager *shareInstance = nil;@implementation SDAppThemeManager+ (instancetype)shareInstance {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{shareInstance = [[SDAppThemeManager alloc] init];shareInstance.configViewModel = [SDAppThemeConfigViewModel defautThemeViewModel];});return shareInstance;
}/**从服务器端加载APP主题接口*/
- (void)loadAppThemeConfig {[[INHttpClientUtil sharedInstance] getWithClientType:HttpClientTypeDefault url:@"/v1/api/theme/system" params:nil success:^(id responseObj) {NSString *code = [NSString stringWithFormat:@"%@",responseObj[@"code"]];if ([@"0" isEqualToString:code] && responseObj[@"data"]) {NSString *curDownloadurl = responseObj[@"data"][@"curDownloadurl"];NSString *curVersion = responseObj[@"data"][@"curVersion"];NSString *nextDownloadurl = responseObj[@"data"][@"nextDownloadurl"];NSString *nextVersion = responseObj[@"data"][@"nextVersion"];SDAppThemeViewModel *themeViewModel = [[SDAppThemeViewModel alloc] init];themeViewModel.curDownloadurl = nextDownloadurl;themeViewModel.curVersion = @"2016.10.27";themeViewModel.nextDownloadurl = nextDownloadurl;themeViewModel.nextVersion = nextVersion;[[SDAppThemeConfigDbManager shareInstance] saveAppThemeViewModelToDb:themeViewModel];[[SDAppThemeDownloadManager shareInstance] downloadThemeZipPackage:themeViewModel];}} failure:^(HttpError *e) {DLog(@"request:%@",e);}];
}/**加载系统主题资源*/
- (void)loadCacheThemeResource {[[SDAppThemeDownloadManager shareInstance] loadCacheThemeResource];
}@end
- 需要用到主题下载类SDAppThemeDownloadManager
SDAppThemeDownloadManager.h
#import <Foundation/Foundation.h>
//#import "SDThemeConfigRequest.h"
#import "SDAppThemeManager.h"
#import "SDAppThemeConfigViewModel.h"
#import "SDAppThemeConfigDbManager.h"#define K_APP_THEME_CHANGED @"K_APP_THEME_CHANGED"
#define K_DEFAULT_APP_THEME_VERSION @"1.0.0"@interface SDAppThemeDownloadManager : NSObject+ (instancetype)shareInstance;- (void)downloadThemeZipPackage:(SDAppThemeViewModel *)themeModel;/**加载系统主题资源*/
- (void)loadCacheThemeResource;@end
SDAppThemeDownloadManager.m
#import "SDAppThemeDownloadManager.h"
#import "SDJsonUtil.h"
//#import "NSString+ext.h"
#import <SSZipArchive/SSZipArchive.h>
#import "SDAppThemeManager.h"
#import "INHttpClientUtil.h"static SDAppThemeDownloadManager *manager = nil;@interface SDAppThemeDownloadManager () <SSZipArchiveDelegate>@end@implementation SDAppThemeDownloadManager+ (instancetype)shareInstance {static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{manager = [[SDAppThemeDownloadManager alloc] init];});return manager;
}- (void)downloadThemeZipPackage:(SDAppThemeViewModel *)themeModel {//判断当前主题版本号下是否存在资源文件夹BOOL curThemeExist = [self hasAppThemeVersion:themeModel.curVersion];if (!curThemeExist) {//如果不存在,重新下载解压__block NSString *saveZipPath = [self saveThemeTargetBasePath:themeModel.curVersion];__block NSString *themeUnZipPath = [self saveThemeDirBasePath:themeModel.curVersion];__block NSString *curDownloadurl = themeModel.curDownloadurl;//下载成功NSString *afileName = [[NSURL URLWithString:curDownloadurl] lastPathComponent];__block NSString *afilePath = [NSString pathWithComponents:@[saveZipPath, afileName]];[[INHttpClientUtil sharedInstance] downloadFileURL:curDownloadurl savePath:afilePath fileName:afilePath tag:[afilePath hash] downloadProgress:^(CGFloat progress) {} success:^(NSURLResponse *response, NSString *filePath) {//下载成功NSString *fileName = [[NSURL URLWithString:curDownloadurl] lastPathComponent];NSString *selFilePath = [NSString pathWithComponents:@[saveZipPath, fileName]];//准备执行解压方法[self onFileSelected:selFilePath unZipPath:themeUnZipPath];} failure:^(HttpError *e) {NSLog(@"failure request :%@",e);}];} else {//如果存在,直接显示__block NSString *saveZipPath = [self saveThemeTargetBasePath:themeModel.curVersion];__block NSString *themeUnZipPath = [self saveThemeDirBasePath:themeModel.curVersion];__block NSString *curDownloadurl = themeModel.curDownloadurl;//下载成功NSString *fileName = [[NSURL URLWithString:curDownloadurl] lastPathComponent];NSString *filePath = [NSString pathWithComponents:@[saveZipPath, fileName]];//准备执行解压方法[self unzipCompltion:themeUnZipPath];}/*//判断下一主题版本号下是否存在资源文件夹中BOOL nextThemeExist = [self hasAppThemeVersion:themeModel.nextVersion];if (!nextThemeExist) {//如果不存在,重新下载解压__block NSString *saveZipPath = [self saveThemeTargetBasePath:themeModel.nextVersion];[[HttpClient sharedInstance] downloadFileURL:themeModel.curDownloadurl savePath:saveZipPath fileName:saveZipPath tag:[saveZipPath hash] success:^(id responseObj) {//下载成功} failure:^(HttpException *e) {//下载失败}];}*/
}// 解压
- (void)releaseZipFilesWithUnzipFileAtPath:(NSString *)zipPath destination:(NSString *)unzipPath {NSError *error;// 如果解压成功if ([SSZipArchive unzipFileAtPath:zipPath toDestination:unzipPath overwrite:YES password:nil error:&error delegate:self]) {// 存储主题的色调[self unzipCompltion:unzipPath];} else {NSLog(@"%@",error);}
}/**调用解压文件@param unzipPath 获取地址*/
- (void)unzipCompltion:(NSString *)unzipPath {// 存储主题的色调// 已经存储主题tabbar图片、navigationbar图片、配置文件等等资源NSArray *folders = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:unzipPath error:NULL];NSString *selectedFilePath = unzipPath;NSString *aPath = [folders lastObject];NSString *fullPath = [unzipPath stringByAppendingPathComponent:aPath];selectedFilePath = fullPath;NSString *configPath = [NSString stringWithFormat:@"%@/config.json",selectedFilePath];NSFileHandle *fh = [NSFileHandle fileHandleForReadingAtPath:configPath];NSData *data = [fh readDataToEndOfFile];NSString *jsonStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];NSMutableDictionary *dict = [[NSMutableDictionary alloc] initWithDictionary:[SDJsonUtil dictionaryWithJsonString:jsonStr]];NSLog(@"theme config.json:%@",dict);SDAppThemeConfigViewModel *themeViewModel = [SDAppThemeConfigViewModel themeViewModel:jsonStr];themeViewModel.t_globalImage = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.globalImage];themeViewModel.navigation.t_backgroundImage = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.navigation.backgroundImage];themeViewModel.tabbar.t_backgroundImage = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.backgroundImage];themeViewModel.tabbar.lianlian.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.lianlian.icon];themeViewModel.tabbar.lianlian.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.lianlian.selectedIcon];themeViewModel.tabbar.guangguang.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.guangguang.icon];themeViewModel.tabbar.guangguang.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.guangguang.selectedIcon];themeViewModel.tabbar.message.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.message.icon];themeViewModel.tabbar.message.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.message.selectedIcon];themeViewModel.tabbar.mine.t_icon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.mine.icon];themeViewModel.tabbar.mine.t_selectedIcon = [self imageWithDocumentoryName:[NSString stringWithFormat:@"%@",selectedFilePath] imageName:themeViewModel.tabbar.mine.selectedIcon];//配置全局主题[SDAppThemeManager shareInstance].configViewModel = themeViewModel;[[NSNotificationCenter defaultCenter] postNotificationName:K_APP_THEME_CHANGED object:nil userInfo:nil];
}/**准备执行解压方法@param selectedPath 原先文件路径@param unZipPath 解压文件路径*/
- (void)onFileSelected:(NSString *)selectedPath unZipPath:(NSString *)unZipPath {NSURL *fileURL = [NSURL fileURLWithPath:selectedPath];NSString *fileNameComponent = fileURL.lastPathComponent;// 获取文件的扩展名NSString *extension = [[fileNameComponent pathExtension] lowercaseString];// 如果是zip类型的压缩包文件,则进行解压if ([extension isEqualToString:@"zip"]) {// 设置解压路径[self releaseZipFilesWithUnzipFileAtPath:selectedPath destination:unZipPath];}
}/**判断当前path路径是否存在@param themeVersion 主题版本号@return 是否文件*/
- (BOOL)hasAppThemeVersion:(NSString *)themeVersion {NSString *pathOfLibrary = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];NSString *path = [pathOfLibrary stringByAppendingPathComponent:[NSString stringWithFormat:@"dftheme-%@",themeVersion]];NSArray *folders = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:path error:NULL];if (!(folders && folders.count > 0)) {return NO;}NSString *aPath = [folders lastObject];NSString *fullPath = [path stringByAppendingPathComponent:aPath];NSFileManager *fileManager = [NSFileManager defaultManager];BOOL result = [fileManager fileExistsAtPath:fullPath];return result;
}/**主题未解压下载目录@param themeVersion 主题版本号@return 最后path*/
- (NSString *)saveThemeTargetBasePath:(NSString *)themeVersion {NSString *pathOfLibrary = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];NSString *path = [pathOfLibrary stringByAppendingPathComponent:[NSString stringWithFormat:@"dfThemesZip-%@",themeVersion]];[self createDirectory:path];return path;
}/**主题解压目录@param themeVersion 主题版本号@return 最后path*/
- (NSString *)saveThemeDirBasePath:(NSString *)themeVersion {NSString *pathOfLibrary = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];NSString *path = [pathOfLibrary stringByAppendingPathComponent:[NSString stringWithFormat:@"dftheme-%@",themeVersion]];[self createDirectory:path];return path;
}- (void)createDirectory:(NSString *)path {NSError *error = nil;[[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YESattributes:nil error:&error];if (error) {NSLog(@"Create directory error: %@", error);}
}/**获取使用存储在沙盒里的图片@param documentoryName 文件目录@param imageName 图片名字@return 图片*/
- (UIImage *)imageWithDocumentoryName:(NSString *)documentoryNameimageName:(NSString *)imageName {// 如果文件名不存在或者文件名为空,则返回空if (!imageName || [imageName isEqualToString:@""]) {return nil;}NSString *imgPath = [documentoryName stringByAppendingPathComponent:[NSString stringWithFormat:@"%@",imageName]];UIImage *image = [UIImage imageWithContentsOfFile:imgPath];if (image) {return image;}return [UIImage imageNamed:imageName];
}/**加载系统主题资源*/
- (void)loadCacheThemeResource {SDAppThemeViewModel *themeVersionViewModel = [[SDAppThemeConfigDbManager shareInstance] getAppThemeViewModelFromDb];if (themeVersionViewModel && ![K_DEFAULT_APP_THEME_VERSION isEqualToString:themeVersionViewModel.curVersion]) {[self downloadThemeZipPackage:themeVersionViewModel];}
}
@end
- 需要用到主题数据:SDAppThemeConfigViewModel
SDAppThemeConfigViewModel.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>/**Navigation主题样式*/
@interface SDAppThemeConfigNavViewModel : NSObject@property (nonatomic, strong) NSString *backgroundColor;
@property (nonatomic, strong) NSString *backgroundImage;@property (nonatomic, strong) UIImage *t_backgroundImage;@property (nonatomic, strong) NSString *btnImageColor;
@property (nonatomic, strong) NSString *btnTitleColor;
@property (nonatomic, strong) NSString *navTitleColor;@property (nonatomic, strong) NSString *showLine;
@property (nonatomic, strong) NSString *lineColor;@end/**单个tab按钮样式*/
@interface SDAppThemeConfigTabItemViewModel : NSObject@property (nonatomic, strong) NSString *title;
@property (nonatomic, strong) NSString *titleColor;
@property (nonatomic, strong) NSString *selectedTitleColor;
@property (nonatomic, strong) NSString *icon;
@property (nonatomic, strong) NSString *selectedIcon;@property (nonatomic, strong) UIImage *t_icon;
@property (nonatomic, strong) UIImage *t_selectedIcon;@end/**tabbar样式*/
@interface SDAppThemeConfigTabViewModel : NSObject@property (nonatomic, strong) NSString *backgroundColor;
@property (nonatomic, strong) NSString *backgroundImage;
@property (nonatomic, strong) NSString *showLine;
@property (nonatomic, strong) NSString *lineColor;
@property (nonatomic, strong) NSString *badgeBgColor;@property (nonatomic, strong) UIImage *t_backgroundImage;@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *lianlian;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *guangguang;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *message;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *shop;
@property (nonatomic, strong) SDAppThemeConfigTabItemViewModel *mine;@end/**将本地的主题config.json转成viewmodel*/
@interface SDAppThemeConfigViewModel : NSObject@property (nonatomic, strong) NSString *globalColor;
@property (nonatomic, strong) NSString *globalImage;
@property (nonatomic, strong) SDAppThemeConfigNavViewModel *navigation;
@property (nonatomic, strong) SDAppThemeConfigTabViewModel *tabbar;@property (nonatomic, strong) UIImage *t_globalImage;+ (SDAppThemeConfigViewModel *)themeViewModel:(NSString *)themeJson;+ (SDAppThemeConfigViewModel *)defautThemeViewModel;@end
SDAppThemeConfigViewModel.m
#import "SDAppThemeConfigViewModel.h"
#import <NSObject+YYModel.h>/**Navigation主题样式*/
@implementation SDAppThemeConfigNavViewModel@end/**单个tab按钮样式*/
@implementation SDAppThemeConfigTabItemViewModel@end/**tabbar样式*/
@implementation SDAppThemeConfigTabViewModel@end/**将本地的主题config.json转成viewmodel*/
@implementation SDAppThemeConfigViewModel+ (SDAppThemeConfigViewModel *)themeViewModel:(NSString *)themeJson {return [SDAppThemeConfigViewModel modelWithJSON:themeJson];
}+ (SDAppThemeConfigViewModel *)defautThemeViewModel {SDAppThemeConfigViewModel *viewModel = [[SDAppThemeConfigViewModel alloc] init];SDAppThemeConfigNavViewModel *navConfigViewModel = [[SDAppThemeConfigNavViewModel alloc] init];navConfigViewModel.backgroundColor = @"171013";navConfigViewModel.btnImageColor = @"ffffff";navConfigViewModel.btnTitleColor = @"ffffff";navConfigViewModel.navTitleColor = @"ffffff";viewModel.navigation = navConfigViewModel;return viewModel;
}@end
- 主题配置序列化存储本地:SDAppThemeConfigDbManager
SDAppThemeConfigDbManager.h
#import <Foundation/Foundation.h>
#import "SDAppThemeManager.h"@interface SDAppThemeConfigDbManager : NSObject+ (id)shareInstance;- (SDAppThemeViewModel *)getAppThemeViewModelFromDb;- (void)saveAppThemeViewModelToDb:(SDAppThemeViewModel *)info;@end
SDAppThemeConfigDbManager.m
#import "SDAppThemeConfigDbManager.h"static NSString *appThemeConfigPath = @"sdAppThemeConfigPath";
static SDAppThemeConfigDbManager *instance = nil;@implementation SDAppThemeConfigDbManager+ (id)shareInstance
{static dispatch_once_t predicate;dispatch_once(&predicate,^{instance = [[self alloc] init];});return instance;
}- (NSString *)getAppThemeConfigPath
{NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);NSString *documentPath = [paths objectAtIndex:0];NSString *path = [documentPath stringByAppendingPathComponent:appThemeConfigPath];return path;
}- (SDAppThemeViewModel *)getAppThemeViewModelFromDb {NSString *dataFile = [self getAppThemeConfigPath];@try {SDAppThemeViewModel *viewModel = [NSKeyedUnarchiver unarchiveObjectWithFile:dataFile];if (viewModel) {return viewModel;}} @catch (NSException *e) {}return nil;
}- (void)saveAppThemeViewModelToDb:(SDAppThemeViewModel *)info {NSData *data = [NSKeyedArchiver archivedDataWithRootObject:info];NSString *dataFile = [self getAppThemeConfigPath];BOOL isSave = [data writeToFile:dataFile atomically:YES];if (isSave) {NSLog(@"存储成功");} else {NSLog(@"存储失败");}
}@end
至此,实现获取下载主题配置更切换主题的代码实现完成。
五、小结
iOS开发-实现获取下载主题配置更切换主题,主要是通过请求服务端配置的主题配置、下载主题、解压保存到本地。通知界面获取对应的图片及颜色等。
学习记录,每天不停进步。
相关文章:

iOS开发-实现获取下载主题配置动态切换主题
iOS开发-实现获取下载主题配置动态切换主题 iOS开发-实现获取下载主题配置更切换主题,主要是通过请求服务端配置的主题配置、下载主题、解压保存到本地。通知界面获取对应的图片及颜色等。 比如新年主题风格,常见的背景显示红色氛围图片、tabbar显示新…...
react经验4:动态组件
什么是动态组件? 在页面的一小块区域切换显示不同的组件 实现方法 1.声明示例组件 //写在component1.tsx中 const Component1()>{return (<div>组件1</div>) } //写在component2.tsx中 const Component2()>{return (<div>组件2</div…...

Java maven的下载解压配置(保姆级教学)
mamen基本概念 Maven项目对象模型(POM),可以通过一小段描述信息来管理项目的构建,报告和文档的项目管理工具软件。 Maven 除了以程序构建能力为特色之外,还提供高级项目管理工具。由于 Maven 的缺省构建规则有较高的可重用性,所以…...

Java课题笔记~数据库连接池
一、数据库连接池 1.1 数据库连接池简介 数据库连接池是个容器,负责分配、管理数据库连接(Connection) 它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个; 释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数…...
设计模式-单例模式
文章目录 单例模式饿汉式单例懒汉式单例懒汉式加锁单例双重锁校验单例静态内部类单例枚举单例 单例模式 单例模式主要是确保一个类在任何情况下都只有一个实例,并提供一个全局访问的点。 主要有以下几种 饿汉式单例 /*** 饿汉式* 类加载到内存后,就实…...
golang mysql
驱动 "github.com/go-sql-driver/mysql"使用到的方法 func sql.Open(driverName string, dataSourceName string) (*sql.DB, error) func (*sql.DB).Prepare(query string) (*sql.Stmt, error)//使用DB.Prepare预编译并使用参数化查询,对预编译的SQL语句…...

uniapp使用echarts
uniapp使用echarts 1.下载资源包2.引入资源包3.代码示例注意事项 1.下载资源包 https://echarts.apache.org/zh/download.html 2.引入资源包 将资源包放入项目内 3.代码示例 <template><div style"width:100%;height:500rpx" id"line" ref&…...
Python命令模式介绍、使用
一、Python命令模式介绍 Python命令模式(Command Pattern)是一种行为型设计模式,它允许将请求或操作封装在对象中,并将其作为参数传递给调用对象,以在不同的环境中执行相同的请求或操作。 功能: 将请求或…...

#typescript 使用file-saver模块#
场景:前端使用file-saver模块做导出文档的时候,出现两个错误 1:npm run build 提示找不到模块,如图 解决方法: 先卸载,不管是否安装都先要卸载 ,然后安装: npm uninstall file-saver npm…...

移动端适配布局rem和vw
在日益发展的移动互联网时代,作为前端开发者,我们必须了解和掌握各种移动端显示效果的适配技术。在众多适配方案中,使用rem和vw进行布局是当前最为流行和普遍使用的两种技术。通过合理运用这两种技术,我们可以让我们的网页在不同尺…...

【Java基础教程】(四十八)集合体系篇 · 上:全面解析 Collection、List、Set常用子接口及集合元素迭代遍历方式~【文末送书】
Java基础教程之集合体系 上 🔹本章学习目标1️⃣ 类集框架介绍2️⃣ 单列集合顶层接口:Collection3️⃣ List 子接口3.1 ArrayList 类🔍 数组(Array)与列表(ArrayList)有什么区别?3.2 LinkedL…...

什么是 DNS ANAME 解析?
本人使用谷歌搜索了简中互联网,完全没有找到任何有关 ANAME 的文章……本文该不会是头一份吧 相信大家对于 DNS 的解析方式都不陌生,常见的有 A、CNAME、MX、TXT 记录等等。其中,网站常用的是 A 记录和 CNAME 记录:A 记录用于将域…...

Neo4j 集群和负载均衡
Neo4j 集群和负载均衡 Neo4j是当前最流行的开源图DB。刚好读到了Neo4j的集群和负载均衡策略,记录一下。 1 集群 Neo4j 集群使用主从复制实现高可用性和水平读扩展。 1.1 复制 集群的写入都通过主节点协调完成的,数据先写入主机,再同步到…...
go web框架 gin-gonic源码解读01————Engine
go web框架 gin-gonic源码解读01————Engine gin-gonic是go语言开发的轻量级web框架,性能优异,代码简洁,功能强大。有很多值得学习的地方,最近准备把这段时间学习gin的知识点,通过engine,context,router…...

windows版docker部署springcloud项目
材料: 1.windows版docker环境(其他版教程可能道理一样但是比如文件后坠名上可能有差异) 2.运行好的数据库容器(实现教程) 3.所有jar包 实现: 最后整好的文件夹结构图(原工程文件机密…...

探索工程机械远程控制新纪元:Intewell-Hyper II震撼发布!
在当前的工程技术领域,远程控制技术以其卓越的效率和方便性,正受到越来越多的关注和运用。而在这个过程中,某机械集团以Intewell-HyperII操作系统为基础,打造出了具有前瞻性的工程机械远程控制器,为行业的发展提供了新…...
DM8 DSC集群实时主备搭建
1、环境准备 主库DSC集群公网ip:192.168.1.34/35 私有ip:192.168.10.134/135 备库ip:192.168.1.33 2、对DSC集群数据库全备 1)主库做全备 [dmdbadmdsc01 bin]$ disql sysdba/dameng123 BACKUP DATABASE TO WEEKLY_FULL_BAK BACKUPSE…...

配置IPv4 over IPv6隧道示例
IPv4 over IPv6隧道: 在IPv4 Internet向IPv6 Internet过渡后期,IPv6网络被大量部署后,而IPv4网络只是散布在世界各地的一些孤岛。利用隧道技术可以在IPv6网络上创建隧道,从而实现IPv4孤岛的互联,IPv4孤岛能通过IPv6公…...

在中国区部署日志通2.0
前提条件 一个域名:使用此域名来访问日志通控制台提供aws iam 的ssl证书 ,而且必须跟域名相关联具有四个子网(两个公有子网和两个私有子网)和NAT网关的VPC 步骤 1.创建ACM证书 1.1 请求公有证书 1.2 配置域名 1.3 新申请的证书记…...
centos下安装jdk
环境:centos7/openjdk-8u40-b25 openJDK页面 java二进制包下载页面 华为jdk镜像 1.下载安装包后上传到服务器上,运行命令解压到/opt/目录下 tar cxvf server-jre-8u271-linux-x64.tar.gz -C /opt/2.配置环境变量 vi /etc/profile source /etc/profile添加下面的…...

Linux相关概念和易错知识点(42)(TCP的连接管理、可靠性、面临复杂网络的处理)
目录 1.TCP的连接管理机制(1)三次握手①握手过程②对握手过程的理解 (2)四次挥手(3)握手和挥手的触发(4)状态切换①挥手过程中状态的切换②握手过程中状态的切换 2.TCP的可靠性&…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...

Psychopy音频的使用
Psychopy音频的使用 本文主要解决以下问题: 指定音频引擎与设备;播放音频文件 本文所使用的环境: Python3.10 numpy2.2.6 psychopy2025.1.1 psychtoolbox3.0.19.14 一、音频配置 Psychopy文档链接为Sound - for audio playback — Psy…...
Redis的发布订阅模式与专业的 MQ(如 Kafka, RabbitMQ)相比,优缺点是什么?适用于哪些场景?
Redis 的发布订阅(Pub/Sub)模式与专业的 MQ(Message Queue)如 Kafka、RabbitMQ 进行比较,核心的权衡点在于:简单与速度 vs. 可靠与功能。 下面我们详细展开对比。 Redis Pub/Sub 的核心特点 它是一个发后…...

sipsak:SIP瑞士军刀!全参数详细教程!Kali Linux教程!
简介 sipsak 是一个面向会话初始协议 (SIP) 应用程序开发人员和管理员的小型命令行工具。它可以用于对 SIP 应用程序和设备进行一些简单的测试。 sipsak 是一款 SIP 压力和诊断实用程序。它通过 sip-uri 向服务器发送 SIP 请求,并检查收到的响应。它以以下模式之一…...

排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...

MacOS下Homebrew国内镜像加速指南(2025最新国内镜像加速)
macos brew国内镜像加速方法 brew install 加速formula.jws.json下载慢加速 🍺 最新版brew安装慢到怀疑人生?别怕,教你轻松起飞! 最近Homebrew更新至最新版,每次执行 brew 命令时都会自动从官方地址 https://formulae.…...

【从零开始学习JVM | 第四篇】类加载器和双亲委派机制(高频面试题)
前言: 双亲委派机制对于面试这块来说非常重要,在实际开发中也是经常遇见需要打破双亲委派的需求,今天我们一起来探索一下什么是双亲委派机制,在此之前我们先介绍一下类的加载器。 目录 编辑 前言: 类加载器 1. …...
Python 训练营打卡 Day 47
注意力热力图可视化 在day 46代码的基础上,对比不同卷积层热力图可视化的结果 import torch import torch.nn as nn import torch.optim as optim from torchvision import datasets, transforms from torch.utils.data import DataLoader import matplotlib.pypl…...