Giter Club home page Giter Club logo

friday-qa's Introduction

iTeaTime | 技术清谈 微信群每周五问答环节



i组织来源

英文名:iTeaTime 中文名:技术清谈/i组织来源

i组织来源:最初来自“iOS开发-多线程交流”的微信群,最后演变为“iTeaTime(技术清谈)”群,此群500人已满,不再加人。

英文名:iTeaTime,读作IT Time。旗下有源码派、技术清谈几个分支。技术清谈主要做编程知识分享,源码派主要做代码开源。组织来源:由一群对开源有热情的开发者组成的非营利组织。

往期清谈汇总

中文名:技术清谈

就是“清谈误国,实干兴邦”里的“清谈”,群里讨论的技术,不考虑生产力。如果我们讨论的技术刚好有生产力,那就太幸运了。绝对算是彩蛋了。

引用 《清談- 维基百科》 的解释:

清谈,又称清言,流行于魏晋时期。汉末黄巾之乱,**政权瓦解,地方势力抬头,儒家经典随之衰落,乱世之中,老庄**逐渐抬头,一般文人不谈俗事,不谈民生,祖述老庄立论,大振玄风,最常谈的是《周易》、《老子》、《庄子》称为“三玄”。何晏、王弼、夏侯玄、王衍、郭象等人皆有辩才。何晏“好老庄言”,认为“天地万物,皆以无为为本”,和夏侯玄、王弼等倡导玄学,成为一时风气,往往废寝忘食,甚至可以把人累病谈死。“当时名士清谈,特如斗智。”是后世国学大师钱穆对当时清谈的叙述。

用于表明,我们讨论的问题,用于探究问题的本质,远离功利目的,以技术讨论过程的乐趣为主。

英文名:iTeaTime

IT + TeaTime = iTeaTime

谐音 IT Time,意义为 It's tea-time for IT Gossip. 与中文名意义相近,取清谈之意。

Tea Time 原意为茶话时间,茶歇时间,就是没事闲聊,讨论技术,偶尔水水群放松下。与此群清谈之风相近。

技术清谈 slogan

热情让技术更严谨, 技术让优异更稳定。

形式

三策三答,问答形式。

其他

提出问题的能力,远胜于搜索答案、收集知识的能力。能提出问题,就证明你已经掌握一半了。这便是主动思考与被动思考的区别。

壁纸

横屏字-light mode 壁纸-WeChat微信版 横屏字-light mode 壁纸 横屏字-dark mode 壁纸

微信聊天背景

群专属壁纸-第06版(绝对不挡群昵称版本+适配非齐刘海版本+适配iPhoneX版本).jpg

竖屏字- light mode 竖屏字- light mode 竖屏字- dark mode 居中版本

friday-qa's People

Contributors

chenyilong avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

friday-qa's Issues

iTeaTime(技术清谈)【000期】【代号:技术清谈简介】

iTeaTime(技术清谈)【000期】【代号:技术清谈】



i组织来源

英文名:iTeaTime
中文名:技术清谈/i组织来源

i组织来源:最初来自“iOS开发-多线程交流”的微信群,最后演变为“iTeaTime(技术清谈)”群,此群500人已满,不再加人。

往期清谈汇总

中文名:技术清谈

就是“清谈误国,实干兴邦”里的“清谈”,群里讨论的技术,不考虑生产力。如果我们讨论的技术刚好有生产力,那就太幸运了。绝对算是彩蛋了。

引用 《清談- 维基百科》 的解释:

清谈,又称清言,流行于魏晋时期。汉末黄巾之乱,**政权瓦解,地方势力抬头,儒家经典随之衰落,乱世之中,老庄**逐渐抬头,一般文人不谈俗事,不谈民生,祖述老庄立论,大振玄风,最常谈的是《周易》、《老子》、《庄子》称为“三玄”。何晏、王弼、夏侯玄、王衍、郭象等人皆有辩才。何晏“好老庄言”,认为“天地万物,皆以无为为本”,和夏侯玄、王弼等倡导玄学,成为一时风气,往往废寝忘食,甚至可以把人累病谈死。“当时名士清谈,特如斗智。”是后世国学大师钱穆对当时清谈的叙述。

用于表明,我们讨论的问题,用于探究问题的本质,远离功利目的,以技术讨论过程的乐趣为主。

英文名:iTeaTime

IT + TeaTime = iTeaTime

谐音 IT Time,意义为 It's tea-time for IT Gossip. 与中文名意义相近,取清谈之意。

Tea Time 原意为茶话时间,茶歇时间,就是没事闲聊,讨论技术,偶尔水水群放松下。与此群清谈之风相近。

技术清谈 slogan

热情让技术更严谨,
技术让优异更稳定。

形式

三策三答,问答形式。

其他

提出问题的能力,远胜于搜索答案、收集知识的能力。能提出问题,就证明你已经掌握一半了。这便是主动思考与被动思考的区别。

壁纸

横屏字-light mode 壁纸-WeChat微信版 横屏字-light mode 壁纸 横屏字-dark mode 壁纸

微信聊天背景

群专属壁纸-第06版(绝对不挡群昵称版本+适配非齐刘海版本+适配iPhoneX版本).jpg

竖屏字- light mode 竖屏字- dark mode 居中版本

iTeaTime(技术清谈)【008期】【代号:超人】

iTeaTime(技术清谈)【008期】【代号:超人】



出题:微博@iOS程序犭袁
本期代号:超人


enter image description here

从未被讨论过的问题,不公布答案。顺延到下一期。只要讨论过,答案不正确也会提供答案。下面将讨论过的问题公布答案:

下列题目可能出现以下虚拟的程序员,非实指:

  • 小地
  • 大风哥

1 【问题】【iOS】猜想系统 isEqual 函数的实现原理,并给出代码实现。要求能通过以下用例。

用例一:

   NSMutableString *s1 = [NSMutableString stringWithString: @"大风, 哥"];
   NSMutableString *s2 = [NSMutableString stringWithFormat: @"%@, %@", @"大风", @""];
   BOOL equal = [s1 isEqual: s2]; // 要求返回YES

用例二:

   CYLCustomizeClass *customizeObject1 = ...;
   CYLCustomizeClass *customizeObject2 = ...;
   BOOL equal = [customizeObject1 isEqual: customizeObject2]; // 要求返回YES

【提示1】考虑父类、子类同时实现了该方法的情况。
【提示2】假设你的类结构包括以下元素,那么 cache 部分可以不用比较:

       NSString *_name;
       NSMutableDictionary *_cache;
       int _length;
       char *_data;

【 难度🌟🌟🌟🌟】【出题人 微博@iOS程序犭袁】
【提示】和006期,suuny出的题有联系,也跟 NSString 底层实现有关。


2 【iOS】请给出下列代码的输出结果,并给出分析。如果有多种可能性需求进行列举,不确定性也要说明。

  override func viewDidLoad() {
       super.viewDidLoad()
       DispatchQueue.global().async {
           print("print 1, thread: \(Thread.current.isMainThread)");
       }
       
       DispatchQueue.global().async {
           print("print 2, thread: \(Thread.current.isMainThread)");
       }
       DispatchQueue.global().async {
           print("print 3, thread: \(Thread.current.isMainThread)");
       }
       DispatchQueue.global().sync {
           print("print 4, thread: \(Thread.current.isMainThread)");
       }
   }
 

【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】
【提示】没看过源码,只看文档,基本答错,这是一道送命题。


3【问题】【iOS】参考代码注释内容:

int main(int argc, const char * argv[]) { 
NSArray *array = @[@"Hello", @"World"];
//在这里插入代码(一行最好)
//在不创建新的数组的情况下将 array变成@[@"Goodbye", @"World"]
NSLog(@"%@", array);
return 0; 
}

【 难度🌟🌟🌟🌟】【出题人 孙源Sunny@dd】


4 【iOS】kengny 是一名产品经理,他平时有两大爱好:第一,到处在各类群里求买企业证书,第二,运营着一款小成本的视频 app,迫于成本压力,一般只会有两个人参演。他向大风哥提出需求,说希望能够在用户退到后台后,上传日志记录用户什么时候进入的后台,便于记录用户使用时长。并要求退到后台后依然能够下载小视频,这样用户上班点击下载按钮,回到家躺床上打开 APP 就能看了。并且要求把后台下载成功率定为大风哥的KPI。

如果你是大风哥,你将如何应对。必要时贴出示例代码。

【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】


5【iOS】kengny 是一名产品经理,他们的 app 是一款类似美团的产品,最近他和一些店家进行了PY交易,要求用户到他们家店附近的时候,立即收到通知。
小地和大风哥,会上听到需求后,小地立即说:这个需求做不了。大风哥会上没说话,产品经理说,明天上线,怎么实现我不管,散会。

会后,大风哥悄悄说对小地说要做也可以,可以这样做:_______。

请补充填空,要求给出详细理由,包括技术实现细节,如有必要贴出示例代码。

【 难度🌟】【出题人 微博@iOS程序犭袁】


6【iOS】大风哥负责企业内部员工 APP 的iOS开发工作,产品经理 kengny 老师通知说,老板要求,发布2.0,对员工数据进行更新,在 iOS 原有数据库基础上,增加一个字段,用于记录用户 “是否是兄弟”。该字段只有老板有操作权限,如果打开APP后,发现不是兄弟,就弹出离职申请页面。服务端得知填写完成后,会发送指令要求手机原地爆炸。如果不能爆炸的话,远程删除APP,或将手机初始化也可以。

如果你是大风哥你将如何应对。要求数据库操作贴出示例代码,数据库类型不限。

【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】


7【算法】请通过编程实现大数(亿位)的相加减乘除。(不限语言)
【 难度🌟🌟🌟】【出题人 消摇-金融-深圳iOSqp】
【提示】用人算的思路让电脑去算。
弱弱的问句第6题是用NSDecimalNumber去做计算吗"

M.W-不知名小作坊-iOS-北京:@颜魏-大世纪-深圳iOS 应该不是,用字符串和数组可以实现大数的加减
颜魏-大世纪-深圳iOS:弱弱的问句第6题是用NSDecimalNumber去做计算吗


8 【iOS】CoreData中几个核心概念及关系阐述下,第三方库 MagicRecord 的读写操作是在什么线程中执行的?【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】


9 【iOS】在一个字典中含有,字符串,字典,数组。层层嵌套,可能十几层。现在想知道任意节点Value中是否含有某个字符串。【 难度🌟🌟】【出题人 BM-成都iOS】
【提示】与广度优先排序,深度优先 排序。


10 【iOS】多线程操作中,读写操作一定要在同一线程中执行吗?给出原因,并至少给出两种场景佐证你的观点,以及实现方法。【难度🌟🌟】【出题人 微博@iOS程序犭袁】


11 【iOS】一个app中可能会产生几个 Autorelease Pool , Autorelease Pool 中的临时对象,何时会被dealloc 。给出原因。【难度🌟🌟】【出题人 微博@iOS程序犭袁】


12 【iOS】For in 循环中频繁创建临时变量的场景下,如何使用 Autorelease Pool 优化, 着重讲下你放置pool的位置,以及这些临时变量的生命周期改变。并给出原因。【难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】


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


One more thing...

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


image


/one more thing/

iTeaTime(技术清谈)【003期】【代号:星战-yoda】

iTeaTime(技术清谈)【003期】【代号:星战-yoda】




下列题目可能出现以下虚拟的程序员,非实指:

  • 小地
  • 大风哥

1【问题】【iOS】iPhone在无耳机状态下,通过实体按键设置静音后,以下路径比如: 微信主tab-朋友圈-点开feed流中的小视频,可以播放声音。 通过点击头像-个人朋友圈主页,点开视频无法播放声音。即使按声音增加键也无法播放。请问这个表现不一致的现象,是feature还是bug,如果是bug你觉得是代码哪里写的有问题。写出修复代码。【难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】

【答案】 :

视频播放器默认静音模式下是没有声音的,但可以控制即使是静音模式下依然有声音,显然前者设置了,后者没有设置。推测前者是被提交了bug所以fix掉了,后者使用场景比较少,所以没有被注意到。

   //忽略静音按钮
   AVAudioSession *session =[AVAudioSession sharedInstance];
   [session setCategory:AVAudioSessionCategoryPlayback error:nil];

完整代码:

