你真的了解UIApplication吗?

Posted TabWu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了你真的了解UIApplication吗?相关的知识,希望对你有一定的参考价值。

一:首先查看一下关于UIApplication的定义

NS_CLASS_AVAILABLE_ios(2_0) @interface UIApplication : UIResponder

//获得单例对象
+ (UIApplication *)sharedApplication NS_EXTENSION_UNAVAILABLE_IOS("Use view controller based solutions where appropriate instead.");

//委托
@property(nullable, nonatomic,assign) id<UIApplicationDelegate> delegate;

//暂停触摸事件
- (void)beginIgnoringInteractionEvents NS_EXTENSION_UNAVAILABLE_IOS("");             

// 告诉接受者继续处理 touch相关的事件
- (void)endIgnoringInteractionEvents NS_EXTENSION_UNAVAILABLE_IOS("");

 // 是否忽略交互事件
- (BOOL)isIgnoringInteractionEvents;                 

//阻止屏幕变暗进入休眠状态 ,耗电,慎重默认NO
@property(nonatomic,getter=isIdleTimerDisabled)       BOOL idleTimerDisabled;

// 通过特定的URL中打开资源
- (BOOL)openURL:(NSURL*)url NS_EXTENSION_UNAVAILABLE_IOS("");
 // 返回一个bool值, 是否从已经安装的 apps 中跳转
- (BOOL)canOpenURL:(NSURL *)url NS_AVAILABLE_IOS(3_0);

 // 发送事件给app内适用的响应者
- (void)sendEvent:(UIEvent *)event;

 // app的主 window 只读
@property(nullable, nonatomic,readonly) UIWindow *keyWindow;

// 隐藏的和看得见的所有 window
@property(nonatomic,readonly) NSArray<__kindof UIWindow *>  *windows;

 // 发送一个含选择器的动作消息到指定的目标
- (BOOL)sendAction:(SEL)action to:(nullable id)target from:(nullable id)sender forEvent:(nullable UIEvent *)event;

// 是否显示网络正在活动,默认是NO
@property(nonatomic,getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible; 
//状态栏样式
@property(readonly, nonatomic) UIStatusBarStyle statusBarStyle; // default is UIStatusBarStyleDefault
//状态栏隐藏
@property(readonly, nonatomic,getter=isStatusBarHidden) BOOL statusBarHidden;
//屏幕旋转方向
@property(readonly, nonatomic) UIInterfaceOrientation statusBarOrientation;

// 在指定的窗口中, 返回默认的视图控制器方向接口
- (UIInterfaceOrientationMask)supportedInterfaceOrientationsForWindow:(nullable UIWindow *)window NS_AVAILABLE_IOS(6_0);

// 状态栏动画持续时间
@property(nonatomic,readonly) NSTimeInterval statusBarOrientationAnimationDuration; 

// 获取状态栏的 rect
@property(nonatomic,readonly) CGRect statusBarFrame; 

// 未读消息数字,0表示隐藏
@property(nonatomic) NSInteger applicationIconBadgeNumber;  

// 是否接受摇晃的时候, 展现 撤销和恢复 视图
@property(nonatomic) BOOL applicationSupportsShakeToEdit NS_AVAILABLE_IOS(3_0);
// app当前的运行的状态
@property(nonatomic,readonly) UIApplicationState applicationState NS_AVAILABLE_IOS(4_0);
// app 在后台运行的时间
@property(nonatomic,readonly) NSTimeInterval backgroundTimeRemaining NS_AVAILABLE_IOS(4_0);

//标记开始新的长时间运行的后台任务
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void(^ __nullable)(void))handler  NS_AVAILABLE_IOS(4_0) NS_REQUIRES_SUPER;

// 标记新的长时间运行的任务以及指定任务的命名
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithName:(nullable NSString *)taskName expirationHandler:(void(^ __nullable)(void))handler NS_AVAILABLE_IOS(7_0) NS_REQUIRES_SUPER;
// 结束指定的长时间的后台任务
- (void)endBackgroundTask:(UIBackgroundTaskIdentifier)identifier NS_AVAILABLE_IOS(4_0) NS_REQUIRES_SUPER;

