iteatimeteam / Friday-QA

iTeaTime |技术清谈 微信群每周五问答环节
MIT License
229 stars 19 forks source link

iTeaTime(技术清谈)【001期】【代号:海王】 #2

Open ChenYilong opened 5 years ago

ChenYilong commented 5 years ago

iTeaTime(技术清谈)【001期】【代号:海王】



出题:微博@iOS程序犭袁 本期代号:海王



enter image description here


1.【问题】【iOS】请问前后台切换,会发生些什么,系统哪些方法会被调用,viewcontroller哪些方法会被调用

【答案】

在不考虑 APP 在后台被 kill 的情况:

进入后台:

方法 作用
applicationWillResignActive 点击 Home 键,app 开始准备进入后台,
这个时候会进入该回调,意味着 app 被挂起,进程即将失去活跃。
经过不严谨的测试,大约有 10 分钟左右的时间用来处理事务。
applicationDidEnterBackground 当 applicationWillResignActive 回调方法完全执行完毕后,
会进入 applicationDidEnterBackground 。

进入前台:

方法 作用
applicationWillEnterForeground 在 app 未被杀死的情况下,点击 icon 再次进入 app,
重新回到前台之前会先进入 applicationWillEnterForeground 回调
applicationDidBecomeActive applicationWillEnterForeground 执行完毕后,
会进入 applicationDidBecomeActive 回调,正式回归活跃。

前后台切换,主要的坑点在于:VC中并没函数会调用,尤其注意:VC 相关的 Appear 和 Disappear 函数并不会被调用。想在VC中监听切换,只能监听通知,每个在appdelegate的生命代理方法都有对应的通知。

如果考虑 APP 在后台被 kill 的情况:

进入后台后,如果没有后台运行权限及功能,可能在一段时间后被系统 kill 掉,再次进入app后,会重新进入启动流程。

方法 作用
main() 函数: 这个阶段一般是 可执行 .o 文件,动态库加载,objc 类注册,category 类注册,
selector 唯一性检查,+(void)load 方法,C++ 静态全局变量的创建等。
didFinishLaunchingWithOptions 用户点击 icon 启动 app,或者被 kill 后以任何方式进入 app,
在 main() 执行后,会进入 didFinishLaunchingWithOptions 回调,
处理首屏渲染,以及其他业务相关的事件,例如监听事件,
配置文件读写或者 SDK 初始化等等。
applicationDidBecomeActive 在 didFinishLaunchingWithOptions 方法作用域结束后,
会进入 applicationDidBecomeActive 回调,
也正式意味着 app 已经处于活跃状态。
rootViewController 的相关的 Appear 函数 注意:此时 rootViewController 的相关的 Appear 函数会被调用。

参考链接:

标题&链接 手机端阅读
标题:WWDC 2016 - Session 406-Optimizing App Startup Time
链接:https://developer.apple.com/videos/play/wwdc2016/406/

2 【问题】【iOS】请问对无序的Array排序,有什么好的方法,代码越少,API越高级越好。有无原生方法可以办到。

苹果为我们提供了很多 Array 的排序方法,但原理上可以看到就是 Comparator (比较器) 和 Descriptor (描述器) 两种,像是 Selector 和 Function ,最终也是使用 Comparator 在做排序,只是响应方法不同。

其中 Swift 也有方法: array.sort(),见

参考链接:

标题&链接 手机端阅读
标题:Apple Documentation-Swift-Array-sorted
链接:https://developer.apple.com/documentation/swift/array/2296815-sorted

先说说 Comparator ,如果数组中元素是 String 或 Number,首选 Comparator,可以将 compare: 方法的返回值直接作为 NSComparisonResult 返回值。实际的排序代码三行就可以搞定。当然用 Selector 和 Function,也是一样的效果,但需要写更多的代码。

例子一:

NSArray *sortedArray = [array sortedArrayUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
                if ([obj1 compare:obj2] == NSOrderedAscending) {
                    return NSOrderedAscending;
                } else if ([obj1 compare:obj2] == NSOrderedDescending){
                    return NSOrderedDescending;
                }else {
                    return NSOrderedSame;
                }
            }];

例子二:

- (void)arraySortUsingCompare {
    // 比较器 排序

    NSMutableArray *arr = [NSMutableArray array];
    for (int i = 0; i < 10; i ++) {
        int n = arc4random() % (10 - 0) + 1;
        [arr addObject:@(n)];
    }
    NSLog(@"排序前 ===== %@", arr);

    [arr sortUsingComparator:^NSComparisonResult(NSNumber *num1, NSNumber *num2) {
        //        return [num1 compare:num2];  // 正序
        return [num2 compare:num1]; // 倒序

    }];

    NSLog(@"排序后 %@", arr);

    arr = [NSMutableArray array];
    [arr addObject:@"Kobe Bryant"];
    [arr addObject:@"LeBorn James"];
    [arr addObject:@"Steve Nash"];
    [arr addObject:@"Stephen Curry"];
    [arr addObject:@"Monkey D Luffy"];
    [arr addObject:@"Roronoa Zoro"];

    NSLog(@"排序前 ==== %@", arr);

    [arr sortUsingComparator:^NSComparisonResult(NSString *str1, NSString *str2) {
        //        return [str1 compare:str2];  // 正序
        return [str2 compare:str1]; // 倒序
    }];

    NSLog(@"排序后 %@", arr);
}