- (AVAudioPlayer *)player {
if (!_player) {
NSURL *URL = [[NSBundle mainBundle] URLForResource:@"xxxx.wav"
withExtension:nil];
_player = [[AVAudioPlayer alloc] initWithContentsOfURL:URL error:nil];
AVAudioSession *autioSession = [AVAudioSession sharedInstance];
[autioSession setCategory:AVAudioSessionCategoryPlayback error:nil];
[autioSession setActive:YES error:nil];
[_player prepareToPlay];
}

耳机场景下,统一做了处理,都可以播放视频带声音。
比如以下代码用于判断耳机状态,因为AVAudioSession是单例,对耳机优先处理即可。

- (BOOL)isHeadsetPluggedIn {  
   AVAudioSessionRouteDescription* route = [[AVAudioSession sharedInstance] currentRoute];  
   for (AVAudioSessionPortDescription* desc in [route outputs]) {  
       if ([[desc portType] isEqualToString:AVAudioSessionPortHeadphones])  
           return YES;  
   }  
   return NO;  
} 

2 【计算机常识】如果图灵未被当时的英国当局发现异常,并且图灵创业成功出任CEO,你觉得图灵和他的小伙伴们创立的公司,最类似于下面哪些?A. IBM B.Apple C.GitHub D.Google E.微软 F. 其他。开放性答案,给出相似的原因。【 难度🌟】【出题人 微博@iOS程序犭袁】

  • 【出题人提示】开放这道题是开放性题目,给出自己的见解即可,主要筛选非技术背景童鞋。
  • 【答案举例】IBM、Google在人工智能领域有所建树。图灵正是人工智能之父,非常契合。
  • 【群里的答案】【同学匿名回答】GitHub 全球最大的同性交友平台。。图灵好像是同性恋?。。。 额 这个勿喷 没有亵渎的意思。。。

3 【问题】【通用问题】大风哥看到下列人物时,马上通过鄙视链将其分为了两类,请猜想结果,并给出原因:许嵩、王小波、马云、刘强东、马化腾、奥巴马、王宝强【 难度🌟】【出题人 微博@iOS程序犭袁】

  • 【出题人提示】许嵩学过iOS,王小波是C++程序员,刘强东大学编程赚钱,马化腾也会编程,奥巴马参加过编程一小时。
  • 【群内答案】因为许嵩学习ios,所以在鄙视链的最顶端。和其他人区分开。

4【问题】【大前端】为什么Flutter会选择一门新语言dart而不是js等其他更普及的语言。 【 难度🌟】【出题人 微博@iOS程序犭袁】

【答案】Flutter团队一次采访中透露因为做flutter的团队当时和dart的团队坐的很近,为了方便沟通。哈哈,团队协作是非常重要的因素。

当然,也不可忽视 Dart 语⾔的特性:

  • Productive(⽣产⼒⾼,Dart的语法清晰明了,⼯具简单但功能强⼤)
  • Fast(执⾏速度快,Dart提供提前优化编译,以在移动设备和Web上获得可预测的⾼性能和快 速启动。)
  • Portable(易于移植,Dart可编译成ARM和X86代码,这样Dart移动应⽤程序可以在iOS、
    Android和其他地⽅运⾏)
  • Approachable(容易上⼿,充分吸收了⾼级语⾔特性,如果你已经知道C++,C语⾔,或者
  • Java,你可以在短短⼏天内⽤Dart来开发)
  • Reactive(响应式编程)

5【问题】【iOS-autolayout】一个ScrollView上有3个UILabel,每个label字数不固定,类似字数很多的那种,要求上下依次排列,当文字超出ScrollView的时候可以滑动,左右不能滚动,上下可滚动。【难度🌟🌟🌟】【出题人群内大佬:@起点】

【出题人提示】就是label的宽度设置跟scrollView等宽,最底下的label底部要跟scrollView的底部约束上就可以了。
考察的主要是scrollView的约束问题。scrollView的约束主要是从内部撑开宽度跟高度。

【答案】

三个label 那个,就是放了个scrollview 然后里面放三个label,从上往下边距全部约束为0,然后label 宽度与scrollview相同,最下面那个label距离底部scrollview为0。(在内部无需多放view)

  1. 在 Scrollview 添加⼀个 ContainView
  2. ContentView 完全覆盖 Scrollview
  3. ContainView 上添加了三个 Label。View 的 bottom 和 第三个 Label 的 bottom 做约束。
  4. 三个 Label 互相做间距和宽的约束,不约束⾼

    3441556378312_ pic_hd
  5. 通过将 Scrollview 的 ContentSize 和 ContainView 的 size 保持⼀致。
- (void)viewDidAppear:(BOOL)animated {
       [super viewDidAppear:animated];
       [self.contentView layoutIfNeeded];
        self.scrollview.contentSize =
       CGSizeMake(CGRectGetWidth(self.contentView.frame), CGRectGetHeight(self.contentView.frame));
}

Demo 如下:

ScrollViewDemo.zip

Demo对应链接 手机端查看
标题:iTeaTime(技术清谈)【003期】【代号:星战-yoda】
链接:#4

6【问题】【iOS】UIView 旋转动画(CAKeyframeAnimation),绕中心点旋转90度后,过程中frame和 bounds 是如何改变的。【难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】

【答案】frame 改变, bounds不改变。注意center也不会影响。


原文链接 手机端阅读
标题:iTeaTime(技术清谈)【003期】【代号:星战-yoda】
链接:#4

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


One more thing...

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


iTeaTime(技术清谈)【-004期】【代号:星际穿越】

iTeaTime(技术清谈)【-004期】【代号:星际穿越】




本期特辑:hybrid、跨平台特辑
本期出品人:微博@iOS程序犭袁

注:题目难度五星为满分,各个类目下题目从易到难依次排列。



hybrid 类 【easy级别】


1【问题】【iOS】【hybrid】请阐述 JavaScriptCore 与 WebCore 工作过程中与线程的关系,阐述基于这种关系,对 JS 与 native 交互的影响,阐述解决优化。

【难度】🌟
【出题人】 微博@iOS程序犭袁


2【问题】【iOS】【Android】【hybrid】嵌入 native 的 web 页面,其 dom 的 localStorage 操作,在 iOS 的沙盒环境下的,阐述使用场景与限制或优势。基于局限,有无替代方案或者优化建议。

【难度】🌟🌟
【出题人】 微博@iOS程序犭袁


3【问题】【iOS】【hybrid】阐述 UIWebView 迁移到 WKWebView 的原因,以及有无遇到阻力,如何解决?

【注】work around 方案也可以。
【难度】🌟🌟
【出题人】 微博@iOS程序犭袁


4【问题】【iOS】【Android】【hybrid】如何用 js 创建一个原生的 Label 居中显示到某个 ViewController/ activity 上,可以通过 JS 修改 Label 的 text 属性,iOS版本代码如下:

var label = new Label();
label.text("Lefe_x");

// view 为 App 当前显示的 ViewController 的 view,通过 js 获取。
label.addToSuperView(view);

【难度】🌟🌟🌟
【出题人】 百度阅读-Lefe_x


5【问题】【iOS】【Android】【hybrid】阐述 H5 秒开方案,从 Web 层,和native层分别阐述。

【难度】🌟🌟🌟
【出题人】 微博@iOS程序犭袁

【答案】

iTeaTime(技术清谈)@ChenYilong

  • web组件加载前:预加载,启动后就加载web组件,减少web组件冷启动时间。
  • web组件加载后:webView的网络请求走native的网络库,可以 HOOK 网络请求或者直接在回调中,将response的数据缓存起来,webview请求的数据会走缓存。

iTeaTime(技术清谈)@yahaha-xsl-北京:

H5 秒开方案: 如果仅仅只需要实现秒开,不考虑服务端页面是否支持Last-Modified (304) 的情况下, 最简单方式,是客户端定义一个 WebView 预加载池就可以了。在前一个页面滑动的时候就将出现在屏幕上和即将有可能显示的加入WebView 预加载池,提前加载,然后通过LRU 进行缓存池清理。"

预加载池这种方法使用不当,内存可能会暴涨。可采用下面的方式缓解:

根据用户行为分析,预测可能被点击的页面,排名靠前的网页预加载。用户行为分析的理论依据:

  • 产品经理经验,比如网页上的“下一页”按钮。
  • 基于埋点用户路径---漏斗模型。
  • 基于热力图,最直观、最直接的分析预测用户操作行为体现方式

iTeaTime(技术清谈)@yahaha-xsl-北京:
可以采用两种方式知道即将有可能要显示的: 1.根据滑动的方向。2.根据用户的行为数据分析命中,他有可能要点开的H5。

iTeaTime(技术清谈)@叮当-广州-iOS :
UC浏览器是这样的,会在网页中分析即将可能点击的按钮去预加载

iTeaTime(技术清谈)@赵三岁-北京-“低层”iOS:
这个webview预加载我在掘金上看到过有个团队就是这么优化的,还是个电商项目,购物完成后他们会预加载评论的 webview、好像是他们有统计这个用户打开评论的概率比较大。

这样操作预加载后,大部分人都感觉网页打开很快,后台统计的秒开数据报表也很漂亮。


6【问题】【iOS】【hybrid】iOS 中如何低成本实现 WebRTC 功能,你的方案,请罗列有什么限制,主要从以下角度分析:

  • 与其他平台相比
  • 与常规native功能相比

【难度】🌟🌟🌟
【出题人】 微博@iOS程序犭袁


7【问题】【iOS】【Android】【hybrid】请阐述下 app 开发者如何保证用户访问的页面是安全页面,如何保证自己的网站,嵌入到 native 的 WebView 中,不会被劫持、被 js 注入。

参考场景:

  • PC端的Chrome在遇到非HTTPS页面时可以报警告,但很少见 native 应用中报这些错误。

【难度】🌟🌟🌟
【出题人】 微博@iOS程序犭袁


8【问题】【iOS】【hybrid】跨平台方案中,如何截取特定 div 标签,并保存为一张图片。跨平台语言不限:RN、Weex。

场景参考招商银行-掌上生活,发送电影卡邀请函。

【难度】🌟🌟🌟🌟
【出题人】 微博@iOS程序犭袁

招商银行app电影邀约 海底捞app饭局邀约

(gif图)

(gif图)

类似邀约图片分享的场景,模版为了可以可以随节日动态更新,hydrid 实现更为灵活。这是就会使用到native对前端栈实现的页面进行div截图。


9【问题】【iOS】【hybrid】针对 RN 开发人员不熟悉native开发的情况下,会出现很多操作,比如绘制一个3000px的cell,cell重用符号滥用,在scrollView上强行拼view而不用tableView,等等,针对这些情况,你作为一个native的开发,怎么避免或者及时预警?

【难度】🌟🌟🌟🌟
【出题人】 大灰灰-平安-iOS-上海


常规类


10【问题】【iOS】如何设计一个圆形的按钮,点击区域也是圆形的?
【难度】🌟
【出题人】 微博@iOS程序犭袁


11【问题】【计算机基础】16进制的 FF+2 后等于什么,有哪几种情况?
【难度】🌟
【出题人】 微博@iOS程序犭袁


12【问题】【iOS】【C】AB线程执行到一半去执行C线程,用Objective-C/Swift和C各自怎么实现。给出代码示例。
【难度】🌟🌟🌟
【出题人】 微博@iOS程序犭袁


13【问题】【算法】给出10W条人和人之间的朋友关系,求出这些朋友关系中有多少个朋友圈(如AB、BC、DE、E
F,这4对关系中存在两个朋友圈),并给出算法的时间复杂度。
【难度】🌟🌟
【出题人】 微博@iOS程序犭袁


hybrid 类 【medium级别】


14【问题】如何自定义 Web 使用的 UserAgent ?

【难度】🌟🌟🌟
【出题人】 颜-物灵-iOS

  • 比较通用的方法, 适用于 WKWebView 或者 UIWebview.

15【问题】嵌套进native的 web 页面,如何展示用户相册图片?

【难度】🌟🌟🌟
【出题人】 颜-物灵-iOS

(思路供参考.我验证过,可行)

  • 调用系统相册, 从用户手机获取图片 assetId. (native)
  • 根据 assetId, 找到对应图片,根据方向信息, 正确旋转图片后, 以缩略图形式,存储到沙盒缓存目录.(native)
  • 将 assetId 传递给 web,未来用作 图片原图 "路径"; 将缩略图地址,传给 web,用作直接展示到UI上的缩略图地址.(native -> web)
  • 使用 标签,显示缩略图, 正常显示,需要在图片路径前拼接 "file://"(web)
  • 根据需要,将 assetId 回传给 native, 以完成进一步的后续交互, 如自定义图片裁剪,上传高清图等.(web -> native)

16【问题】 如何实现 ReactNative 代码的动态更新?

【难度】🌟🌟🌟
【出题人】 颜-物灵-iOS

(思路供参考.我验证过,可行)

  • 将 ReactNative 引擎, 正确引入项目中.
  • 配置 main.bundle 代码路径时, 路径支持动态根据server配置获取.
  • 有新更新, 本地打包生成 main.bundle, 并通过 Server 下发给 App.

17【问题】【 Lua 实现 App 动态化方案】如何在 iOS 项目中,集成 luajit, 实现特定业务逻辑的动态更新.

【难度】🌟🌟🌟
【出题人】 颜-物灵-iOS

iTeaTime(技术清谈)@颜-物灵-iOS:

(仅供讨论, 个人对 lua 比较钟爱, 获取能找到更多的小伙伴)

简单描述下: lua 最吸引我的一点是: 它可以真正 "同步" 地 和 native API 在同一线程中 高效通信. 这一点, 是 JS, Flutter , 不太容易做到的一点.

  • 引入: 基于源码编译 luajit 为 .a, 引进项目中.(极小, 不到300kb, 就可以集成一个独立的完整的脚本引擎)
  • 通过 C 文件, 桥接 lua 和 objc. lua 可以指定暴露给 native 的方法, native 也可以根据需要暴露一些常用的安全性要求不高的方法, 如 文件管理相关的 API.
  • lua 源文件中,编辑为字节码文件, 通过 Server 下发给 App. App 根据特定逻辑,加载指定的 lua 文件,来实现特定业务的动态管理.

关于带入luajit的问题:

luajit 然后需要把 jit 特性关掉
比lua 本身 还是快一些(我没具体测试过)

项目中 我们真正在用的 并不多# 做了 一个 iOS 和 Andoroid 通用的资源管理器,自动工具app的状态信息返回对应的图片素材。 有一点像一个 可以直接写代码 的配置文件

Q:那当时为什么选lua不选js?

A:luavm可以多线程并发,jscore是单线程,硬伤。还有一个原因是 考虑 调用时的线程切换 # 另外考虑的是 后续能尽可能在 iOS 和Android 间复用逻辑。线程切换指的是,js 和 native 同步通信,在任意 native 线程中。因为写的 资源管理器,是无法预知自己会在哪个线程被调用。基于 jscore 好像也是可以同步通信的 #但是 没有 通过 c 文件桥接 通用性高。 android 的kotlin 可以通过 ndk 基于c 和lua桥接。另外的原因 可能就是 lua 体积比较小,方便集成 300k左右#

Q:(iTeaTime(技术清谈)@五子棋-淘宝-iOS) js 和 native 同步通信,在任意 native 线程中。因为写的 资源管理器,是无法预知自己会在哪个线程被调用 这个问题在哪…?

如果要说基于c的桥接 jscore是可以直接操作void *裸指针的…

A:(iTeaTime(技术清谈)@颜-物灵-iOS)
就是 native 调用某个 js 方法,立即获取返回值,用 c 桥接 jscore ,我还没试过。

Q:(iTeaTime(技术清谈)@味精-蚂蚁-北京)
jscore 不占体积,ios内置,jscore是直接有c api 的 并不是只可以使用oc封装,rn就是直接用的jscore capi

A:(iTeaTime(技术清谈)@颜-物灵-iOS)lua的多线程。我没有进一步看过# 我观察到的现象是: 多个native线程,是一个共享同一个 lua虚拟机的

Q:(iTeaTime(技术清谈)@味精-蚂蚁-北京)
本质上没区别 跨上下文的通信 都是数据在两个环境下的序列化...lua的虚拟机 风云很老的一篇文章提到过,lua本质上下文依然依赖一个线程一个上下文 但是lua有库 ,可以跨线程同步上下文。看似是在支持单虚拟机多线程。

Q:(iTeaTime(技术清谈)@五子棋-淘宝-iOS)
不用,3.2 lua把一堆的全局变量改了,可以每个真实线程里创建一个luavm。

A:(iTeaTime(技术清谈)@颜-物灵-iOS)这个 当时 主要是考虑到 Android那边 webview 好像很乱,似乎没有可以类比 jscore的东西 (Andorid 大白 我是)

Q:(iTeaTime(技术清谈)@味精-蚂蚁-北京)子奇说的那个 也是每个线程一个vm 和上下文吧... 并不是看似一个虚拟机同时直接操作多线程

A:(iTeaTime(技术清谈)@颜-物灵-iOS)
那 lua 和 c 的栈通信,有什么特殊的吗?或者说 有比较轻量的方式模拟吗?(我还是第一次接触 这种 跨语言的通信方式)

A:(iTeaTime(技术清谈)@味精-蚂蚁-北京)
并不是跨语言通信 而是跨上下文通信。本质上是一个数据流 压栈出栈(我不确定现在的lua 早年间大概四五年前...是这样的。所有数据先得序列化 然后压到虚拟机里 然后由虚拟机读序列化 重新构建虚拟机里的各种对象结构。本质是两个上下文对内存结构的组织差异...无法互相认识。

Q:(iTeaTime(技术清谈)@颜-物灵-iOS)
那现在 flutter 基于dart,有可能 和 c 这么通信吗?(我们当时 技术调研 我专门看了下 没看到相关介绍 就把flutter 否了)。

A:(iTeaTime(技术清谈)@味精-蚂蚁-北京)
但lua 与c的结合度很高...有很多trick的方案 可以直接操作内存传值 但风险太大了..并不了解dart虚拟机 不多扯了╮(╯_╰)╭

A:(iTeaTime(技术清谈)@五子棋-淘宝-iOS)
感觉lua和c直接调用不存在问题…lua底层不就用c写的吗…就跟cpython一样…

A:(iTeaTime(技术清谈)@味精-蚂蚁-北京)
对 不存在。就是刀子太锋利了

Q:GitHub@ChenYilong 真实,来自灵魂的解释,儿子和父亲交流,没什么障碍。

A:(iTeaTime(技术清谈)@味精-蚂蚁-北京)
障碍在儿子和父亲的文化代沟,就是各自上下文对象的组织结构。


18 【问题】【iOS】【hybrid】调用 js 绘图库的情况下,调用 js 绘图通过以下方式调用会出现什么情况, 该怎么解决

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    // 调用 js 绘图
}

// 或者

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
   // 调用 js 绘图
}

【难度】🌟🌟
【出题人】 PlutoY-广州YY


19 【问题】【iOS】【hybrid】WKWebView 加载本地文件如何做兼容?

【难度】🌟🌟
【出题人】PlutoY-广州YY


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


One more thing...

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




//one more thing

iTeaTime(技术清谈)【-002期】【代号:模仿游戏之寻龙诀】

iTeaTime(技术清谈)【-002期】【代号:模仿游戏之寻龙诀】




本期特辑:iOS应用安全与逆向之基础原理
本期出品人:微博@iOS程序犭袁
本期代号:模仿游戏之寻龙诀
本期出题人(排名不分先后):

  • 风扬-拍拍贷-SOi
  • SAGESSE-iOS-深圳
  • 鹅喵-便利蜂移动端
  • 微博@iOS程序犭袁

注:题目难度五星为满分,各个类目下题目从易到难依次排列。


逆向类


1【问题】【iOS】对称加密有哪些?描述其原理。
【难度🌟】【出题人:风扬-拍拍贷-SOi】


2【问题】【iOS】随便找一个正在运行的程序,给 objc_msgSend 下符号断点。程序断下之后,写一条 lldb 指令打印当前调用方法的 selector
【难度🌟🌟】【出题人:鹅喵-便利蜂移动端】

【回答】
要看具体 cpu 架构
读取第二个参数对应的寄存器:

objc_msgSend 两个固定参数, selector 第二个,存放在 x0x1 寄存器中。

【SAGESSE-iOS-深圳】给出答案:

平台 x86_64 arm 通用的
命令 po (char*)$rsi po (char*)$x1 po (char*)$arg2
参考 《x86-64传参规则》 《ARM子函数定义中的参数放入寄存器的规则》 所谓通用,是指在 arm 和在 x86_64 下用 po (char*)$arg2 都能得到预期效果。 $arg1-$argN 是第1到第n,无论什么框架和约定(lldb处理过了),:arg1 到 argN 是 Xcode9/10 添加的功能,在 Xcode8 或者之前需要用 rsix1

【鹅喵-便利蜂移动端】写成 x/s $arg2 也行, x/s 比较好打 po (char*)$arg2 或者 po x/s $arg2