// 指定最小时间间隔在后台获取操作
- (void)setMinimumBackgroundFetchInterval:(NSTimeInterval)minimumBackgroundFetchInterval NS_AVAILABLE_IOS(7_0);

//进入到后台,是否能够进行后台的操作
@property (nonatomic, readonly) UIBackgroundRefreshStatus backgroundRefreshStatus NS_AVAILABLE_IOS(7_0);

@property(nonatomic,readonly,getter=isProtectedDataAvailable) BOOL protectedDataAvailable NS_AVAILABLE_IOS(4_0);

// 返回用户界面的布局方向。只读
@property(nonatomic,readonly) UIUserInterfaceLayoutDirection userInterfaceLayoutDirection NS_AVAILABLE_IOS(5_0);

// 字体偏好 只读
@property(nonatomic,readonly) NSString *preferredContentSizeCategory NS_AVAILABLE_IOS(7_0);

@end

UIApplication的核心作用是提供了iOS程序运行期间的控制和协作工作。它的基类是UIResponder;每一个程序在运行期必须有且仅有一个UIApplication(或则其子类)的一个实例;在程序开始运行的时候,UIApplicationMain函数是程序进入点,这个函数做了很多工作,其中一个重要的工作就是创建一个UIApplication的单例实例。在你的代码中你,你可以通过调用[UIApplication sharedApplication]来得到这个单例实例的指针。UIApplication的一个主要工作是处理用户事件,它会维护一个队列,把所有用户事件都放入队列,逐个处理,在处理的时候,它会发送当前事件到一个合适的处理事件的目标控件。此外,UIApplication实例还维护一个在本应用中打开的window列表(UIWindow实例),这样它就可以接触应用中的任何一个UIView对象。UIApplication实例会被赋予一个代理对象,以处理应用程序的生命周期事件(比如程序启动和关闭)、系统事件(比如来电、记事项警告)等等。

知识点1:属性的运用

   //通过sharedApplication获取该程序的UIApplication对象
    UIApplication *app=[UIApplication sharedApplication];
    app.applicationIconBadgeNumber=100;

知识点2:关于openURL的运用

/*
NSURL统一资源定位符  格式 > 协议://路径
*/
// 创建UIApplication对象
UIApplication  *app = [UIApplication sharedApplication];

// 打电话 tel为打电话协议
[app openURL:[NSURL URLWithString:@"tel://10086"]];

// 发短信 sms为发短信协议
[app openURL:[NSURL URLWithString:@"sms://10086"]];

// 打开网址 http为上网协议
[app openURL:[NSURL URLWithString:@"http://www.ithemima.com"]];

// 发送邮件 mailto为发送邮件协议
[app openURL:[NSURL URLWithString:@"mailto://zhangsan@itcast.cn"]];

知识点3:状态栏的管理从iOS7开始,系统提供了2种管理状态栏的方式

a: 通过UIViewController管理(每一个UIViewController都可以拥有自己不同的状态栏)

b: 通过UIApplication管理(一个应用程序的状态栏都由它统一管理)

在iOS7之后,默认情况下,状态栏都是由UIViewController管理的,若想通过UIApplication进行管理,则需要配置plist文件:View controller-based status bar appearance 设置成NO (默认值为YES)

// 示范代码:
// 隐藏系统状态栏
[UIApplication sharedApplication].statusBarHidden = YES;
// 设置系统状态栏样式
[UIApplication sharedApplication].statusBarStyle = UIStatusBarStyleLightContent;