参考链接:

标题&链接 手机端阅读
标题: 《Objective-C中的排序及Compare陷阱》
链接:https://blog.csdn.net/u011883764/article/details/38868097

但是如果需要针对一个对象的几个属性作为不同的维度去做排序,那选择 Descriptor,因为不需要根据利用属性对排序优先级写一大堆的逻辑判断。主要将所有参与比较的属性都放入描述器中即可,如果想对球员的年龄和号码(优先级分先后)进行排序,只需要依次加入描述器组,三行代码就可以完成。

- (void)arraySortUsingDescriptor {
    NSMutableArray *arr = [NSMutableArray array];

    Person *person = [[Person alloc] init];
    person.name = @"Ingram";
    person.age = 21;
    person.number = 14;

    [arr addObject:person];

    person = [[Person alloc] init];
    person.name = @"Ball";
    person.age = 21;
    person.number = 2;

    [arr addObject:person];

    person = [[Person alloc] init];
    person.name = @"Zubac";
    person.age = 21;
    person.number = 15;

    [arr addObject:person];

    NSSortDescriptor *ageDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"age" ascending:YES];
    NSSortDescriptor *numberDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"number" ascending:YES];
    [arr sortUsingDescriptors:@[numberDescriptor, ageDescriptor]];

    for (Person *person in arr) {
        NSLog(@"\n 球员姓名: %@ \n 球员号码: %d \n 球员年龄: %d \n -------- \n", person.name, person.number, person.age);

    }
}

3【问题】【iOS】请问APNs推送如何区分设备,如何将设备的信息传给Apple,你上传的时机时怎样的,猜想这个设备信息是如何生成的

【答案】

【设备信息传递给apple】 post请求; Use HTTP/2 and TLS 1.2 or later to establish a connection between your provider server and one of the following servers: • Development server: api.sandbox.push.apple.com:443 • Production server: api.push.apple.com:443

也就是:

设备信息是通过一个 POST 请求将 DeveiceToken 和其他信息发送给 APNS,需要用 HTTP/2 和 TLS 1.2 或以上的版本,在自己提供的服务和以上服务之间建立连接。

当然,还可以用一台机器的 2197 端口让 APNS 通过防火墙

请求示例:

HEADERS
  - END_STREAM
  + END_HEADERS
  :method = POST
  :scheme = https
  :path = /3/device/00fc13adff785122b4ad28809a3420982341241421348097878e577c991de8f0
  host = api.sandbox.push.apple.com
  authorization = bearer eyAia2lkIjogIjhZTDNHM1JSWDciIH0.eyAiaXNzIjogIkM4Nk5WOUpYM0QiLCAiaWF0I
     jogIjE0NTkxNDM1ODA2NTAiIH0.MEYCIQDzqyahmH1rz1s-LFNkylXEa2lZ_aOCX4daxxTZkVEGzwIhALvkClnx5m5eAT6
     Lxw7LZtEQcH6JENhJTMArwLf3sXwi
  apns-id = eabeae54-14a8-11e5-b60b-1697f925ec7b
  apns-expiration = 0
  apns-priority = 10
  apns-topic = com.example.MyApp
DATA
  + END_STREAM
  { "aps" : { "alert" : "Hello" } }

【上传时机】didRegisterForRemoteNotificationsWithDeviceToken 方法,回调内处理设备信息上传的业务。但有些情况是,我们希望根据用户账号来做推送,例如即时通讯应用。那么我们就要在登录或自动登录后,上传deviceToken,和用户信息绑定并处理替换逻辑,避免推送错乱。

【设备信息】This address takes the form of a device token unique to both the device and your app.

猜测:UDID+bundleId+生产/开发环境+时间戳。

其中注意带时间戳hash是为什么频繁上传device token的主要原因。长期不活跃app,比如用户一个月或者两个月没打开过该app,该服务器后端就再也推不到了。


4【问题】【前端】js中,this指向性问题如何解决。

【答案】「.bind(this) 或 用箭头函数」「const that = this;」


5【算法】我如果说我每天都在处理昨天和前天产生的bug,那么我是一个什么类型的程序员。

【答案】斐波那契程序员,这个梗可以参考:斐波那契数列。


原文标题 & 原文链接 手机端阅读
标题:《iTeaTime(技术清谈)【001期】【代号:海王】》
链接:https://github.com/iteatimeteam/Friday-QA/issues/2

Posted by 微博@iOS程序犭袁 & 公众号@iTeaTime技术清谈 原创文章,版权声明:自由转载-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0

--------------------------------------------

One more thing...

【非礼勿视】以下为彩蛋部分,建议28岁以上男性观看

-------------------------------------------- ![image](https://user-images.githubusercontent.com/2911921/57273775-a32fc680-70cb-11e9-8cfd-2475e0abbb22.png)