/one more thing/

上述讨论与调用约定有关,相关概念:
rdirsirdxrcxr8r9

参考文档:


3【问题】【iOS】应用中使用了一个外部动态库的符号,这个符号的具体实现被查找了几次?为什么?
【难度🌟🌟🌟】【出题人:鹅喵-便利蜂移动端】

【提示】看过 fishhook 原理应该都知道 lazy symbol binding


4【问题】【iOS】Objective-C 和 C 在 iOS 中的区别,
尝试从以下角度分析两者区别:

  • 汇编角度
  • 系统加载两者的区别
  • 存储区别

【难度🌟🌟🌟】【出题人:风扬-拍拍贷-SOi】

/one more thing/

【出题人提示】
汇编角度: 汇编调用OC和C的过程分别是什么
2、加载区别:
OC:消息转发
自定义C函数:直接调用地址
系统C函数:共享缓存库
3、存储区别:MochO-中存储的区别

//TODO: 待讨论部分
第二点感觉覆盖不全,自己写的C代码就是调用库了吧?

【答案】

  1. OC 是 C 的超集,在 C 的基础上加入了面向对象编程范式的支持,为了支持这一范式,需要运行时支持。所以方法调用会在编译期转换为对运行时函数的调用,例如 objc_msgSend 系列函数。ARC 内存管理也需要运行时的支持,在编译期会自动插入对应调用。
  2. 所有包含了 OC 代码的可执行文件会依赖 libobjc.A.dylib,这个动态库中包含了处理嵌入在可执行文件内辅助运行时运行的一些数据结构(例如加载类、方法列表、+load的执行等)的函数。libobjc.A.dylib 在被 dyld 加载时会向 dyld 注册一个映像加载的钩子函数,使得被动态载入的可执行文件同样可以被 libobjc.A.dylib 预处理。
  3. 类与方法列表、CFString 对象等数据,被存放在了可执行文件中,例如各种 __objc 开头的区段。
    内存布局方面,除了 TaggedPointer、通过各种方式 bridge 过来的其他库中创建的之外的对象,都只能通过 alloc 在堆上分配内存

5【问题】【汇编】arm64位系统里的通用寄存器有多少个,分别是干什么的?什么是状态寄存器?
【难度🌟🌟🌟】【出题人:风扬-拍拍贷-SOi】


6【问题】【iOS】动态下发一个经过苹果签名的动态库是否可以加载(允许使用dlopen), 为什么?
【难度🌟🌟🌟🌟】【出题人:SAGESSE-iOS-深圳】

【出题人提示】
1: 首先,动态下载肯定不在bundle里, 只能在沙盒里面
2: 从题目条件得知是经过苹果签名的,所以代码签名这一步是通过的
3: 可以通过lldb测试


7【问题】【iOS】iOS 是如何通过代码签名确保应用安全的?
【难度🌟🌟🌟🌟】【出题人:SAGESSE-iOS-深圳】


8【问题】【iOS】分别给 objc_msgSend 和你要调用的方法下符号断点,第一次断下的时候可以在调用栈中看到 objc_msgSend。第二次断下的时候,调用栈里只有你要调用的方法了。objc_msgSend 哪儿去了?
【难度🌟🌟🌟🌟】【出题人:鹅喵-便利蜂移动端】

【提示】其实是想讨论一下如何控制堆栈平衡以及 backtrace 背后的原理:

  1. 调试器中看到的调用栈是怎么来的
  2. 如何通过汇编做到不带栈帧的调用

【答案】

跳板函数/蹦床函数/trampoline function 正解。

首先,如果用了 bl 指令的话 lr 里面会存储返回地址的,但是串成串还要靠栈帧结构。
x86_64 有个一个 rbp , 每一次 call 都会压入 rbp , 就会形成一帧帧调用栈, 然后通过 rbp 可以朔到最开始。所以展示 backtrace 只要遍历栈帧就可以了,首个栈帧靠 ip 确定。

普通的函数是call调用, 而objc_msgSend 是长跳转(jump),估计是为了减轻栈溢出的压力, 另外尾递归也是长跳转


Q-A环节
Q:[腾讯-刘翅鹏]第8题是指定cachelookup吗?
A:[鹅喵-便利蜂移动端]不是,CacheLookup 里面应该是顺带做了这个事

参考 《[腾讯-刘翅鹏]的笔记》

Q:是否如下图所言:

A:
[鹅喵-便利蜂移动端]是的,不过 cdecl 调用约定是被调用者清理栈空间,所以纯汇编写的时候要注意平衡

A:【欧阳大哥】上面那个红框中的结论有待商榷吧。
如果函数调用发生在最后一条指令时不能用bl而只用用b的原因是因为:执行bl指令时会把当前指令的下一条指令保存到LR寄存器中。问题是因为这是最后一条指令了,下一条指令是一条未知指令,所以如果仍然用bl指令的话,那么函数返回时所跳转的地址将可能是一条无效的地址了。。而不是所谓的栈溢出的现象。

Q:[SAGESSE-iOS-深圳] 我突然想到个问题,栈顶的第一个条数据是rbp吗,
A:[鹅喵-便利蜂移动端]应该是栈上最后一个申请的变量,rbp 是当前栈帧的顶端,所以函数退出清理栈的时候不需要记住你申请了多少栈空间,只要 movq %rbp, %rsp 就可以了。*(rbp + 8) 是上个栈帧的 rbp。

*(void*)($rbp + 0) 上一个栈帧的地址
*(void*)($rbp + 8) 返回地址

然后通过返回地址可以就可得到函数的信息

Q: 也就是说:第一个调用的函数,当前栈的rbp是啥? *(rbp)

A: 刚才调试了一下,是个0.

Q-A结束



常规类


9【iOS】kengny 是一名产品经理,他们的 app 是一款类似美团的产品,最近他和一些店家进行了PY交易,要求用户到他们家店附近的时候,立即收到通知。
小地和大风哥,会上听到需求后,小地立即说:这个需求做不了。大风哥会上没说话,产品经理说,明天上线,怎么实现我不管,散会。

会后,大风哥悄悄说对小地说要做也可以,可以这样做:_______。

请补充填空,要求给出详细理由,包括技术实现细节,如有必要贴出示例代码。

【 难度🌟】【出题人 微博@iOS程序犭袁】

已知 iOS 定位方法有:GPS定位、基站蜂窝定位、Wi-Fi定位等多种定位方法,

精准度优先级可以为:

  • 首选是 GPS,
  • 然后是 GPRS(IP 和 routetrace ),蜂窝网络进行 routetrace 可以获取到第一个接入点
  • 然后是 Wi-Fi(IP 和 routetrace 和附近的 Wi-Fi 名),SSID 名的优先级比较低,主要是靠routetrace
  • 然后是附近的蓝牙设备

如果结合以上多种定位方法,这四个方案是同时的,组合起来可有效命中率。

蓝牙相关的例子:
好多超市有蓝牙定位,还有商场的室内定位,都是基于蓝牙

还有基于Apple设备蓝牙配对效果的:

其中Wi-Fi SSID部分注意事项:

即使申请了权限,也只能在系统的Wi-Fi列表里获取所有Wi-Fi信息,APP内好像也是不能获取的。

正如 《iOS NetworkExtension 框架使用笔记》 所说:

ps1:如果你运行完,没看到打印。心想被坑了,那就拿
起你的手机进入到设置,打开【无线局域网】设置页
面。这时候你再看看控制
ps2:苹果这么搞也是不好玩,还要进入到他自己的设置
页面才能获取wifi列表,坑一~

此类的APP也是有引导用户这么做的,第一次不行,需要重新进一次吧:
而且有人反应该权限现在申请好像比较难,周期较长,半个月还不一定能申请好。

涉及的API:

GPS 部分采用地理围栏相关的API:

适合横向的大范围坐标,但比如写字楼、商场等纵向的情景,纯定位不是很理想。需要借助其他措施。

UNLocationNotificationTrigger 部分的限制:

Region-based notifications aren't always triggered immediately when the edge of the boundary is crossed. The system applies heuristics to ensure that the boundary crossing represents a deliberate event and is not the result of spurious location data. For more information about the heuristics that are applied, see Monitoring the User's Proximity to Geographic Regions.


10【问题】【C++】以下输出结果是什么?分析原因

class A{

public:
int m;
void foo1(){ cout<<“hello”<<endl;}
void foo2(){cout << “hello”<< m <<endl;}
virtual void foo3(){cout << “hello”<<endl;}

};

A*p =NULL;
p->foo1();
p->foo2();
p->foo3();

【难度🌟🌟】【出题人:欧阳大哥-美团-北京】

【答案】

【SAGESSE-iOS-深圳】:

错误分析:
foo1和foo2是静态成员函数,调用时编译器会直接生成调用地址, 因为不会访问this指针所以调用不会出现问题;但foo2有访问成员m的操作,这就需要访问this指针了所以会出现段错误; foo3因为是虚函数,所以需要访问虚表,但this是空指针,所以调用也会出现段错误;

输出结果:

因为c++是一个跨平台的语言,在每个平台的 STL 实现都有可能不一样,所以输出结果会有所不同。
在foo2中的 cout << "hello" << m <<endl; 会被拆分成:

cout << "hello";
cout << m;
cout << endl;

当执行到 cout << m; 时,会因为 this->m 而发生段错误,这时的 "hello" 到底有没有输出呢?

第一种情况: 在 Xcode 中直接运行,这时 stdout 直接输出到 Xcode 的控制台,它的输出是即时的, 所以有溃之前就己经输出,所以最终输出结果是

hello
hello
段错误

第二种情况: 在 Xcode 中编译,然后在终端中运行,这时输出不是即时的,写入的数据是缓存在内存里,只有当调用 endl(flush) 时才会真正的去写入文件(io),所以最终输出结果是

hello
段错误

以下为其他同学的讨论部分:

//TODO: 待系统整理

[鹅喵-便利蜂移动端]:

hello
hello
段错误

原因:[鹅喵-便利蜂移动端]cpp的方法调用等价于method(this,args...),只要不访问成员变量或vtable就不会崩

[SAGESSE-iOS-深圳]foo1和foo2是静态成员函数,调用时编译器会直接生成调用地址, foo3因为是虚函数,所以需要访问虚表,但p是空指针,所以会直接段错误, 顺便一提如果foo1和foo2有访问成员m的操作结果又不一样了

【Never-成都-太合乐动-iOS】:
foo1 和 foo2 直接地址 调用

【yx@美团北京】:
foo2的hello确实也能正常输出 一直到尝试访问m实例变量挂了

看你用的g++ 编译器的行为可能不一样

编译器不重要,实现在STL库里面

xcode debugger的控制台输出是即时的

实测没有
重点是没有执行到endl

cout << "hello";
cout << m;
cout << endl;

foo3 因为是虚函数 会牵扯到 虚表操作

Xcode 可以输出,xcode debugger帮助flush了。
std::endl 一定会刷,其他情况一般不会立即刷。

以下为不同环境的输出结果:




11【iOS】CoreData中几个核心概念及关系阐述下,第三方库 MagicRecord 的读写操作是在什么线程中执行的?为何有人如此讨厌使用CoreData,CoreData适合什么样的项目?【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】


12【iOS】kengny 是一名产品经理,他平时有两大爱好:第一,到处在各类群里求买企业证书,第二,运营着一款小成本的视频 app,迫于成本压力,一般只会有两个人参演。他向大风哥提出需求,说希望能够在用户退到后台后,上传日志记录用户什么时候进入的后台,便于记录用户使用时长。并要求退到后台后依然能够下载小视频,这样用户上班点击下载按钮,回到家躺床上打开 APP 就能看了。并且要求把后台下载成功率定为大风哥的KPI。

如果你是大风哥,你将如何应对。必要时贴出示例代码。

【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】

【答案】

关于后台下载,我们研究的时候,很有必要把 iOS7 和 iOS7 之后的方案分清楚。
因为即使是现在,我们的 APP 最低版本都是iOS9+,但现在网上很多答案都还是iOS7之前的方案,给读者产生了混淆与误导。

现在分几个部分解答:

  • iOS7前的陈旧方案
  • 大文件后台下载,用 Background Transfer service 特性,涉及iOS11的新API,让请求等待网络正常后再自动尝试。
  • 小文件后台下载,用 BAR ( Background App Refresh)或 Remote notification

iOS7前的陈旧方案

iOS7 之前后台下载方案十分不灵活,现在已经基本不再使用。下面做下介绍:

  • 使用 beginBackgroundTaskWithExpirationHandler 函数,向系统申请最多10分钟来执行需要后台运行的操作
  • 将 App 的后台运行模式设置为 audio 、VOIP、location、Newstand 等,无限制的在后台运行。

下面做下详细介绍:

(一)使用 beginBackgroundTaskWithExpirationHandler 函数,向系统申请一段时间来执行需要后台运行的操作,这种方法的缺点是,后台操作最多只能运行10分钟,超过10分钟之后App会休眠。使用这种方法需要APPNAME-info.plist中设置 Application does not run in background 为NO,然后在适当的时间调用 beginBackgroundTaskWithExpirationHandler 函数。

(二)将 App 的后台运行模式设置为 audio 、VOIP、location、Newstand 等,无限制的在后台运行。修改 info.plist -> requried background modes-> App plays audio or streams audio/video using AirPlay , 进入后台,播放无声音乐。前台后台一套下载流程,下载完成,更新数据;下载失败,重新下载尝试。这种方案审核风险较大,不建议使用。因为审核时是可以通过静态分析知道使用了哪些API的,如果一个程序本来就不是音乐类的,却使用了播放音乐的API后台播音乐,有可能就被拒绝,如果想要绕过这个限制,可以向APP增加播放音乐的功能,但这样实际是增加了无用功能。

总结:

第二种,只有极少数 APP 能够用到,一般 APP 无法使用;第一种,运行时间无法保证,无法进行下载恢复等操作,毫无实用性可言。故现在已经很少 APP 在使用上述方式。下面介绍更为实用的方案:

Background Transfer service 特性实现大文件后台下载

注意: NSURLSession 是一个类蔟,不同系统版本实现上是有差异的。很多都要亲自实验一下,而且不同系统版本的行为也不太一样。建议不仅要阅读文档,而且要多多尝试调试。

当 App 使用了 Background Transfer service特性后,可以将一个下载任务交给系统的独立进程去下载,不管App在前台、休眠、以及crash,下载过程都在进行,因为是系统的独立进程在为App进行下载。

基本步骤:

使用 backgroundSessionConfigurationWithIdentifier: 初始化的 configure 初始化一个后台下载使用的 session。
实现 NSURLSessionDelegateNSURLSessionTaskDelegateNSURLSessionDownloadDelegate 中的
URLSession:task:didCompleteWithError: ,
URLSession:downloadTask:didFinishDownloadingToURL: , urlSessionDidFinishEvents(forBackgroundURLSession:) 和其他业务需求的 protocol
实现 application:handleEventsForBackgroundURLSession:completionHandler: 方法。

点击下载,创建 task 对象并开始:

NSURLSessionDownloadTask *downloadTask = [ session downloadTaskWithRequest:[NSURLRequest requestWithURL: downloadURL];

后台下载成功调用相关代理方法,实现数据和 UI 更新;下载失败从 error 中查找 resumeData,重新开始下载。


QA环节:

Q:下载能控制退到后台的下载速度么,在后台慢慢下,打开在前台全速

A:有的,configureation 里面有一个属性值 discretionary,就是控制的,在后台不占用设备性能的情况下进行下载。

Q:如果在前台,设了这个discretionary的值有用么,也会被系统控制下载速度?

A:没用了,里面强调的是 allows background tasks,如果需要具体限速的数值的话,是没有的,需要自己实现了。限速如果实现,应该是类似断点续传的思路。用suspend和resume做。

Q:后台下载是要用户开的吧?关掉了就只能用播放音乐了。URLSessionDownloadTask 和后台刷新开关有没有关系?

A:URLSessionDownloadTask 和后台刷新开关没有关系。同时,后台下载跟应用的进程没有关系了,是系统做维护的。,用第一种方案也是可以实现,即使用户手动关闭的app,最终也是可以下载成功的,但也不是说还会继续后台下载。

@property(getter=isDiscretionary) BOOL discretionary;

(Apple-Developer-Documentation-API-NSURLSessionConfiguration-discretionary )

此属性设置为 YES 时,系统根据当前性能自动处理后台任务的优先级,以获得最佳性能 (仅background session有效)。根据文档可知:allowsCellularAccessdiscretionary 被用于节省通过蜂窝连接的带宽。建议在使用后台传输的时候,使用 discretionary 属性,而不是 allowsCellularAccess 属性,因为它会把 Wi-Fi 和电源可用性考虑在内。

QA环节结束


用户主动关闭的app,会保存 resumedata ,在后面启动的时候调用didCompleteWithError方法, error 里有resumedata,可以持续下载。
这里有一个缺点就是,iOS11之前,如果因为没有网络导致系统下载失败了,系统即使唤醒了App,App也是没有办法下载的,然后App会进入休眠,即使后面有了网络,系统也不会继续下载,因为只要系统向App发出了失败的信号,除非App 调用resume函数来恢复下载过程,系统是不会自己恢复下载的。这里就需要用到本文提到的BAR ( Background App Refresh)模式,让App过一段时间被系统唤醒,然后App就可以去检查网络,当有网时恢复下载过程,恢复下载的原理类似于断点下载。

iOS11之后,可以采用下面API进行:

URLSession Adaptable Connectivity API

iOS11的重大更新,可以通过 urlSession(_:taskIsWaitingForConnectivity:) 让请求等待网络正常后再自动尝试。

URLSessionTask Scheduling API

通过 URLSessionTask Scheduling API 可以在 App 没有运行的时候下载内容,而手机也会结合实际电量,使用状态去决定是否执行。

参考:

用 BAR ( Background App Refresh)或 Remote notification 实现小文件后台下载

在iOS7以后,系统增加了两种后台的模式,一种是 Background fetch ,另一种是Remote notification,可以用于小文件下载。

BAR ( Background App Refresh)

之前讨论的方案,跟后台刷新没有关系的,没有使用 performFetchWithCompletionHandler 相关的功能

注意:BAR ( Background App Refresh)相关的,用户没有主动kill掉的app才会有 BAR 功能。
具体用法参考:

Remote notification

在iOS7以前,当系统收到推送消息后,会立即弹出消息提示用户,用户点击消息之后,就可以启动App,然后加载数据。使用了这种新的后台模式之后,当系统收到推送消息之后,会唤醒App,给App一个机会执行一部分操作,等操作之后才提醒用户,而且还支持 silent 模式,即执行完操作之后,完全不对用户做任何提醒,默默的就在后台把活干完了,此功能需要用户开启推送权限。


13【iOS】大风哥负责企业内部员工 APP 的iOS开发工作,产品经理 kengny 老师通知说,老板要求,发布2.0,对员工数据进行更新,在 iOS 原有数据库基础上,增加一个字段,用于记录用户 “是否是兄弟”。该字段只有老板有操作权限,如果打开APP后,发现不是兄弟,就弹出离职申请页面。服务端得知填写完成后,会发送指令要求手机原地爆炸。如果不能爆炸的话,远程删除APP,或将手机初始化也可以。

如果你是大风哥你将如何应对。要求数据库操作贴出示例代码,数据库类型不限。

【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】


14【算法】请通过编程实现大数(亿位)的相加减乘除。(不限语言)
【 难度🌟🌟🌟】【出题人 消摇-金融-深圳iOSqp】
【提示】用人算的思路让电脑去算。

/one more thing/

多人提供答案:

[Lefex]提供以下答案:

《图解一道面试题 - 大数相加减乘除》

【SAGESSE-iOS-深圳】提供以下答案:

Swift版本:

除法使用移位减实现,不过会这么复杂是因为是以二进制保存的数:

static func + (lhs: XCNumber, rhs: XCNumber) -> XCNumber {
       var cf = 0
       var result = XCNumber()
       for pos in 0 ..< max(lhs.integers.count, rhs.integers.count) {
           let rax = lhs[pos] + rhs[pos] + cf
           result[pos] = rax
           cf = rax &>> XCNumber.nbits
       }
       let maximum = (lhs[.max] + rhs[.max] + cf) & XCNumber.mask
       result.isSigned = maximum & 0x80 != 0 // 最高位的值是否为1, 如果为1说明结果是负数
       if maximum != 0 {
           result.integers.append(.init(truncatingIfNeeded: maximum)) // 如果是结果是非负数,需要保存进位
       }
       return result
   }
   static func - (lhs: XCNumber, rhs: XCNumber) -> XCNumber {
       return lhs + -rhs
   }
   static func * (lhs: XCNumber, rhs: XCNumber) -> XCNumber {
       guard !lhs.isZero && !rhs.isZero else {
           return XCNumber() // 如果任何一个数为0都不需要计算
       }
       return XCNumber.calculator(lhs, rhs) { lhs, rhs in
           var result = XCNumber()
           for row in 0 ..< rhs.integers.count {
               var cf = 0
               var pos = row
               for column in 0 ..< lhs.integers.count {
                   let rax = result[pos] + lhs[column] * rhs[row] + cf
                   result[pos] = rax
                   pos += 1
                   cf = rax &>> XCNumber.nbits
               }
               while cf != 0 {
                   let rax = result[pos] + cf
                   result[pos] = rax
                   pos += 1
                   cf = rax &>> XCNumber.nbits
               }
           }
           return result
       }
   }
   static func / (lhs: XCNumber, rhs: XCNumber) -> XCNumber {
       guard !rhs.isZero else {
           fatalError("0不能作为除数")
       }
       guard !lhs.isZero else {
           return XCNumber() // 如果被除数为0, 不需要处理
       }
       return XCNumber.calculator(lhs, rhs) { lhs, rhs in
           var bit = lhs.integers.count * 8 - 1 // 因为是小于count * 8
           var result = XCNumber()
           var remainder = XCNumber(lhs)
           var divisor = rhs << bit  // 移动到最左边(乘N)
           while bit >= 0 {
               if divisor <= remainder {
                   result.set(1, at: bit) // 直接设置比特位
                   remainder -= divisor
               }
               bit = bit - 1
               divisor = divisor >> 1 // 向右移动(恢复)
           }
           return result
       }
   }

[李胜运-齐数-上海小程序]提供的JS版本,仅仅实现了正数的加 乘。

//TODO: 待完善。

function mergeStr(strA, strB, isIntegerPart){
  let arrA = strA ? strA.split("") : [0];
  let arrB = strB ? strB.split("") : [0];
  let shotArr = arrA.length > arrB.length ? arrB : arrA;
  let longArr = arrA.length <= arrB.length ? arrB : arrA;
  while(shotArr.length < longArr.length){
   if (isIntegerPart) {
    shotArr.unshift("0");
   } else {
    shotArr.push("0");
   }
  }

  let carry = 0;
  let sumArr = [];
  for(let i = longArr.length-1; i >=0; i--){
   let numA = Number(shotArr[i]);
   let numB = Number(longArr[i]);
   let sum = numA + numB + carry;
   sumArr.unshift(sum % 10);
   carry = Math.floor(sum / 10);
  }

  return {
   sumStr : sumArr.join(""),
   carry  : carry
  }
 }
 function add(strA, strB){
  let arrA = strA.split(".");
  let arrB = strB.split(".");
  let intrgerPartObj = mergeStr(arrA[0], arrB[0], true);
  let decimalPartObj = mergeStr(arrA[1], arrB[1], false);

  let carryStr = intrgerPartObj.carry ? intrgerPartObj.carry : "";
  let intrgerPart = carryStr + intrgerPartObj.sumStr;
  let carryIntrgerPartObj = mergeStr(intrgerPart, String(decimalPartObj.carry), true)
  carryStr = carryIntrgerPartObj.carry ? carryIntrgerPartObj.carry : "";

  let decimalPartStr = decimalPartObj.sumStr == "0" ? "" : "." + decimalPartObj.sumStr
  let res = carryStr + carryIntrgerPartObj.sumStr + decimalPartStr;
  return res;
 }


 function mul(strA, strB){
  let pointA =  strA.indexOf(".") == -1 ? 0 : strA.length - 1 - strA.indexOf(".");
  let pointB =  strB.indexOf(".") == -1 ? 0 : strB.length - 1 - strB.indexOf(".");
  let allPoint = pointA + pointB;
  let arrA = strA.replace(".", "").split("");
  let arrB = strB.replace(".", "").split("");
  let shotArr = arrA.length > arrB.length ? arrB : arrA;
  let longArr = arrA.length <= arrB.length ? arrB : arrA;
  while(shotArr.length < longArr.length){
   shotArr.unshift("0");
  }
  
  let all = [];
  for(let i = longArr.length-1; i >=0; i--){
   let sumArr = [];
   let carry = 0;
   for(let count = 0; count < longArr.length - i - 1; count++){
    sumArr.unshift("0");
   }
   for(let j = shotArr.length - 1; j >= 0; j--){
    let numA = Number(shotArr[i]);
    let numB = Number(longArr[j]);
    let sum = numA * numB + carry;
    sumArr.unshift(sum % 10);
    carry = Math.floor(sum / 10);
   }
   if (carry) {
    sumArr.unshift(carry);
   }
   all.push(sumArr.join(""));
  }

  var res = "0"
  for(let i = 0; i < all.length; i++){
   res = add(res, all[i]);
  }
  
  let resArr = res.split("");
  if (allPoint > 0) {
   while (allPoint >= resArr.length) {
    resArr.unshift("0");
   }
   resArr.splice(resArr.length - allPoint, 0, ".");
  }
  // return resArr.join("");
  return resArr.join("").replace(/^0+/g, "").replace(/^\./g, "0.");
  
 }



 console.log(mul("61", "1.0"))
 console.log(mul("88", "10.3"))
 console.log(mul("0.88", "0.103"))
 console.log(mul("12323736.453", "10.03"))
 console.log(mul("11111111", "55555555"))
 console.log(mul(".10", "13"))
 console.log(add("21.1233", "23.5"));
 console.log(add(".33", "5.5"));
 console.log(add("8.000", "23.5"));
 console.log(add("21.1233", "23.5"));
 console.log(add("999999999999999999999", "999999999999999999999"));



//TODO: 未完待续


15 【iOS】多线程操作中,读写操作一定要在同一线程中执行吗?给出原因,并至少给出两种场景佐证你的观点,以及实现方法。【难度🌟🌟】【出题人 微博@iOS程序犭袁】


16 【iOS】一个app中可能会产生几个 Autorelease Pool , Autorelease Pool 中的临时对象,何时会被dealloc 。给出原因。【难度🌟🌟】【出题人 微博@iOS程序犭袁】


17【iOS】For in 循环中频繁创建临时变量的场景下,如何使用 Autorelease Pool 优化, 着重讲下你放置pool的位置,以及这些临时变量的生命周期改变。并给出原因。【难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】


18【算法】【iOS】在一个字典中含有,字符串,字典,数组。层层嵌套,可能十几层。现在想知道任意节点Value中是否含有某个字符串。【 难度🌟🌟🌟🌟】【出题人 BM-成都iOS】
【提示】广度优先,深度优先,为非常朴素的暴力搜索。
暴力搜索也有策略的,看到数组、字典就展开, 这是 深度优先
看到数据、字典先记下来,等这一层所有节点都查完了再展开下一层的,这是广度优先。从数据结构来分析,深度优先是维护一个栈,广度优先是维护一个队列


One more thing...

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


/one more thing/

iTeaTime(技术清谈)【002期】【代号:刺客信条】

iTeaTime(技术清谈)【002期】【代号:刺客信条】




下列题目可能出现以下虚拟的程序员,非实指:

  • 小地
  • 大风哥

1【问题】【果粉常识题】为什么iPhone有的后置摄像头上会有一个小孔,这可能是iPhone背面上唯一可能进水的部分,这个孔是干什么的【难度🌟】
【出题人 iTeaTime(技术清谈)@ChenYilong

【答案】 iPhone 背部的小孔实际上是一个麦克风,它的作用是降噪。,故意放在远离嘴巴的位置,收集环境噪音,在通话时将环境噪音删掉。采用的是【双 Mic 降噪技术】

双脉降噪技术主要原理是,频率相同的声波会发生干涉,如果波频相同,振幅相反,则会互相抵消。

假设,手机底部的 Mic 收集到的声波是 Va,手机背部手机到的是 Vb;声波通过干涉相抵的简易公式是 Vm = (Va - Vb) * n; n 是差分电路的放大系数。

当手机处在一个噪音环境下,前后两个 Mic 收录的音波几乎相同,Vm1 = (Va1 - Vb1) * n; 若 Va1 - Vb1 无限趋近于 0,则 Vm1 无限趋近于 0

当我们利用 Mic 通话时,Vm2 = (Va2 - Vb2) * n, Va2 >> Vb2.

故而当我们及时身处在一个不算安静的环境,只要不遮挡手机背面的 Mic,我们听到的声音就是 Vm = Vm2 - Vm1, 理想情况下,Vm1 约等于 0; 但也有一些非理想的情况,例如,说话说未能对准 Mic,Va2 不够大,影响收音效果,声音变小。

AirPods 也是拥有两个 Mic,但 AirPods 采用的是上行降噪技术,筛选信噪,并做放大和降低。不过,耳机的降噪就是另外一个故事了。


2【问题】【计算机常识】小地做了一个微信机器人,每天给女神发今天天气真不错,你在干嘛?女神一直没回复。直到第99天,女神回复微信说,你这样做是没有用的。小地看到消息,高兴地说:我的机器人终于通过测试了!大风哥,拍着他的肩膀,语重心长地说:小地,你高兴得太早了。请回答:小地为什么高兴,大风哥为什么说他高兴得太早了。【难度🌟】【出题人 iTeaTime(技术清谈)@ChenYilong

【答案】小地高兴在于他以为他的机器人通过了图灵测试,大风哥,说他高兴太早,是因为图灵测试的完整定义是指测试者与被测试者(一个人和一台机器)隔开的情况下,通过一些装置(如键盘)向被测试者随意提问。 进行多次测试后,如果有超过30%的测试者不能确定出被测试者是人还是机器,那么这台机器就通过了测试,并被认为具有人类智能。
这里30%的测试者无法成立。

3【问题】【iOS】小地是一名base北京的iOS程序员,他有一次要出差深圳,但想找几个能在深圳可以一起吃早餐的朋友。但他的iPhone没有越狱,于是他在北京打开Xcode修改了系统定位到深圳,成功在探探、微信、陌陌上分别找到了可以共度早餐的人。但由于连续看了三天的妇联首映,加之几夜没睡也没吃早餐,他早晨在酒店无法下床,他想故技重施,打开公司打卡软件修改位置打卡。但发现无法修改。只好请假下午去,扣了半天工资。请问:小地他怎么改的位置,为什么公司打卡软件改不了,是怎么做的?【难度🌟🌟🌟🌟】【出题人 iTeaTime(技术清谈)@ChenYilong

【答案】使用gpx文件, Xcode 虚拟定位可修改模拟器以及真机的系统的定位。即使是从App Store下载的探探、微信、陌陌只要使用系统接口获取定位信息,就可以通过gpx模拟定位。

1 Xcode 中新建一个项目, 创建一个 .gpx 文件
2 高德获取经纬度,链接 https://lbs.amap.com/console/show/picker , iOS 端采用的定位坐标系是 WGS-84 , 而获得的定位一般是火星坐标 GCJ-02,把 获得的坐标转化为原始坐标:WGS-84或者直接用 Google 地图获取坐标,就不需要坐标系转换了。还有一个 gpx 文件生成网站:https://www.gpxgenerator.com/ 可以直接选择坐标,然后导出 gpx 文件。

参考链接:

标题&链接 手机端阅读
标题:高德获取经纬度API
链接:https://lbs.amap.com/console/show/picker
标题&链接 手机端阅读
标题:GPX Generator
链接:https://www.gpxgenerator.com/

3 修改代码 把 Location.gpx 文件里的代码 改为 要定位的经纬度
4 点击 Debug--->Simulate Location --> Location 然后运行

(Location 这个是新创建 gpx 的文件名)

举例 Location.gpx :

<?xml version="1.0"?>
<gpx version="1.1" creator="gpxgenerator.com">
   <wpt lat="21.021460306037525" lon="105.81782341003418">
       <ele>16.10</ele>
       <time>2019-04-11T17:59:18Z</time>
   </wpt>
</gpx>

钉钉也可以修改定位打卡,如果钉钉设置 Wi-Fi 打卡,公司只配置校验了 SSID,没有校验 DHCP 地址。把家里的 Wi-Fi 名称改得和公司打卡的 Wi-Fi 即可。

如果有一些打卡软件不能修改,那可能是因为未使用系统定位方法,或者未仅仅使用该方法作为定位依据。具体使用何种方法,可在另行讨论。但已知 iOS 定位方法有:GPS定位、基站蜂窝定位、Wi-Fi定位等多种定位方法,

精准度优先级可以为:

  • 首选是 GPS,
  • 然后是 GPRS(IP 和 routetrace ),蜂窝网络进行 routetrace 可以获取到第一个接入点
  • 然后是 Wi-Fi(IP 和 routetrace 和附近的 Wi-Fi 名),SSID 名的优先级比较低,主要是靠routetrace
  • 然后是附近的蓝牙设备

如果结合以上多种定位方法,这四个方案是同时的,组合起来命中率就很高了,取合理的定位结果交集进行反作弊也是一种思路。

但是在iOS13中对 Wi-Fi 定位权限进行了收紧,需要用户进行额外授权,相关的上下文可以参考下面的链接:

参考链接:

标题&链接 手机端阅读
标题:iOS13AdaptationTips-Network
链接:ChenYilong/iOS13AdaptationTips#24

另外,做灰产的,有一种外设,基于苹果 MFi 认证,配合配套软件直接提供修改后的坐标,Apple 的这一类产品,最初是给那些没有 GPS 模块的iPad、iPod做定位的功能弥补,让这些用户也能使用定位。但这类产品修改的也是系统定位,进而也可以间接做打卡用图。不过是需要实体的装置。这个就不在讨论范围了。

还有其他几种相关的情况,见下图:

越狱情况:
限制就更少,比如越狱后的钉钉小助手
未越狱情况,
hook系统的定位方法:
CLLocationManager相关,然后重新签名。
因为重签名后bundleID变了,
只要APP在打卡接口验证就可防止该漏洞。

4【问题】【iOS】小地是一名中级iOS开发,他最近学会了iOS黑魔法 - Method Swizzling ,他感觉黑魔法很方便,于是他大量使用了这个技巧,并默默分享给其他同事,想大家一起成长,一起用。大风哥是团队一名高级开发,听到后,告诫小地谨慎使用。如果你是大风哥,你会怎么去告诫他。【难度🌟🌟🌟🌟】【出题人 iTeaTime(技术清谈)@ChenYilong

【答案】

优点:

区别于⼿动为每⼀个类编写埋点⽅法或者写⼀个基类来做统⼀的埋点,前两者在某些场景下⼯ 作量都不算⼩。可以做⼀个 UIViewController 的 Category,置换原⽣⽅法,在置换⽅法中将写⼊埋点代码,这样可以直接⼀键埋点完成。之后新增的 UIViewController 类也不需要再关⼼这些的埋点代码。

- (void)cyl_APOViewDidLoad {
Class class = [self class];
if (!([class isEqual:[UIViewController class]] || [class isEqual: [UINavigationController class]])) {
NSLog(@"统计该⻚⾯ %@", class);
}
}

置换 NSDictionary-setObject:forKey: 方法,用于防止 crash。 NSArray 同理。

- (void)cyl_safeSetObject:(id)object forKey:(id<NSCopying>)key {
if (object && key) {
[self safe_setObject:object forKey:key];
}
}

Swift 版本实现:

缺点:

总结:一时hook一时爽,debug火葬场。

原因:

以下为 Stack Overflow-What are the Dangers of Method Swizzling in Objective C?

参考链接:

标题&链接 手机端阅读
标题:What are the Dangers of Method Swizzling in Objective-C?
链接:https://stackoverflow.com/questions/5339276/what-are-the-dangers-of-method-swizzling-in-objective-c

中列举出的7个问题:

  • Method swizzling is not atomic
  • Changes behavior of un-owned code
  • Possible naming conflicts
  • Swizzling changes the method's arguments
  • The order of swizzles matters
  • Difficult to understand (looks recursive)
  • Difficult to debug

可见,其没有类似注解的东⻄,⽅法置换没有有效声明。如果滥⽤,反⽽会增加维护成本。若擅⾃使⽤未同步其他同学,会成为极⼤的项⽬隐患。尤其是⼀些封装的模块。

这里着重说明几个场景:

场景:(iTeaTime(技术清谈)@国家一级保护废物 提供答案)

如果多次hook了同一个类的同一个方法,
跟分类重名的表现是一样:表现为无法控制执行的先后顺序,与编译器build的顺序有关,但编译器顺序有不可控性。

比如下面的实现方法,可能出现方法覆盖的问题:

+ (void)load {
static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{
Class class = [self class];
SEL originalSelector = @selector(viewDidLoad); SEL swizzledSelector = @selector(XK_ViewDidLoad);
Method originalMethod = class_getInstanceMethod(class, originalSelector);
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod),
method_getTypeEncoding(swizzledMethod));
if (didAddMethod) {
class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod),
method_getTypeEncoding(originalMethod));
} else {
method_exchangeImplementations(originalMethod, swizzledMethod);
}
});
}