// 隐藏系统状态栏带动画
[[UIApplication sharedApplication] setStatusBarHidden:YES withAnimation:UIStatusBarAnimationSlide];
// 设置系统状态栏样式带动画
[[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES];

二:UIApplication (UIRemoteNotifications)分类,处理远程通知

@interface UIApplication (UIRemoteNotifications)

//在iOS8中,我们使用新的函数来注册通知
- (void)registerForRemoteNotifications NS_AVAILABLE_IOS(8_0);

//关闭推送
- (void)unregisterForRemoteNotifications NS_AVAILABLE_IOS(3_0);

//获取本地推送授权状态
- (BOOL)isRegisteredForRemoteNotifications NS_AVAILABLE_IOS(8_0);

//授权状态的枚举类型
//UIUserNotificationTypeNone 无授权
//UIUserNotificationTypeBadge 更新APP图标角标
//UIUserNotificationTypeSound 播放声音
//UIUserNotificationTypeAlert     屏幕中间弹出一个UIAlertView
- (void)registerForRemoteNotificationTypes:(UIRemoteNotificationType)types NS_DEPRECATED_IOS(3_0, 8_0, "Please use registerForRemoteNotifications and registerUserNotificationSettings: instead");

//获取通知中心 是否 允许程序通知消息的值。
- (UIRemoteNotificationType)enabledRemoteNotificationTypes NS_DEPRECATED_IOS(3_0, 8_0, "Please use -[UIApplication isRegisteredForRemoteNotifications], or -[UIApplication currentUserNotificationSettings] to retrieve user-enabled remote notification and user notification settings");

@end

知识点1:授权的方法实例

UIUserNotificationType type = UIUserNotificationTypeBadge | UIUserNotificationTypeAlert | UIUserNotificationTypeSound;
UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:type categories:nil];
[[UIApplication sharedApplication] registerUserNotificationSettings:setting];

知识点2:远程推送通知实现的条件

所有的苹果设备,在联网状态下,都会和苹果服务器APNs建立一个长连接;远程推送通知就是借助苹果设备与APNs服务器之间的长连接,借助APNs服务器讲消息发送给客户端。远程推送通知实现的条件,必须有真机,只有真机具备UDID,才能生成deviceToken设备令牌(deviceToken的生成算法只有Apple掌握,为了确保算法发生变化后仍然能够正常接收服务器端发送的通知,每次应用程序启动都重新获得deviceToken);需要开发推送Cer证书;

知识点3:远程推送通知步骤:

1:iOS8以后,使用远程通知,需要请求用户授权
2:注册远程通知成功后会调用以下方法,获取deviceToken设备令牌:
-(void)application:(UIApplication *)application 
       didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken;
3:把deviceToken设备令牌发送给服务器,时刻保持deviceToken是最新的
4:监听远程推送通知:
-(void)application:(UIApplication *)application 
       didReceiveRemoteNotification:(NSDictionary *)userInfo;

知识点4:判断是否打开推送 IOS7跟IOS8也是有区别

if ([[UIDevice currentDevice].systemVersion floatValue]>=8.0f) {

UIUserNotificationSettings *setting = [[UIApplication sharedApplication] currentUserNotificationSettings];

if (UIUserNotificationTypeNone == setting.types) {
NSLog(@"推送关闭 8.0");
}
else
{
NSLog(@"推送打开 8.0");
}
}
else
{
UIRemoteNotificationType type = [[UIApplication sharedApplication] enabledRemoteNotificationTypes];

if(UIRemoteNotificationTypeNone == type){
NSLog(@"推送关闭");
}
else
{
NSLog(@"推送打开");
}
}

知识点5:IOS7跟IOS8关于注册通知是有差异

@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    // Override point for customization after application launch.

    //首次打开应用,跳转登录界面


    //登录成功,跳转主界面
    [self LoadMainView];

    //注册远程通知
    if ([[UIDevice currentDevice].systemVersion floatValue] < 8.0)
    {
        UIRemoteNotificationType type = UIRemoteNotificationTypeAlert | UIRemoteNotificationTypeBadge | UIRemoteNotificationTypeSound;

        [application registerForRemoteNotificationTypes:type];

    }
    else
    {
        UIUserNotificationType type = UIUserNotificationTypeAlert | UIUserNotificationTypeBadge | UIUserNotificationTypeSound;

        UIUserNotificationSettings *setting = [UIUserNotificationSettings settingsForTypes:type categories:nil];

        [application registerUserNotificationSettings:setting];

    }


    return YES;
}

#pragma mark 注册远程通知代理方法,返回deviceToken