场景:(iTeaTime(技术清谈)@molon 提供)
Hook了具有继承关系的相同方法。

以下场景:

如果子类并没有重写父类的方法,拿父类的implement去swizzling本来就是错误的行为。

A<—继承---B<—继承---C
(B是A的子类,C又是B的子类)

A 里有 test 方法,但是 B 和 C 都没有重写。
通常如果要对 B 或者 C 的 test 进行hook的话,很多开发者都喜欢去给 B 或者 C add A.test 的 implemention。
那如果先hook的C,又hook的B,似乎就形成了C与A直接打交道的局面。但是以面向对象来说,C的原实现应该是B的当前实现才合理。
所以不应该hook当前类没有重写的方法,这种其实直接继承(或者加category方法)就可以做了,不需要hook,需要调用原实现直接[super test]即可。


原文标题 & 原文链接 手机端阅读
标题:《iTeaTime(技术清谈)【002期】【代号:刺客信条】》
链接:#3

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


One more thing...

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



iTeaTime(技术清谈)【007期】【代号:蝙蝠侠】

iTeaTime(技术清谈)【007期】【代号:蝙蝠侠】



出题:微博@iOS程序犭袁 和他的小伙伴们
本期代号:蝙蝠侠

enter image description here

下列题目可能出现以下虚拟的程序员,非实指:

  • 小地
  • 大风哥
  • kengny 老师

【今日话题】如何看到小程序的跨平台方案,比如:美团App内置Flutter引擎容器可以跑微信小程序,DCloud出了跨平台uni-app方案,一次编写,导出多个小程序版本发布。还没京东也出了自己的跨平台方案。你是否看好这些平台?


1 【iOS】kengny 是一名产品经理,他平时有两大爱好:第一,到处在各类群里求买企业证书,第二,运营着一款小成本的视频 app,迫于成本压力,一般只会有两个人参演。他向大风哥提出需求,说希望能够在用户退到后台后,上传日志记录用户什么时候进入的后台,便于记录用户使用时长。并要求退到后台后依然能够下载小视频,这样用户上班点击下载按钮,回到家躺床上打开 APP 就能看了。并且要求把后台下载成功率定为大风哥的KPI。

如果你是大风哥,你将如何应对。必要时贴出示例代码。

【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】


2【iOS】kengny 是一名产品经理,他们的 app 是一款类似美团的产品,最近他和一些店家进行了PY交易,要求用户到他们家店附近的时候,立即收到通知。
小地和大风哥,会上听到需求后,小地立即说:这个需求做不了。大风哥会上没说话,产品经理说,明天上线,怎么实现我不管,散会。

会后,大风哥悄悄说对小地说要做也可以,可以这样做:_______。

请补充填空,要求给出详细理由,包括技术实现细节,如有必要贴出示例代码。

【 难度🌟】【出题人 微博@iOS程序犭袁】


3【iOS】大风哥负责企业内部员工 APP 的iOS开发工作,产品经理 kengny 老师通知说,老板要求,发布2.0,对员工数据进行更新,在 iOS 原有数据库基础上,增加一个字段,用于记录用户 “是否是兄弟”。该字段只有老板有操作权限,如果打开APP后,发现不是兄弟,就弹出离职申请页面。服务端得知填写完成后,会发送指令要求手机原地爆炸。如果不能爆炸的话,远程删除APP,或将手机初始化也可以。

如果你是大风哥你将如何应对。要求数据库操作贴出示例代码,数据库类型不限。

【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】


6【算法】请通过编程实现大数(亿位)的相加减乘除。(不限语言)
【 难度🌟🌟🌟】【出题人 消摇-金融-深圳iOSqp】


8 【iOS】CoreData中几个核心概念及关系阐述下,第三方库 MagicRecord 的读写操作是在什么线程中执行的?【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】


9 【iOS】在一个字典中含有,字符串,字典,数组。层层嵌套,可能十几层。现在想知道任意节点Value中是否含有某个字符串。【 难度🌟🌟】【出题人 BM-成都iOS】


11 【iOS】多线程操作中,读写操作一定要在同一线程中执行吗?给出原因,并至少给出两种场景佐证你的观点,以及实现方法。【难度🌟🌟】【出题人 微博@iOS程序犭袁】


12 【iOS】一个app中可能会产生几个 Autorelease Pool , Autorelease Pool 中的临时对象,何时会被dealloc 。给出原因。【难度🌟🌟】【出题人 微博@iOS程序犭袁】


13 【iOS】For in 循环中频繁创建临时变量的场景下,如何使用 Autorelease Pool 优化, 着重讲下你放置pool的位置,以及这些临时变量的生命周期改变。并给出原因。【难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】

14题 Autorelease Pool 方法走完了,才会对里面的临时对象做一次release操作,当临时对象引用计数为0时,才会dealloc
从后往前release


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


One more thing...

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


enter image description here

enter image description here

enter image description here

/one more thing/

iOS面试题

百度面试题

2、属性的实质是什么?包括哪几个部分?属性默认的关键字都有哪
1、什么是动态运行时语言
些?@ dynamic关键字和@ synthesize关键字是用来做什么的?
3、 NSString
为什么要用copy关键字,如果用 strong会有什么问题?
4、 nonatomic
和 atomic的区别? atomic是绝对的线程安全么?为什
么?如果不是,那应该如何实现?
5、简述kvo、kvc、 Delegate他们之间的区别?
6、 Objective-C与C、C++之间的联系和区别?
7、线程间如何通信?
8、如何访问并修改一个类的私有属性?
9、数据持久化的几个方案
10、obic使用什么机制管理对象内存?
11、内存泄漏可能会出现的几种原因,聊聊你的看法?
12、bck的实质是什么?一共有几种bock?都是什么情况下生成
13、介绍一下分类,能用分类做什么?内部是如何实现的?它为什么
的?
会覆盖掉原来的方法?
14、obc中向一个ni对象发送消息将会发生什么?
15、 untime如何通过 selector
找到对应的MP地址?
16、有没有用过运行时,用它都能做什么?

iTeaTime(技术清谈)【009期】【代号:梵高星空】

iTeaTime(技术清谈)【009期】【代号:梵高星空】


1【问题】请列举至少三种"代码块"管理工具,并介绍你觉得最好用的,以及好用点。
【 难度🌟】【出题人 iTeaTime(技术清谈)@ChenYilong


2【问题】【iOS】
iTeaTime(技术清谈)@小橘爷-字节跳动
SKStoreReviewController 这个有什么办法能监听点击的是几颗星呢?
【 难度🌟🌟🌟】【出题人iTeaTime(技术清谈)@小橘爷-字节跳动】

【回答】
iTeaTime(技术清谈)@SAGESSE-深圳-某不知名小作坊:
A:
SKStoreReviewController的实现如下

@implementation SKStoreReviewController
+ (void)requestReview {
SKXPCConnection* connection = [[SKXPCConnection alloc] initWithServiceName:@"com.apple.itunesstored.xpc"];

id arg3 = // <OS_xpc_dictionary: dictionary[0x15fa63bc0]: { refcnt = 1, xrefcnt = 1, count = 1, reply = 0, dest port = 0x0, dest msg id = 0x0, transaction = 0, voucher = 0x0 } <dictionary: 0x15fa63bc0> { count = 1, transaction: 0, voucher = 0x0, contents = "0" => <int64: 0x15fffc060>: 188 }>
id arg4 = ^{ ... };

[connection sendMessage:arg3 withReply:arg4];
}
@end 

XPC调用后由StoreKit服务(另一个进程)显示和管理控制器,通过手动创建XPC连接到StoreKit服务使用API或许是个不错的方案,但StoreKit服务是否提供查询功能无从得知。
结论是暂时无法实现


3【问题】【算法】【理财】

假设一个理财产品的平均年化收益为10%,且是收益平稳。

问:每个月固定投入多少钱,分别能在5、10、20、40、50年后得到100万。

如果是到1000万呢?5、10、20、40、50年定投金额金额分别为多少?

要求写出计算代码?

【 难度🌟🌟】【出题人iTeaTime(技术清谈)@消摇-金融-深圳iOS】


4【问题】【算法】【生活】

你看中了一套价值500万的房子,这个时候你有150万的资金,为此,你需要向银行贷款350万。假设目前银行住房贷款利率为5.75%,那么如果你分期30年还,总共需要还多少钱?(提示:每月偿还后,贷款总金额减少,所需利息也会减少)

如果你能通过公积金贷款90万(利率3.25%), 向银行贷款260万,那么你总共需要还多少钱?

【 难度🌟🌟🌟】【出题人iTeaTime(技术清谈)@消摇-金融-深圳iOS】


5【问题】【iOS】
iTeaTime(技术清谈)@十代-小公司-泉州iOS
image

【难度🌟】【出题人iTeaTime(技术清谈)@十代-小公司-泉州iOS】

【回答】
iTeaTime(技术清谈)@十代-小公司-泉州iOS:

  1. print 不会被执行, 因为数组是空的, 也不会 crash, 因为逻辑与判断第一个条件的时候就 false
  2. print 不会被执行, 因为数组是空的, 并且会 crash, 因为 logicAnd 函数的第二个参数取值的时候越界了
  3. 使用 closure 将第二个参数延缓执行, 这样就在 guard 的时候就返回 false

func logicAndRepair(_ left: Bool, _ right: @autoclosure () -> Bool) -> Bool {
   guard left else {
       return false
   }
   return right()
}

if logicAndRepair(!nums.isEmpty, nums[0] > 0) {
   print("The first number \(nums[0]) is greater than zero !")
}


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


One more thing...

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


iTeaTime(技术清谈)【006期】【代号:布加迪】

iTeaTime(技术清谈)【006期】【代号:布加迪】



出题:微博@iOS程序犭袁 和他的小伙伴们
本期代号:布加迪

enter image description here


【今日话题】: 你如何看待张小龙的预言:未来2年内,小程序将取代80%的App市场。每次都能听到“2岁多的小程序,终于又双叒迎来了“春天”?”的声音,似乎native每天都在冬天,你会因为市场的影响而更新技术栈,或者调整编程的百分比,为前端多多增加百分比吗?未来前端在你的占比中多少比较合适?


1.【问题】【iOS】参考代码注释内容:

int main(int argc, const char * argv[]) {
   //在这里插入一行代码,使下面的代码输出 "Goodbye World"
   NSLog(@"Hello World");
   return 0;
}

【 难度🌟🌟🌟🌟】【出题人 孙源Sunny@dd】

【答案】

几种 tricky 版本:

重定义 NSLog

以下几种宏定义皆可:

   #define NSLog(FORMAT, ...) fprintf(stderr, "Goodbye World\n")
   #define NSLog(x) printf("Goodbye World\n")
   #define NSLog NSLog(@"Goodbye World");

[鹅喵-便利蜂移动端]:

voidNSLog)(id)=(id _){CFLog(0, CFSTR("Goodbye World"));};

利用编译器的注释特性

[鹅喵-便利蜂移动端]:

NSLog("Goodbye World"); //\
NSLog(@"Hello World"); 

下面着重介绍两种,更有技术含量的版本:

深入理解 NSString

NSString 的内存分配实际是很复杂的,可能分配在栈区、堆区、常量区。

我们常常以为@"foo",这样的字符串是常量区(也称为常量存储区或 _TEXT 区。),运行时不能改,内存区域映射都是 dyld 干的。

其实我们可以简单理解为 NSString 是一个 map 结构,key 存在常量区,的确无法修改,但是 value 是一个静态变量,我们可以运行时修改。

常量字符串的内存复制方案

[molon-杭州]提供思路:

首先 Objective-C 中任何两个相同字符串值的声明,即使是存储在不同的变量名中,也是指向同一个对象。

常量区的变量内存地址是连续的。

而常量字符串的指针在 CFString 段里面,内存复制的话只复制 CFString 的 size 就够了。

直接操作内存就可修改,只要有权限,内存当中的任何地方都能操作。程序运行起来,可以理解为其汇编代码也是写入内存的。你想靠修改对应位置,塞入汇编代码,修改运行中逻辑都可以。很多计算机病毒就是这么做的。但是一般操作系统提供的 API 会做一定的权限控制,例如不能修改其他进程的,等等,但是只要你能提权也是可以操作,很多外挂、破解基本上都是这么个原理。相对来说, Objective-C 反而显得不安全,对 hook 的亲和力太特么强。像其他语言一般还需要用内联汇编去做层 inline hook,控制堆栈平衡等,而 Objective-C 却没有。

比如如果逆向以下代码:

int main(int argc, const char * argv[]) {

   NSString *a = @"Hello world";
   NSString *b = @"bye";
   memmove((void *)(@"Hello world"),(void *)(@"Goodbye world"),17);//此处17为随意填写,并无特定含义,请查看下文完整的取值计算方案。
   NSString *c = @"ok";

   NSLog(@"Hello world");
   NSLog(@"ok");
   NSLog(@"bye");
   return 0;
}

那么,下图红框部分即为 Objective-C 的常量区:

(逆向结果由[molon-杭州]提供)

enter image description here

常量区:

enter image description here

然后这个常量区 CFString 里对应的 char指针对应的那块内存区域也是连续的。

上述代码中 memmove 拷贝的是 CFString 的内容,不是这块区域的。

首先从<CoreFoundation/CFString.h> 可以查看 CFString 结构体,

可以发现其大小跟 CPU 架构有关,结构并不简单,而且 __CFConstStr 属于内部 API 无法访问,所以我们可以模仿重新定义一个类似的结构:

以下方案由[Never-成都iOS]提供:

#import <Cocoa/Cocoa.h>

struct CYLConstStr {
   struct {
       uintptr_t _cfisa;
       uint32_t _swift_strong_rc;
       uint32_t _swift_weak_rc;
       uint8_t _cfinfo[4];
       uint8_t _pad[4];
   } _base;
   uint8_t *_ptr;
#if defined(__LP64__) && defined(__BIG_ENDIAN__)
   uint64_t _length;
#else
   uint32_t _length;
#endif
};

int main(int argc, const char * argv[]) {
   //在这里插入一行代码,使下面的代码输出 "Goodbye World"
   memmove((void *)(@"Hello World"), (void *)(@"Goodbye World"), sizeof(struct CYLConstStr));
   NSLog(@"Hello World");
   return 0;
}

运行结果:

enter image description here

参考文献:

修改 CFString __DATA 段 方案

[孙源Sunny@dd] 提供思路:

cstring 存在 __TEXT ,是不可变区域,CFString 存在 __DATA,可以修改,该情况与修改 static 变量没什么区别。

CFString__DATA 端我觉得原因是它的结构里有个 isa 指针指向了 __CFConstantStringClassReference ,这种在编译时无法确定,得在动态链接时才知道这个地址并赋值上去。

根据 WWDC 2016 - Session 406-Optimizing App Startup Time 的说明:

enter image description here

可知:

区域 作用
__TEXT ,是不可变区域,CFString 存在 __DATA,可以修改,该情况与修改 static 变量没什么区别。

CFString__DATA 端我觉得原因是它的结构里有个 isa 指针指向了 __CFConstantStringClassReference ,这种在编译时无法确定,得在动态链接时才知道这个地址并赋值上去。

根据 WWDC 2016 - Session 406-Optimizing App Startup Time 的说明:

enter image description here

可知:

区域 作用
__DATA 头文件,代码,只读常量
__DATA 所有可读写内容(全局变量、静态变量等等)

举例说明 NSString_TEXT_DATA 三者的关系,

比如 《iOS控制代码段大小的一些经验》 一文中提到:

如果定义一个 NSString 数组,元素数量庞大,可能会导致 __TEXT 代码段非常大。仅仅下面的代码,生成的目标文件大小就可以达到 89.51KB。具体原因并不是字符串的总字节数多,而是元素数量大,中间的取值指令过多。
代码:

enter image description here

用到的宏定义:

enter image description here

尽管编译器只在text段的字符常量区生成一份字符,多次使用不会增加字符常量区的大小,但是会增加 __TEXT 段代码的大小,使用 MachOView 工具查看可执行文件,结果如下图:

enter image description here

cstring 只有一份,多次调用不会存在多份,但是再通过反编译查看调用语句:

enter image description here

调用的函数会转变成上图的指令,可以看到是从字符常量区取到 rax, 再取到栈空间。这样一个一个的取,由于有非常多个字符串,那么相应的指令就会存在非常多,导致调用函数的代码段变得非常大。而且这样会非常浪费栈空间。

总结就是:

在使用 NSString 时,cstring 只有一份,多次调用不会存在多份,但调用的函数中间还有一步指令,是从字符常量区取到 rax, 再取到栈空间,rax对应的值保存在 _DATA 中。

上面的题目,修改的就是 _DATA 中的值。

cstring 才是 __TEXT
cfstring 是 __DATA

CFString__DATA 端我觉得原因是它的结构里有个 isa 指针指向了 __CFConstantStringClassReference,这种在编译时无法确定,得在动态链接时才知道这个地址并赋值上去.

[鹅喵-便利蜂移动端]提供代码实现:

int main(int argc, const char * argv[]) {
   typedef struct STR {
       size_t padding[2];
       char const *s;
       size_t len;
   }STR;
   STR *str =(STR *)@"Hello World";
   str->s = "GoodBy World";
   NSLog(@"Hello World");
   return 0;
}

enter image description here

一行代码模式:

// 改 cstring 的方式
int main(int argc, char **argv) {
 typedef struct STR { size_t padding[2]; char const *s; size_t len;} STR; STR *goodbye = (STR*)@"Hello World"; goodbye->s = "Goodbye World"; goodbye->len = 13;
 NSLog(@"Hello World");
 return 0;
}

运行结果:

enter image description here

Apple 的 opensource 的 CF 是 CFLite,跟生产环境的不一样,可以参考其 README 说明:

Apple 的 opensource 版本:

enter image description here

生产环境版本:

enter image description here


2【iOS】有没有办法通过提供的ipa包然后判断出是支持ipad还是iphone,还是都支持。【 难度🌟🌟】【出题人 SuperDanny-轩宇-珠海iOS】

把IPA解压,包内容的info.plist有个UIDeviceFamily,值=1是iPhone,=2是iPad,=1,2是都支持

/usr/libexec/PlistBuddy -c 'Print :UIDeviceFamily' xxx.app/Info.plist

enter image description here

[鹅喵-便利蜂移动端][M.W-不知名小作坊-iOS-北京]回答正确


3 【算法】使用熟悉的编程语言,编写一个函数,要求输入与以下列表相似的结构,则返回值为true,否则为false。【注意】输入字符串无限制,英文字符、标点符号均无需特殊处理,与中文一样视为作完整字符。

  • 上海自来水来自海上
  • 黄山落叶松叶落山黄
  • 山东落花生花落东山
  • 山西悬空寺空悬西山
  • 湖南过路车路过南湖

【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】

【提示】算法实际为回文算法,题目主要在于边界情况处理,在函数顶端要有判空等操作。可自行搜索,下面提供群里提供的答案,如有瑕疵可以指正。

【答案】

python3 的,天生编码支持好,递归做法:

def check_re(str):
if not str:
 return True
if str[0] != str[-1]:
 return False
else:
 return check_re(str[1:-1])