#ifdef __IPHONE_8_0
- (void)application:(UIApplication *)application didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
    //iOS8之后注册远程通知需要实现代理方法:
    [application registerForRemoteNotifications];
}

- (void)application:(UIApplication *)application handleActionWithIdentifier:(NSString *)identifier forRemoteNotification:(NSDictionary *)userInfo completionHandler:(void(^)())completionHandler
{
    //handle the actions
    if ([identifier isEqualToString:@"declineAction"]){
    }
    else if ([identifier isEqualToString:@"answerAction"]){
    }
}
#endif

- (void)application:(UIApplication *)application didRegisterForRemoteNotificationsWithDeviceToken:(NSData *)deviceToken
{
    NSString* newToken = [[[NSString stringWithFormat:@"%@",deviceToken]
                           stringByTrimmingCharactersInSet:[NSCharacterSet characterSetWithCharactersInString:@"<>"]] stringByReplacingOccurrencesOfString:@" " withString:@""];
    NSLog(@"nsdata:%@\\n 字符串token: %@",deviceToken, newToken);// 获取device token
    //将token发送给服务器
}

- (void)application:(UIApplication *)application didFailToRegisterForRemoteNotificationsWithError:(NSError *)error
{
    NSLog(@"RegistFail %@",error);
}

- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler
{
     //接收通知内容
}

三:UIApplication (UILocalNotifications)分类 处理本地通知

@interface UIApplication (UILocalNotifications)

//立刻推送,忽略本地通知对象的fireDate设置进行本地推送通知
- (void)presentLocalNotificationNow:(UILocalNotification *)notification NS_AVAILABLE_IOS(4_0);
//延时推送,根据本地通知对象的fireDate设置进行本地推送通知
- (void)scheduleLocalNotification:(UILocalNotification *)notification NS_AVAILABLE_IOS(4_0); 
//取消指定的本地推送通知
- (void)cancelLocalNotification:(UILocalNotification *)notification NS_AVAILABLE_IOS(4_0);
//取消全部本地推送通知
- (void)cancelAllLocalNotifications NS_AVAILABLE_IOS(4_0);
//获取本地推送数组
@property(nullable,nonatomic,copy) NSArray<UILocalNotification *> *scheduledLocalNotifications NS_AVAILABLE_IOS(4_0);         

@end

知识点1:推送通知分为

本地推送通知:

不需要联网,在APP代码中推送的通知,确定知道未来某个时间点应该提醒用户什么【开发人员在APP内部通过代码发生 = 本地推送通知】

远程推送通知:

需要联网,是由服务器推送的通知,不确定未来某个时间点应该提醒用户什么【服务器可以确定通知时间和内容 = 远程推送通知】

知识点2:本地推送通知步骤

1:在iOS8以后使用本地推送通知,需要得到用户的许可
2:创建UILocalNotification本地通知对象,并设置必要属性
3:开始本地推送通知:
第一种方法,延时推送,根据本地通知对象的fireDate设置进行本地推送通知
[[UIApplication shareApplication] scheduleLocalNotification:notification];

第二种方法,立刻推送,忽略本地通知对象的fireDate设置进行本地推送通知
[[UIApplication shareApplication] presentLocalNotificationNow:notification];

4:监听用户点击通知:
APP处于前台,此时不会弹框通知用户,但会调用对应的代理方法 :
-(void)application:(UIApplication *)application didReceiveLocalNotification;

APP处于后台,屏幕上方会弹出横幅,用户点击横幅后,会进入前台,调用上面的代理方法。

APP已关闭,屏幕上方会弹出横幅,用户点击横幅后,会启动APP,调用以下方法:
-(BOOL)application:(UIApplication *)application 
       didFinishLaunchingWithOptions:(NSDictionary *)launchOptions;
/* 通过参数launchOptions获取本地推送通知内容 */
UILocalNotification *local = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];

5:调用UIApplication的对象方法,取消本地推送通知:
/* 取消指定的本地推送通知 */
-(void)cancelLocalNotification:(UILocalNotification *)notification;
/* 取消全部本地推送通知 */
-(void)cancelAllLocalNotification;