print(check_re("asdffdsa) //True
print(check_re("asdfdsa)) //True
print(check_re("上海自来水来自海上)) //True
print(check_re(黄山落叶松叶落山黄")) //True
print(check_re("山东落花生花落东山")) //True
print(check_re("山西悬空寺空悬西山") //True
print(check_re("湖南过路车路过南湖")) //True
print(check_re("123456")//False

jS版本:

function judgeIsPalindrome (str) {
if (null == str || str.length < 2) {
return 'false';
} else {
if (str.split(""). reverse().join("")= str) {
return 'true';
} else {
return 'false';
}
}
}
console.log(judgeIsPalindrome('🍎🍌🍇🍇🍌🍎'));
console. log(judgeIsPalindrome('abccba'));

输出结果:

enter image description here

另一 java 版本:

// still 3 
public static boolean isPalindrome(String s) {
 if (s == null) return false;
 int left = 0; int right = s.length()-1;
 while (left < right) {
  if (s.charAt(left) == ' ') left++;
  else if (s.charAt(right) == ' ') right--;
  else if (s.charAt(left) != s.charAt(right)) return false;
  left++;
  right--;
 }
 return true;
}

[Jenny]回答。

边界情况,可酌情添加,为加分项目:

  • 字符里面也许应该排除一下 ZWJ 组合 emoji
  • 不考虑 unicode 组合字的话,Pokémon 这种字倒过来就会变成 noḿekoP,注音符号跑偏了,所以至少是标准库或第三方库要有良好的 unicode 支持 (鹅喵-便利蜂移动端)

4.【算法】要求使用熟悉的编程语言,编写一个函数,要求输入任意字符串,都能返回对称结构的字符串。【注意】输入字符串无限制,英文字符、标点符号均无需特殊处理,与中文一样视为作完整字符。

举例:

输入的原始字符串:

  • 走马灯灯马走灯熄马停步

输出的字符串:

  • 走马灯灯马走

【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】

【答案】 详细可以搜:最长回文子串算法。

下面是一种时间复杂度为 O(n^2)的写法,并非最优解,最优解为 Manacher 算法, 时间复杂度O(n), 空间复杂度O(n),可自行搜索。:

public static void main(String[] args) {
       // write your code here
       String str = "步停马熄灯走马灯灯马走你";
       String str1 = "qqqqbcddcbasf";
       String str2 = "abcdeff";
       String str3 = "11118889999888";
       String str4 = "5544334433111";

       System.out.println(getStr(str));
       System.out.println(getStr(str1));
       System.out.println(getStr(str2));
       System.out.println(getStr(str3));
       System.out.println(getStr(str4));
   }

   static String getStr(String source) {
       if (source == null || source.length() < 1) {
           return "\n";
       }
       for (int i = source.length() / 2; i > 0 ; i--) {
           StringBuilder builder = new StringBuilder();
           builder.append(String.join("", Collections.nCopies(i, "(.)")));
           for (int j = i; j > 0; j--) {
               builder.append("\\" + j);
           }
           String patternStr = builder.toString();
           Pattern pattern = Pattern.compile(patternStr);
           Matcher m = pattern.matcher(source);
           if (m.find()) {
               return m.group(0);
           }
       }
       return "\n";
   }

5【iOS】看下面的方法执行完之后 ViewController 会被销毁吗,ViewController 的 view 会被销毁吗?为什么?

- (void)addViewController { 
UIViewController *viewController = [[UIViewContrnller alloc] init];
[self.view addSubview: viewController.view]; 
}
…

【 难度🌟🌟】【出题人 Saber-ios-望京】

【答案】view被引用,vc没被引用,所以VC被销毁,view不销毁。

详细解释:
vc引用view,view对vc无引用。 vc在view在,view在与vc可不在。vc为局部变量,方法结束后直接销毁;vc.view被添加在self.view上,所以不会被销毁.


6【iOS】请给出以下代码的输出结果:

NSArray *array = @[@"1"]; 

NSMutableArray *mutableArray = [[NSMutableArray alloc] initWithObjects:@"123’, nil];

void(ˆblock)(void) = ˆ{ 
NSLog(@"array %@",array); 
NSLog(@"mutableArray %@",mutableArray);
};
array = @[@"2"]; 
[mutableArray add0bject:@"456"];
block(); 

【 难度🌟】【出题人 微博@iOS程序犭袁 】

【答案】

array 1
mutableArray 123,456

参考: 《iOS中__block 关键字的底层实现原理》


7【问题】【iOS】segment 页面如何进行内存优化。需求描述:segment一次性把所有页面加载出来会导致内存爆增。几个segment 子页面的图片都是高清大图。【难度🌟🌟🌟】【出题人:中鼎iOS攻城狮】

下面答案由【BM-成都iOS】提供:

题目主要有2个核心:1.多个页面 2.高清大图

针对多个页面,用lazy的形式,用时加载就好了。所以题目主要是讨论高清大图。

作为另外一个补充:

关于高清大图上传问题。

  1. 理论应该尽可能还原用户创造的原始数据。比如用户上传一个头像,虽然现实控件只有100像素。但是理论上不应该客户端直接把图片压缩了上传给服务器,万一以后这张头像会作为背景图呢?

  2. 关于流程问题。很多对于资源类型的上传直接使用后台接口上传data。

    但是有一个问题是,整个过程是这样的:1.客户端上传data给后台主机。2.主机拿到图片上传到对象服务器。3.对象服务器给主机回调。4.主机给客户端上传结果回调。(举例一个栗子:3个角色,你,财务,人事。(事情是核对你的工资是否正确) 难道不觉得这样的一个流程很**么?流程:财务给你发工资,然后你拿到钱,找人事问应该给你发多少,如果发错了,你再找财务说给你发错了,重新核对。 过程完全可以优化为:财务向人事核对工资是否正确,然后给你发工资

    所以,整个过程的标准流程为:向服务器请求token,Bucket,路径等一系列参数。由客户端直接向对象存储器上传,上传成功以后请求接口告知主机上传成功。在这个过程中,主流的对象存储器的sdk都有断点续传等乱七八糟的优化。会一定范围内解决上传内存暴增情况


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


One more thing...

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


image

第三题答案有误

【方法三】【消摇提供答案】
a = ( a + b ) - b * ( b = a );

这个答案确实不对,应该是这样吧
a = b + 0 * ( b = a);

dealloc中使用weak_self会出现什么结果

😊:

- (void)dealloc{
    __weak __typeof(self) weak_self = self;
    NSLog(@"%@",weak_self);
}

会出现什么结果


SAGESSE:

nil


明天见:

懵逼


嗨,胡小桶 CIUM:

实验了下,炸了


SAGESSE:

好吧


五子棋:

weak_register_no_lock
就搜这个runtime方法就行了
这crash我查过


此刻柳暗花明:

五子棋大佬说得太对了


明天见:


明天见:

我在看10年前的文档


林小达:

这个crash我也查过,检测到self==nil的时候直接abort好像是


SAGESSE:

大佬说得太对了


😊:

会过度释放


😊:

然后就崩溃了


😊:

iTeaTime(技术清谈)【004期】【代号:林肯】

iTeaTime(技术清谈)【004期】【代号:林肯】



出题:微博@iOS程序犭袁
本期代号:林肯



从未被讨论过的问题,不公布答案。顺延到下一期。只要讨论过,答案不正确也会提供答案。下面将讨论过的问题公布答案:

今天会从没有修改马甲(马甲格式为【昵称+地区/公司/职位】)的同学中随机抽取几位幸运儿,送出飞机票若干张。待会儿我出题,回答任意一道即可,别人回答过的,不能再回答,交卷时间为出题日第二天20点。因为是自己出的题,大部分网上没有答案。可以讨论,没点名同学,抢答正确后,请自觉补充同类型问题一道供点名同学回答。题目能够精准筛选非技术同学即可,不需要很难。


1【问题】【编程基础】如何用一行代码,互换两个变量的值,且不产生第三个变量。

【方法一】【啥玩意儿啊-iOS-北京,提供答案】利用Swift元组特性:
可以在定义的同时就取出元祖中的值
// 相当于同时定义了三个变量
let (name, age, score) = (“a”, 30, 99.9)

根据这一特性,我们可以这样互换值:
(a, b) = (b, a)

【方法二】【消摇提供答案】
(a = a ^ b) && (b = a ^ b) && (a = a ^ b) 或者这样 a = a ^ b; b = a ^ b; a = a ^ b;

(a = a + b) && (b = a - b) && (a = a - b)
(a = a x b) && (b = a / b) && (a = a / b)

【方法三】【消摇提供答案】
a = ( a + b ) - b * ( b = a );


2【问题】【iOS】如何给view同时加上圆角和阴影?至少给出两种实现方法,使用到的API越高级越好。
【提示】两种方法,答案提示:UIBezierPath,和iOS11 layer有个新的方法
【答案】iOS11的layer是maskedCorners,CACornerMask。

参考链接:

标题&链接 手机端阅读
标题:ios 圆角 cornerRadius 对性能的影响究竟多大? 你测试过吗?
链接:https://www.jianshu.com/p/13820dbf5d20

3【问题】【计算机常识】在开发中,我们在重连等场景中,为避免造成过度的资源消耗,我们常常把重试的时间间隔做递增处理,有时是指数级增长方式,比如第1次与第二次时间间隔为2秒,第二次与第三次时间间隔为4秒,然后是8秒,我们有时也按照1,3,5这样的规律递增。这种编程技巧的名称是什么?

【答案】指数退避算法。


4 【问题】【算法】《易传·系辞上传》:“易有太极,是生两仪,两仪生四象,四象生八卦。”,这句话结合下面的几张图,与计算机数据结构中的哪个概念更为相近,描述该概念,越详细越好。问题如下:
六十四卦所在结构中节点数是多少?
六十四卦中的任意一卦,在上述数据结构体系中对应的概念叫什么?
六十四卦中的任意一卦的高度与深度分别是多少?
“完全” 与 “满” 用哪一个,形容下面的图片更为贴切?

14153248314177 jpg

v2-30f016d2570d0f3717312be92922fb9c_r

【答案】总体是二叉树,高度是 0 深度是7,节点数是 2ˆ7-1, 满二叉树。参考下图:

image


5【问题】【hybrid-app】js与native交互中,js如何调用native方法,native如何调js方法,借助的中间foundation叫什么。给出核心步骤对应函数,重点给出前端和native需要约定联调的部分。【难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】
【提示】推荐 《一本走心的 JS-Native 交互电子书》
【答案】【群成员闪舞提供】
native 能直接调用 js
[webView stringByEvaluatingJavaScriptFromString:javascriptCommand];

js 不能直接调用 native 的方法,但是可以间接的通过一些方法来实现。可以利用 UIWebView 的 webView: shouldStartLoadWithRequest: navigationType: 代理方法来做。 WKWebView 中可以通过 webView: decidePolicyForNavigationAction: decisionHandler:

要想触发native 的 webView: shouldStartLoadWithRequest: navigationType方法,可以通过下面两种形式:
1.创建 iframe 标签
2.设置 window 的 location

核心步骤:

  1. native 加载 html,其中的 script 标签里(也就是 js 代码), js 创建 iframe 标签,并设置它的 src 属性为 wvjbscheme://BRIDGE_LOADED,并且把回掉放到一个数组里
    2.在 webView: shouldStartLoadWithRequest: navigationType 方法中拦截 wvjbscheme://BRIDGE_LOADED,并加载本地(桥中)的 js
    3.本地(桥) js 创建隐藏的 iframe 标签并且修改 src 为 wvjbscheme://WVJB_QUEUE_MESSAGE,这样就又能在 webView: shouldStartLoadWithRequest: navigationType 拦截了。

6【问题】【iOS】猜想dequeueReusableCellWithIdentifier的实现是怎样的,给出示例代码。注意边界条件:相邻cell的identifier相等时。你的实现中该函数的时间复杂度是多少。为什么?【难度🌟🌟🌟🌟】【出题人 微博@iOS程序犭袁】
cell复用机制的实现猜想,见 GitHub-Chameleon

- (UITableViewCell *)dequeueReusableCellWithIdentifier:(NSString *)identifier
{
   for (UITableViewCell *cell in _reusableCells) {
       if ([cell.reuseIdentifier isEqualToString:identifier]) {
           UITableViewCell *strongCell = cell;
           
           // the above strongCell reference seems totally unnecessary, but without it ARC apparently
           // ends up releasing the cell when it's removed on this line even though we're referencing it
           // later in this method by way of the cell variable. I do not like this.
           [_reusableCells removeObject:cell];

           [strongCell prepareForReuse];
           return strongCell;
       }
   }
   
   return nil;
}

时间复杂度为: O(n)

注意:

NSArray / NSMutableArray

containsObject:containsObject:indexOfObject*removeObject: 会遍历里面元素查看是否与之匹对,所以复杂度等于或大于 O(n)。

这里 _reusableCells 使用的是NSMutableSet,而
NSSet / NSMutableSet / NSCountedSet

这些集合类型是无序没有重复元素。这样就可以通过 hash table 进行快速的操作。比如 addObject:, removeObject:, containsObject: 都是按照 O(1) 来的。需要注意的是将数组转成 Set 时会将重复元素合成一个,同时失去排序。

加之 for 循环,可以得到复杂度计算结果。

参考:《深入剖析 iOS 性能优化》


7【问题】如图:用autolayout做下横竖屏适配:【难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】

里面:蓝色是父视图,子视图是Label和图片,图片可拉伸。Label和图片总是相对居中显示。
对图片顶端,label底端,拉伸,水平总是居中。

Screenshot 2019-04-26 at 8 56 03 PM

【答案】把两个子视图,包一层View,不一定是StackVIew,也可以是普通View,内部搞好约束,top、left、bottom、right。再对中间层view做水平、垂直居中操作即可。

类似前端方案:【十代-小公司-泉州iOS提供】
使用 FlexLib 框架:

Pasted Graphic 1
Pasted Graphic 2


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


One more thing...

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


image

iTeaTime(技术清谈)【-005期】【代号:赤壁】

iTeaTime(技术清谈)【-005期】【代号:赤壁】





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

大话人工智能:从赤壁之战到神经网络

⚠️⚠️⚠️warning:本文涉及“开车”内容,部分内容可能令你不适,更适合22岁以上具有独立思考的男性阅读。

本文也是《深度学习的数学》的读后感,后文也会介绍这本书。

这是 iTeaTime(读作:IT Time,中文名:技术清谈) 第一次涉及人工智能的话题,所以谈得比较浅,后续还有有人工智能相关的话题,会谈得深一点。

引言

如果你问女朋友“是否听过神经网络、深度学习”,她可能会说”没有“。

但是当你问她“是否听过人工智能”,她八成说听过。如果还说没有,那就拿出大杀器--”围棋人机大战“。

人工智能的一个特点便是:

人工智能一旦在某一个领域超越人类,人类将永远无法反超。

人工智能之所以能如此智能,便完全来自于7乘24小时的深度学习。深度学习灵感最初是来自于仿生学,仿的是大脑的运作规律。在人工智能中,堪比大脑的部分正是神经网络。

本文将从赤壁之战讲到神经网络,带你打开人工智能的大门,一睹深度学习的真容。

从赤壁之战到简单神经网络结构

话说,赤壁之战激战正酣,然而有趣的是:我们故事里的三位男主--魏蜀吴三国统帅却都在一个微信群中,也没人退群。似乎这个群里正在进行着某种不可告人的交易。

下图就是这个“赤壁之战微信群”的群关系。

群里还埋伏有两名战地记者,同时也是当代著名的战略家: Tom 和 Jerry ,这对欢喜冤家,他们都想挖掘赤壁里两性相关故事,但就是这样一个细分领域,他们俩儿研究的题材却“截然不同”:一个是爱情、一个是基情。

群里有12位草民,他们并不属于魏蜀吴任何一个阵营,却“唯钱是从”,他们最感兴趣的是领赏、抢红包。他们可以是魏蜀吴三家任意一家的手下。

但12人中也分为三类,他们各自打听到了魏蜀吴三国统帅其中一位的兴趣,于是默默记下并格外关注此类型佳人。

魏蜀吴三国统帅在群里,一直想悬赏寻找一个佳人晚上来临幸。要求草民们随时留意。

此时群里新来了一个神秘人,没人知道神秘人身份,随着12名手下在群里的欢迎词,还有魏蜀吴三国统帅的上线,以及三位男主各自的活跃程度,群里炸了锅。

Tom 和 Jerry 两位八卦记者,马上嗅到了新闻的味道。马上炮制10w+网文。

而本文的读者,作为吃瓜群众,你最想知道的可能就是神秘人的性别,所以从 Tom 和 Jerry 的网文中你就可以清晰地判断出。

上面出现的种种人物,可谓是“各怀鬼胎”,下图描述了每个人的兴趣点:

神秘人出现时,12位手下“盲人摸象”猜测神秘人的身份:

12位手下每个人描述的都是同一个人,说的都是“部分正确的”,但是他们的描述全都是出于自己的猜测,
同时也存有侥幸心理,他们也在赌自己描述的关键词,能命中某一位男主,以此来邀功拿到赏赐。这几个手下含糊其辞,却煞有介事的描述,非常类似“谁是卧底 (快乐大本营游戏)”的规则。

上图也描述了典型的三层神经网络的基本构成为:Layer L1是输入层,Layer L2是隐含层,Layer L3是输出层。

当我们不考虑对内部结构进行细化,我们可以称这种为简单神经网络结构。

我在这里构建的场景,左侧列出了简单神经网络结构,右侧为了能形象说明各个层级的作用,我拿赤壁之战的三个男主进行了类比。

这个类比,可能比较荒诞不经,那么我们就举一个正经的例子,比如:让神经网络判断一个在12格中手写的数字是0还是1。

这时

故事 神经网络概念对应
输入层的12个手下 与手写输入的12格一一对应,主要负责进行信息录入。
12位手下盲人摸象 指对0或1的局部特征进行匹配,一旦局部特征匹配成功就会变得兴奋。
隐藏层,三位男主静静等待12位手下各自兴奋,然后观察关系比较好的手下的表现,激发自己的兴趣。 就对应于12格特征匹配率中,看哪一个数字的特征匹配度更高,隐藏层的对应的神经单元就被激活。
输出层观察男主,写男主与美女的爱情故事,或者写男主的基情故事。 就对应于输出层的神经单元被隐藏层的某一个数字对应的神经单元激活。

注:简单神经网络结构示意图的探讨还未涉及卷积神经网络,卷积的概念后文会进行讨论。

简单神经网络结构中,输入层主要作用就是盲人摸象,隐藏层主要作用就是静静等待输入层的信息。

从赤壁之战到卷积神经网络结构

随着时代的变迁,封建制度更加完善,帝王的帮手也越来越多,他们已经不满足于守株待兔,而是组织人力主动出击。于是就有了更加细化的“卷积神经网络结构”。

而且似乎上个故事里只捕风捉影操作信息还是不太形象,为了让类比更形象,这个故事里我们就开始直接用“抓人”来代替“捕获信息”的设定。

下图描述了该结构的特点:

我们可以看到,主要是隐藏层发生了变化,由简单的一层,变为了 ”卷积操作+卷积层+池化层“的架构,
同时我在图里把输入层的作用也弱化了。

以猴哥为首的锦衣卫,凭借自己”火眼金睛“的特异功能,主动出击。主动在输入层中开启人脸扫描,马上把潜在的群友,按照”宁可错杀不可放过“的原则统统抓起来,押往东厂。

东厂会对锦衣卫押送过来的人进行精选,精选的方式有很多,比如挑选最符合帝王喜好的那一位,直接押送铜雀台。

后续流程和简单神经网络就保持一致。唯一的区别就是,Tom 和 Jerry 不再需要看各位男主的兴奋程度来推测,而是直接从铜雀台进行判断就可以了。

在这个故事中我们引出了“卷积神经网络结构”,如果说简单神经网络结构中输入层主要作用就是盲人摸象,隐藏层主要作用就是静静等待输入层的信息。

那么卷积神经网络结构中,隐藏层就要更为活跃,隐藏层成立了卷积层和池化层,并有个卷积操作用来主动出击。

故事 神经网络概念对应
锦衣卫的火眼金睛扫描 对应于卷积操作
东厂 对应于卷积层,用来存放卷积操作的结果。
铜雀台 对应于池化层,用来对卷积层的结果进行进一步提炼,提炼的方法有很多种,最常见的是最大池化。
挑选最符合帝王喜好的那一位,直接押送铜雀台 最大池化

深度学习的数学读后感

以上的故事是《深度学习的数学》这本书里我提炼出来并进一步演绎的故事。

对应的示意图:

参考: 《这本书让我摆脱了被数学支配的恐惧!》

下面也介绍也这本书。

本书介绍

本书属于计算机类图书:

  • 划分类别:科普类

  • 易读性:五星

  • 专业性:三星

  • 观点创新性:三星

  • 实体图书质量:四星

  • 综合推荐等级:四星

  • 个人推荐等级:三星半

本文是一篇“《深度学习的数学》读后感”,书籍作者毕业于数学系,对数学研究颇深,全书虽然是深度学习,却没有一行代码,读完不禁让人手痒,无处施展,于是作者独辟蹊径,给了一种使用 Excel 来“体验”的途径,不过整体体验欠佳,本来以为会使用复杂的函数,结果均为简单的加减乘除。但是也能从侧面进行理论验证,也算一种动手实践途径。作用和示意图一样,是理论文字版本的另一种演绎。如果理论你已经完全掌握,那么 Excel 的环节可能有点鸡肋。如果理论你根本读不下去,那么 Excel 的环节会很有帮助。

作者文中涉及计算机知识非常少,几乎没有深入探讨,每次提到都是浅尝辄止,只起到注解作用。所以本文会添加很多计算机相关的延伸阐述。

本文术语一览:

缩写 术语 含义
dl / DL deep learning 深度学习
DP BackPropagation 反向传播算法

深度学习概念

如果给你下面几个关键词,你会怎么造句?

  • 学习
  • 预测
  • 误差
  • 代价

我先来一个:

学习,比如学开车漂移,终极目标就是人车合一。
所谓人车合一,就是开车前的预想与实际操作的误差最小。所有的误差积累起来就是代价,比如翻车。
所谓漂移出神入化,就是零误差,无代价。

上面造句的内容,其实也引出了《深度学习的数学》这本书里的核心概念。

误差反向传播法的必要性

递推在计算机上的复杂度优势造就了误差反向传播法

学习过深度学习一定绕不开 BP(反向传播法)的概念,那么为什么是?

选择反向传播而非前向传播,用一句话来总结原因:

计算机擅长递推关系式。(见2-2节)

我们说一个算法“性能”优越,大部分场景讲的是时间复杂度。说计算机擅长递推关系式,是因为通常这个算法时间复杂度更低。

参考 “求斐波那契数列之和” 这个问题,实现方法中,可以分为for in 循环累加和递推关系式等几种方式。
使用递推关系式进行计算的时间复杂度明显优于其他方式,是比较典型的用空间换取时间的策略。

正是递推在计算机上的复杂度优势,造就了误差反向传播法。

激活函数

Q:激活函数不就是一个函数吗?激活一词怎么理解?

A:因为该函数的作用就是用他的取值来决定是否能激活神经元。

内积外积

外积 wedge product 音译
内积 comer/scalar product

神经单元误差

神经单元误差是误差反向传播法的基础。

实际的含义为:

回归分析平方误差与加权输入的关系。

那么问题来了。

误差反向传播法的特点就是将繁杂的导数计算替换为数列的递推。

Q:为什么用导数来表示神经单元误差?导数与误差是什么关系?

A: 导数能表示曲线的斜率,而误差的最小值就是斜率为0时。所以用导数来表示误差,可以方便表示:
当值越大,那么误差就越大。当导数为零时,误差也为零。


One more thing...

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


enter image description here

//one more thing

iTeaTime(技术清谈)【-003期】【代号:模仿游戏之窃听风云】

iTeaTime(技术清谈)【-003期】【代号:模仿游戏之窃听风云】




本期特辑:iOS应用安全与逆向之攻防技能
本期出品人:微博@iOS程序犭袁
本期出题人(排名不分先后):

  • molon-杭州
  • Leo-磊子@微链客
  • 鹅喵-便利蜂移动端
  • SAGESSE-iOS-深圳
  • 风扬-拍拍贷-SOi

注:题目难度五星为满分,以下题目从易到难依次排列。


逆向类


1【问题】【逆向】为什么我们可以在应用编译好之后还能通过 hack 手段塞入一些额外逻辑,原理是什么?

//one more thing

【难度🌟】【出题人:molon-杭州】


2【问题】【逆向】【C】【Objective-C】【ios】逆向C语言应用时,看到的堆栈信息有可读的函数名也有不可读的函数地址,为什么呢?那在逆向 Objective-C 应用时,为什么就能实现看到绝大多数可读函数名?
【难度🌟】【出题人:molon-杭州】

/one more thing/


3【问题】【iOS】
针对iOS应用逆向的常规手段而言,
回答问题:

  • 如何判断我们的 APP 被逆向软件注入,被 hook/hack 了?
  • 如何加固防止别人破解我们的 APP ?
  • 请给出加固的方法,并阐述其原理。

【难度🌟🌟】【出题人:Leo-磊子@微链客 和 molon-杭州】


4【问题】【iOS】App 如何加壳,破壳?AppStore下载的包为何需要砸壳?
【难度🌟🌟】【出题人:SAGESSE-iOS-深圳 和 风扬-拍拍贷-SOi】


5【问题】【iOS】常见的反调试手段有哪些?
【难度🌟🌟】【出题人:鹅喵-便利蜂移动端】


6【问题】【iOS】【验证码】【逆向】某应用的注册验证码接口为了避免恶意滥用,对 POST 数据进行了加密,那倘若我们是攻击者,要通过逆向手段破解这种防护手段保证攻击的持续进行,应该从哪着手呢?
【难度🌟🌟】【出题人:molon-杭州】

/one more thing/


7【问题】【iOS】【验证码】【逆向】如果遇到上述的攻击者,应用开发者还能有什么额外手段去增强防护呢?说到底,解决验证码接口攻击的最终并且一定有效的手段应该是什么呢?
【难度🌟🌟】【出题人:molon-杭州】


8 【问题】【逆向】因为逆向的强大,应用在攻击者手中终归玩物,那网络应用开发者在与其对抗的过程中最大的优势是什么呢?
【难度🌟🌟🌟】【出题人:molon-杭州】


9【问题】【汇编】arm64位系统里的通用寄存器有多少个,分别是干什么的?什么是状态寄存器?
【难度🌟🌟🌟】【出题人:风扬-拍拍贷-SOi】


常规类


10【问题】【iOS】罗列出几个你能立马从崩溃堆栈中识别出的崩溃类型特征,给出调试方法,重点介绍如何调试 BAD_ACCESS 错误。
【难度🌟🌟】【出题人 微博@iOS程序犭袁】


11【问题】【iOS】组件化中,拆库时遇到递归调用问题,如何解决。
【 难度🌟🌟🌟】

/one more thing/


12【问题】【iOS】评价下以下代码:

if (Thread.isMainThread) {
           self.doSomething();
       } else {
           DispatchQueue.main.sync {
               self.doSomething();
           }
       }

func doSomething() {
   print("\(Thread.current.isMainThread)")
   }

【 难度🌟🌟】【出题人 微博@iOS程序犭袁】


13【问题】【iOS】使用 CoreText API绘制文字“我是**人”,要求字体大小18、颜色:“我是”黑色,“**人“红色。【 难度🌟🌟🌟】

//one more thing


14【问题】【iOS】组件化拆分里边string的category拆分成几个类,以什么纬度拆的,除了string外其他category有几个类,分别是做什么的
【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】


15【问题】【iOS】CoreData中几个核心概念及关系阐述下,第三方库 MagicRecord 的读写操作是在什么线程中执行的?为何有人如此讨厌使用CoreData,CoreData适合什么样的项目?CoreData如何进行数据库更新操作?【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】


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


One more thing...

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


iTeaTime(技术清谈)【005期】【代号:变形金刚-擎天柱】

iTeaTime(技术清谈)【005期】【代号:变形金刚-擎天柱】



出题:微博@iOS程序犭袁

本期代号:变形金刚-擎天柱



enter image description here

从未被讨论过的问题,不公布答案。顺延到下一期。只要讨论过,答案不正确也会提供答案。下面将讨论过的问题公布答案:

今天会从没有修改马甲(马甲格式为【昵称+地区/公司/职位】)的同学中随机抽取几位幸运儿,送出飞机票若干张。待会儿我出题,回答任意一道即可,别人回答过的,不能再回答,交卷时间为出题日第二天20点。因为是自己出的题,大部分网上没有答案。可以讨论,没点名同学,抢答正确后,请自觉补充同类型问题一道供点名同学回答。题目能够精准筛选非技术同学即可,不需要很难。


1 【问题】【算法】缓存操作进行优化的措施中,有没有迎合用户“喜旧厌新”的算法技巧,可谓是缓存界的“断舍离”算法?也即:那些过去经常被访问的,将来也很可能被访问,优先级提高。那些长时间不被访问的,直接删了就好。描述下算法的实现原理。给出工作中至少两个使用场景。【 难度🌟】【出题人 微博@iOS程序犭袁】
【答案】LRU彻汰策略,应用场景比如iOS的两个常用库:Lottie、YYCache。


2 【问题】【在IM开发中】app 接收到一个message,上层UI刷新一次,要求考虑到CPU和电量消耗,解决短时间内接收到很多条消息的问题。怎么解决?有几种方案?【出题人:远之²³³³-free zone-北】【 难度🌟🌟】
【答案】

方案一:利用联结(在异步线程上调用dispatch_source_merge_data后,就会执行 dispatch source 事先定义好的handler)、DISPATCH_SOURCE_TYPE_DATA_ADD,将刷新UI的工作拼接起来,短时间内做尽量少次数的刷新。

方案二:自己实现队列、确定一个合适的时间阈值,在阈值时间到达时、主动取消息或者被动接受消息,最后刷新UI,达到消息限流的作用。举例:假设我们消息的获取都是通过长连接推送过来的,而不是主动拉取的。可以用消息队列来做,消费者定期去队列取数据进行数据展示。
或者假设前一条 消息和后一条消息间隔只在0.2s以内,就可以认为是频繁收到消息。然后把这0.2s内的消息刷新相关操作,比如做个动画效果。


3 描述:如图label1在containerView上,containerView、label2在cell.contentView上
问题:label1与label2的字数不固定,需求是,无论label2字数多少,label1都不能被拉伸或者压缩:【 难度🌟🌟🌟】【出题人:记忆、搁浅】

Pasted Graphic 3

效果图见:

Pasted Graphic 4

【答案】需要给label1设置一下优先级,设置平行的的Content compression resistance priority。

系统 Autolayout 参考 :

Masonry 参考以下属性:

   static const MASLayoutPriority MASLayoutPriorityRequired = UILayoutPriorityRequired;
   static const MASLayoutPriority MASLayoutPriorityDefaultHigh = UILayoutPriorityDefaultHigh;

图形化操作见以下动图:

1557371233399


4 【计算机常识】如果你一直在用GitLab开发,现在公司要切换到GitHub开发,可以两个邮箱不一样,你自己的提交记录,GitHub无法识别,签到数据也没了,请问如何让GitHub能够识别你整个仓库中所有的提交记录。【难度🌟🌟】【出题人 微博@iOS程序犭袁】
【注】“签到数据”指的是下图:
image
【答案】参考:

无话不谈

技术清谈,无话不谈。今天带来 iTeaTime(技术清谈)@Never-成都-太合乐动-iOS 的推荐:

编程专用字体:

brew cask install font-fira-code


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


One more thing...

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


image

one more thing

//one more thing

enter image description here

enter image description here

enter image description here

/one more thing/

enter image description here

enter image description here
/one more thing/

enter image description here

/one more thing/

enter image description here

/one more thing/

enter image description here

/one more thing/

enter image description here
/one more thing/

enter image description here

/one more thing/

enter image description here

/one more thing/

-->

//one more thing

//one more thing

//one more thing

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

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 或以上的版本,在自己提供的服务和以上服务之间建立连接。

  • 开发环境: api.sandbox.push.apple.com:443
  • 生产环境:api.push.apple.com:443

当然,还可以用一台机器的 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期】【代号:海王】》
链接:#2

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


One more thing...

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


image

iTeaTime(技术清谈)【-001期】【代号:复仇者联盟】

iTeaTime(技术清谈)【-001期】【代号:复仇者联盟】

出题:微博@iOS程序犭袁





image

从未被讨论过的问题,不公布答案。顺延到下一期。只要讨论过,答案不正确也会提供答案。


  • 1 若把《复仇者联盟》中的世界,看成一个大的代码工程,复仇者联盟的成员看成类/对象,那么请回答下列问题:

奇异博士在联盟中的角色,更像下面哪个?
A. PD
B. PM
C.PRD
D.git
E.other

【答案】D。可以开分支,回退提交。


  • 2 奇异博士在其独立电影中打败大boss(名字叫多玛姆/黑暗次元)的方法更类似于下面哪种?
  • A. 递归
  • B. do while 循环
  • C. for 循环
  • D. 遍历
  • E. other

【答案】B,do while 循环,当自己死亡时,复活自己,直到多玛姆接受谈判条件

  • 3 复仇者联盟,因不满灭霸的break change版本,返回过去修改代码,但是美队他们发现能够看到过去的自己,甚至两个美队可以互打,但是却不能直接杀死小时候的灭霸,基于量子力学的理论,回到过去不能改变历史,最多只能形成平行宇宙,这种现象类似于编程中的哪个概念:
    A.git branch -b
    B.git rebase
    C. git reset --soft HEAD~
    d. git tag
    E. git cherry-pic
    F. Other

【答案】A,平行宇宙的概念就是开分支,继续开发。


  • 4 复仇者联盟中的成员,哪位自带copy方法?

自身有copy能力可以是:

  • 钢铁侠,因为可以无限制造出钢铁侠装备
  • 奇异博士,他可以变出无数分身。

  • 5 变身的浩克与本体博士之间的关系,更类似于下面哪个概念?

A. 封装
B. 继承
C. 多态
D. other

【答案】C。多态。本体与变身之间不共享记忆与意识。


  • 6 灭霸打响指后,蚁人为什么能成功躲过一劫?

A. 蚁人执行了git stash操作
B. 蚁人未提交
C. 蚁人执行了git check -b
D. 蚁人是静态库,无法修改其代码
E.other

【答案】A,B,蚁人被困在量子世界,灭霸的愿望没有覆盖量子世界,所以蚁人更类似于未提交,stash 暂存区也可以讲通。


  • 7 矮人给灭打造的手套,更类似于下面哪个概念:

    A. 集合
    B. array
    C. map/dict
    D. ViewController/Activity
    E. other

【答案】可以是一个dict,每个宝石有对应的坑(key)。也可以是array。

可以从实际工程设计的角度看,如果矮人打造手套时,考虑把他设计为数组或者字典,最主要看什么?
因为宝石的形状是不一样的,所以有自己对应的坑位。

六个宝石要形成阵法,宝石是阵基,得放准,否则可能会爆炸

手套类,里面有响指方法,宝石既然是固定的,而且要有防伪校验,做成属性,比做成数组要方便多了吧。可以在setter里校验真伪。数组适合,元素数量未知。
并且手套就是为了收集几颗宝石打造的,当宝石集齐后,响指方法就可以执行,在响指方法内部校验宝石,不仅保证数量而且保证真实性。宝石是map更方便校验。


  • 8 美队架战斗机到达黑豹的国度-瓦坎达,完美降落在他们的战斗机机场,原理更类似于下面哪种?

A 适配器模式
B 协议
C 接口
D 继承
E 其他

【答案】B协议。只要飞机场,遵循相同的协议,接口相同即可使用。


  • 9 《权利的游戏》中红袍女向光之王发出火焰请求。她总共用了7次消息才成功建立对话。请问她最有可能用的是什么协议?TCP, UDP, 还是IP和ICMP?

TLS + HTTPS connect 的流程示意图:

TCP协议:面向连接的传输层协议,能够处理在传输过程中的丢包、传输顺序混乱等异常情况,也能够有效利用带宽,缓解网络拥堵。 由于TCP协议为了保证传输的可靠,每次连接时,需要经过至少7次收发包请求。


  • 10 【算法】如果无数多的猴子在无数多的打字机上随机的打字,并持续无限的时间,那么在某个时候他们必然会打出莎士比亚的诗集。那么这种说法与哪种不实用得算法类似

【答案】Bogo Sorting 猴子排序。


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


One more thing...

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


021-Victoria的秘密-林薇多003

iTeaTime(技术清谈【-006期】【代号:西部世界】

iTeaTime(技术清谈)【-006期】【代号:西部世界】

主题:iOS13适配专辑
出品人:GitHub@ChenYilong





enter image description here


请对以下【iOS13】标签的问题均为 iOS13 新特性已经引入的新适配问题,发表你的看法,内容不限,必须包括需要适配的解读以及方案,引用的文章需要给出参考链接,必须给出自己的见解:

1 【问题】【iOS13】SwiftUI


2 【问题】【iOS13】iPadOS app for macOS


3 【问题】【iOS13】LBS:Location authority


4 【问题】【iOS13】faster app launch、smaller app updates


5 【问题】【iOS13】Sign in with Apple


6 【问题】【iOS13】iPadOS


7 【问题】【iOS13】Reactive Programming in iOS13


8 【问题】【iOS13】Independent apps on Apple Watch


9 【问题】【iOS13】Dark Mode


10【问题】【iOS13】AR


12【问题】【iOS13】新系统 KVC crash 风险


13【问题】【iOS13】模态界面默认交互改变


14【问题】【iOS13】App Delegate --> Scene Delegate


15【问题】【iOS】【hybrid】针对 RN 开发人员不熟悉native开发的情况下,会出现很多操作,比如绘制一个3000px的cell,cell重用符号滥用,在scrollView上强行拼view而不用tableView,等等,针对这些情况,你作为一个native的开发,怎么避免或者及时预警?

【难度】🌟🌟🌟🌟
【出题人】 大灰灰-平安-iOS-上海


16【问题】【iOS13】SF Symbols in iOS 13


17【问题】嵌套进native的 web 页面,如何展示用户相册图片?

【难度】🌟🌟🌟
【出题人】 颜-物灵-iOS

//one more thing


18【问题】【iOS13】remove 3D touch


19【问题】【iOS13】CryptoKit


20【问题】【iOS】【hybrid】WKWebView 加载本地文件如何做兼容?

【难度】🌟🌟
【出题人】PlutoY-广州YY


21【问题】【iOS】【hybrid】调用 js 绘图库的情况下,调用 js 绘图通过以下方式调用会出现什么情况, 该怎么解决

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    // 调用 js 绘图
}

// 或者

- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation {
   // 调用 js 绘图
}

【难度】🌟🌟
【出题人】 PlutoY-广州YY


22【问题】【iOS】【Android】【hybrid】如何用 js 创建一个原生的 Label 居中显示到某个 ViewController/ activity 上,可以通过 JS 修改 Label 的 text 属性,iOS版本代码如下:

var label = new Label();
label.text("Lefe_x");

// view 为 App 当前显示的 ViewController 的 view,通过 js 获取。
label.addToSuperView(view);

【难度】🌟🌟🌟
【出题人】 百度阅读-Lefe_x


23【问题】【iOS13】NotificationCenter


24【问题】【iOS13】Network


25 【问题】【iOS】 setNeedsLayoutlayoutIfNeeded 调用后,系统布局执行刷新的时机是怎么样的? 如果两个方法同时调用会有什么效果与问题?

   [self setNeedsLayout];
   [self layoutIfNeeded];

【提示】请问各位大佬,团队里写代码随意,很多地方都调用了setNeedsLayout,触发了界面刷新,能不能像前端那样弄个虚拟dom减少频繁刷新对性能的影响?"
看到有些人代码每次setModel都要setneedslayout一下 不知道为啥

【答案】

iTeaTime(技术清谈)@SAGESSE-深圳-某不知名小作坊:

如果同时使用就是强制重新布局。

调用setNeedsLayout是为了减少layoutSubviews的执行次数,如果set一次就修改布局一次,很浪费性能, 所以系统提供了setNeedsLayout 来标记这个区域是否需要重新布局,在下一周期时会调用layoutIfNeeded方法,当检测到标记时调用layoutSubviews进行重新布局。

一般主动调用layoutIfNeeded提前布局是在需要获取位置或者生成动画才需要,所以建议延迟布局。

Q:还有没有像虚拟dom那样计算真正变化 的ui的?

A:系统的layoutSubviews本身就是在计算有没有真正变化

Q:但是里面全部UI都在里面计算了。相同的计算会导致UI刷新么。

A:系统的不会,随非你手动调用setframe/setcenter/setbounds。

Q:像在layoutsubviews里面很多这样写`self.contentView.frame = CGRectMake(25, (SCREENHEIGHT - 280) / 2, SCREENWIDTH - 50, 280); 即使每次相同都会导致刷新吧

A:的确会导致页面刷新, 所以建议检查一下值是否发生了变化再set 比如:

CGRect nframe = ...;
if (!CGRectIsEqual(self.contentView.frame, nframe)) {
  self.contentView.frame = nframe;
}

Q:强行这样判断导致开发效率降低了

A:是很麻烦,但系统己经提供了一套很好的解决方案,自动布局autoresizingMask和约束。它们只在需要的时候才会进行布局。


如果只是setneedlayouts self.view不影响subview的


26 【问题】【iOS】如何借助Xcode搜索所有在block内部的self 单词,借此来排查内存泄漏?

【提示】用instrument工具检测内存泄漏不是更方便吗?
检查不出,很难才出现一两次。但是确实存在,就是不知在哪个地方。几天测试才出现两次。所以才有这个挫招扫描。
【答案】

iTeaTime(技术清谈)@SAGESSE-深圳-某不知名小作坊:

\^(\s*\(.*\)\s*)?\{(.|\n)*?\bself\b[^}]*\}

可能会有误匹配,因为xcode居然不支持平衡组,不然,不可能有误匹配。

一般国际化需要这种方式搜字符串替换。


参考链接:

标题&链接 手机端阅读
标题:iOS13 Compositional Layout
链接:https://juejin.im/post/5d00c430f265da1b8466de01
标题&链接 手机端阅读
标题:iOS 13 升级体验
链接:https://juejin.im/post/5d2587da6fb9a07ed524c774

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


One more thing...

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


//one more thing

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.