知识点3:实例代码

1. 注册通知代码以及UIAlertView显示通知方法代码

- (BOOL)application:(UIApplication *)application 
        didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
 {
    //因为是storyboard启动,这里就没有其他启动代码了

    //iOS8.0以后,如果需要使用推送通知,需要得到用户许可
    if (application.currentUserNotificationSettings.types == UIUserNotificationTypeNone) {
        //注册通知,有横幅通知、应用数字通知、应用声音通知
        UIUserNotificationSettings * setting = 
              [UIUserNotificationSettings settingsForTypes:UIUserNotificationTypeAlert |
                                                           UIUserNotificationTypeBadge |
                                                           UIUserNotificationTypeSound
                                                categories:nil];
        [application registerUserNotificationSettings:setting];
    } else {
        //当APP关闭后接收到通知,在启动中获取本地推送通知对象
        UILocalNotification *notification = launchOptions[UIApplicationLaunchOptionsLocalNotificationKey];
        [self showLocalNotification:notification];
    }
    return YES;
}
/* 弹框UIAlertView显示本地通知的信息 */
- (void)showLocalNotification:(UILocalNotification *)notification
{
    /* 显示本地通知 */
    NSDictionary *userInfo = notification.userInfo;
    NSString *title = @"本地通知";
    NSString *msg = userInfo[@"msg"];
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title 
                                                    message:msg 
                                                   delegate:nil 
                                          cancelButtonTitle:@"取消" 
                                          otherButtonTitles:@"确定", nil];
    [alert show];
    //移除本地通知
    [[UIApplication sharedApplication] cancelLocalNotification:notification];
}

2. 创建本地通知代码

/* 创建一个本地通知 */
- (UILocalNotification *)makeLocalNotification{
    //创建本地推送通知对象
    UILocalNotification *notification = [[UILocalNotification alloc] init];
    //设置调用时间
    notification.fireDate = [NSDate dateWithTimeIntervalSinceNow:10.0];//通知触发的时间,10s以后
    notification.repeatInterval = NSCalendarUnitMinute;//每隔多久重复发一次本地通知
    //设置通知属性
    notification.alertBody = @"最近添加了诸多有趣的特性,是否立即体验?";//通知主体
    notification.applicationIconBadgeNumber = 1;//应用程序图标右上角显示的消息数
    notification.alertAction = @"打开应用"; //待机界面的滑动动作提示
    notification.alertLaunchImage = @"Default";//通过点击通知打开应用时的启动图片,这里使用程序启动图片
    notification.soundName = UILocalNotificationDefaultSoundName;//收到通知时播放的声音,默认消息声音
    //设置用户信息
    notification.userInfo = @{ @"id":@1, 
                               @"user":@"Kenshin Cui", 
                               @"msg":@"我来了一发本地通知"};//绑定到通知上的其他附加信息
    return notification;
}

如果需要每天的中午12点准时本地推送怎么办呢?就像这么办,修改fireDate和repeatInterval属性

NSDateFormatter *formatter1 = [[NSDateFormatter alloc]init];  
[formatter setDateFormat:@"yyyy-MM-dd HH-mm-sss"];  
NSDate *resDate = [formatter dateFromString:@"2016-04-09 12-00-00"];
notification.fireDate = resDate;//设定为明天中午12点触发通知
//记得设置当前时区,没有设置的话,fireDate将不考虑时区,这样的通知会不准确
notification.timeZone = [NSTimeZone defaultTimeZone];
notification.repeatInterval = NSCalendarUnitDay;//每隔一天触发一次

3:监听用户点击

/* 注册本地通知完成会调用,即用户点击确定授权后调用 */
- (void)application:(UIApplication *)application 
        didRegisterUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings
{
    //在这里我们尝试发送本地推送通知
    if (notificationSettings.types != UIUserNotificationTypeNone) {
        UILocalNotification *notification = [self makeLocalNotification];
        //延迟调用通知
        [application scheduleLocalNotification:notification];
        //立刻发送通知
        //[application presentLocalNotificationNow:notification];
    }
}
/* 应用还在运行,无论前台还是后台,都会调用该方法处理通知 */
- (void)application:(UIApplication *)application 
        didReceiveLocalNotification:(UILocalNotification *)notification
{
    if( notification ) {
        [self showLocalNotification:notification];
    }
}
/* 应用进入前台,去除应用边角数字显示 */
- (void)applicationWillEnterForeground:(UIApplication *)application {
    //去除应用边角数字
    [application setApplicationIconBadgeNumber:0];
}

四:UIApplication (UIUserNotificationSettings)分类 ios8远程通知注册

@class UIUserNotificationSettings;
@interface UIApplication (UIUserNotificationSettings)

// IOS8注册远程通知
- (void)registerUserNotificationSettings:(UIUserNotificationSettings *)notificationSettings NS_AVAILABLE_IOS(8_0);

// IOS8获得当前的通知设置
- (nullable UIUserNotificationSettings *)currentUserNotificationSettings NS_AVAILABLE_IOS(8_0);

@end

五:UIApplication (UIRemoteControlEvents)分类 远程事件开关

@interface UIApplication (UIRemoteControlEvents)

//允许传递远程控制事件
- (void)beginReceivingRemoteControlEvents NS_AVAILABLE_IOS(4_0);
//关闭远程控制
- (void)endReceivingRemoteControlEvents NS_AVAILABLE_IOS(4_0);

@end

结合远程事件的运用;接收到一个远程控制事件。比如耳机控制。允许传递远程控制事件,必须调用UIApplication的beginReceivingRemoteControlEvents方法;关闭远程控制,调用endReceivingRemoteControlEvents。

六:UIApplication (UIStateRestoration)分类 控制状态恢复

@protocol UIStateRestoring;
@interface UIApplication (UIStateRestoration)
// 异步恢复状态
- (void)extendStateRestoration  NS_AVAILABLE_IOS(6_0);
// 结束异步恢复状态
- (void)completeStateRestoration  NS_AVAILABLE_IOS(6_0);
// 阻止应用程序使用最近的快找图像,在接下来的循环中
- (void)ignoreSnapshotOnNextApplicationLaunch NS_AVAILABLE_IOS(7_0);
// 注册自定义对象的使用状态恢复系统
+ (void)registerObjectForStateRestoration:(id<UIStateRestoring>)object restorationIdentifier:(NSString *)restorationIdentifier NS_AVAILABLE_IOS(7_0);
@end

七:UIApplicationDelegate协议

 

//主要方法有:
//应用程序的生命周期
//应用程序启动完成的时候调用
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@"%s",__func__);
return YES;
}

//当我们应用程序即将失去焦点的时候调用
- (void)applicationWillResignActive:(UIApplication *)application {
NSLog(@"%s",__func__);
}

//当我们应用程序完全进入后台的时候调用
- (void)applicationDidEnterBackground:(UIApplication *)application{
NSLog(@"%s",__func__);
}

//当我们应用程序即将进入前台的时候调用
- (void)applicationWillEnterForeground:(UIApplication *)application {
          NSLog(@"%s",__func__);
}

//当我们应用程序完全获取焦点的时候调用
只有当一个应用程序完全获取到焦点,才能与用户交互.
- (void)applicationDidBecomeActive:(UIApplication *)application {
          NSLog(@"%s",__func__);
}

//当我们应用程序即将关闭的时候调用
- (void)applicationWillTerminate:(UIApplication *)application {
          NSLog(@"%s",__func__);
}

 

 

最近有个妹子弄的一个关于扩大眼界跟内含的订阅号,每天都会更新一些深度内容,在这里如果你感兴趣也可以关注一下(嘿对美女跟知识感兴趣),当然可以关注后输入:github 会有我的微信号,如果有问题你也可以在那找到我;当然不感兴趣无视此信息;

以上是关于你真的了解UIApplication吗?的主要内容,如果未能解决你的问题,请参考以下文章

你真的了解低代码平台吗?

你真的了解 sync.Once 吗

你真的对java static了解吗,代码优化可能更加简单

你真的了解URL encode吗?

你真的了解MD5吗?

你真的了解扩展方法吗?