// 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;
}
iTeaTime(技术清谈)【006期】【代号:布加迪】
出题:微博@iOS程序犭袁 和他的小伙伴们 本期代号:布加迪
【今日话题】: 你如何看待张小龙的预言:未来2年内,小程序将取代80%的App市场。每次都能听到“2岁多的小程序,终于又双叒迎来了“春天”?”的声音,似乎native每天都在冬天,你会因为市场的影响而更新技术栈,或者调整编程的百分比,为前端多多增加百分比吗?未来前端在你的占比中多少比较合适?
1.【问题】【iOS】参考代码注释内容:
【 难度🌟🌟🌟🌟】【出题人 孙源Sunny@dd】
【答案】
几种 tricky 版本:
重定义 NSLog
以下几种宏定义皆可:
[鹅喵-便利蜂移动端]:
利用编译器的注释特性
[鹅喵-便利蜂移动端]:
下面着重介绍两种,更有技术含量的版本:
深入理解 NSString
NSString
的内存分配实际是很复杂的,可能分配在栈区、堆区、常量区。我们常常以为@"foo",这样的字符串是常量区(也称为常量存储区或
_TEXT
区。),运行时不能改,内存区域映射都是 dyld 干的。其实我们可以简单理解为
NSString
是一个 map 结构,key 存在常量区,的确无法修改,但是 value 是一个静态变量,我们可以运行时修改。常量字符串的内存复制方案
[molon-杭州]提供思路:
首先 Objective-C 中任何两个相同字符串值的声明,即使是存储在不同的变量名中,也是指向同一个对象。
常量区的变量内存地址是连续的。
而常量字符串的指针在
CFString
段里面,内存复制的话只复制 CFString 的 size 就够了。直接操作内存就可修改,只要有权限,内存当中的任何地方都能操作。程序运行起来,可以理解为其汇编代码也是写入内存的。你想靠修改对应位置,塞入汇编代码,修改运行中逻辑都可以。很多计算机病毒就是这么做的。但是一般操作系统提供的 API 会做一定的权限控制,例如不能修改其他进程的,等等,但是只要你能提权也是可以操作,很多外挂、破解基本上都是这么个原理。相对来说, Objective-C 反而显得不安全,对 hook 的亲和力太特么强。像其他语言一般还需要用内联汇编去做层 inline hook,控制堆栈平衡等,而 Objective-C 却没有。
比如如果逆向以下代码:
那么,下图红框部分即为 Objective-C 的常量区:
(逆向结果由[molon-杭州]提供)
常量区:
然后这个常量区
CFString
里对应的char
指针对应的那块内存区域也是连续的。上述代码中
memmove
拷贝的是CFString
的内容,不是这块区域的。首先从
<CoreFoundation/CFString.h>
可以查看CFString
结构体,可以发现其大小跟 CPU 架构有关,结构并不简单,而且
__CFConstStr
属于内部 API 无法访问,所以我们可以模仿重新定义一个类似的结构:以下方案由[Never-成都iOS]提供:
运行结果:
参考文献:
修改 CFString
__DATA
段 方案[孙源Sunny@dd] 提供思路:
cstring
存在__TEXT
,是不可变区域,CFString
存在__DATA
,可以修改,该情况与修改static
变量没什么区别。CFString
在__DATA
端我觉得原因是它的结构里有个 isa 指针指向了__CFConstantStringClassReference
,这种在编译时无法确定,得在动态链接时才知道这个地址并赋值上去。根据 WWDC 2016 - Session 406-Optimizing App Startup Time 的说明:
可知:
__TEXT
,是不可变区域,CFString
存在__DATA
,可以修改,该情况与修改static
变量没什么区别。CFString
在__DATA
端我觉得原因是它的结构里有个 isa 指针指向了__CFConstantStringClassReference
,这种在编译时无法确定,得在动态链接时才知道这个地址并赋值上去。根据 WWDC 2016 - Session 406-Optimizing App Startup Time 的说明:
可知:
__DATA
__DATA
举例说明
NSString
、_TEXT
与_DATA
三者的关系,比如 《iOS控制代码段大小的一些经验》 一文中提到:
如果定义一个
NSString
数组,元素数量庞大,可能会导致__TEXT
代码段非常大。仅仅下面的代码,生成的目标文件大小就可以达到 89.51KB。具体原因并不是字符串的总字节数多,而是元素数量大,中间的取值指令过多。 代码:用到的宏定义:
尽管编译器只在text段的字符常量区生成一份字符,多次使用不会增加字符常量区的大小,但是会增加
__TEXT
段代码的大小,使用 MachOView 工具查看可执行文件,结果如下图:cstring 只有一份,多次调用不会存在多份,但是再通过反编译查看调用语句:
调用的函数会转变成上图的指令,可以看到是从字符常量区取到 rax, 再取到栈空间。这样一个一个的取,由于有非常多个字符串,那么相应的指令就会存在非常多,导致调用函数的代码段变得非常大。而且这样会非常浪费栈空间。
总结就是:
在使用
NSString
时,cstring
只有一份,多次调用不会存在多份,但调用的函数中间还有一步指令,是从字符常量区取到rax
, 再取到栈空间,rax对应的值保存在_DATA
中。上面的题目,修改的就是
_DATA
中的值。cstring 才是 TEXT cfstring 是 `DATA`
CFString
在__DATA
端我觉得原因是它的结构里有个isa
指针指向了__CFConstantStringClassReference
,这种在编译时无法确定,得在动态链接时才知道这个地址并赋值上去.[鹅喵-便利蜂移动端]提供代码实现:
一行代码模式:
运行结果:
Apple 的 opensource 的 CF 是 CFLite,跟生产环境的不一样,可以参考其 README 说明:
Apple 的 opensource 版本:
生产环境版本:
2【iOS】有没有办法通过提供的ipa包然后判断出是支持ipad还是iphone,还是都支持。【 难度🌟🌟】【出题人 SuperDanny-轩宇-珠海iOS】
把IPA解压,包内容的info.plist有个UIDeviceFamily,值=1是iPhone,=2是iPad,=1,2是都支持
[鹅喵-便利蜂移动端][M.W-不知名小作坊-iOS-北京]回答正确
3 【算法】使用熟悉的编程语言,编写一个函数,要求输入与以下列表相似的结构,则返回值为true,否则为false。【注意】输入字符串无限制,英文字符、标点符号均无需特殊处理,与中文一样视为作完整字符。
【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】
【提示】算法实际为回文算法,题目主要在于边界情况处理,在函数顶端要有判空等操作。可自行搜索,下面提供群里提供的答案,如有瑕疵可以指正。
【答案】
python3 的,天生编码支持好,递归做法:
jS版本:
输出结果:
另一 java 版本:
[Jenny]回答。
边界情况,可酌情添加,为加分项目:
4.【算法】要求使用熟悉的编程语言,编写一个函数,要求输入任意字符串,都能返回对称结构的字符串。【注意】输入字符串无限制,英文字符、标点符号均无需特殊处理,与中文一样视为作完整字符。
举例:
输入的原始字符串:
输出的字符串:
【 难度🌟🌟🌟】【出题人 微博@iOS程序犭袁】
【答案】 详细可以搜:最长回文子串算法。
下面是一种时间复杂度为 O(n^2)的写法,并非最优解,最优解为 Manacher 算法, 时间复杂度O(n), 空间复杂度O(n),可自行搜索。:
5【iOS】看下面的方法执行完之后 ViewController 会被销毁吗,ViewController 的 view 会被销毁吗?为什么?
【 难度🌟🌟】【出题人 Saber-ios-望京】
【答案】view被引用,vc没被引用,所以VC被销毁,view不销毁。
详细解释: vc引用view,view对vc无引用。 vc在view在,view在与vc可不在。vc为局部变量,方法结束后直接销毁;vc.view被添加在self.view上,所以不会被销毁.
6【iOS】请给出以下代码的输出结果:
【 难度🌟】【出题人 微博@iOS程序犭袁 】
【答案】
参考: 《iOS中__block 关键字的底层实现原理》
7【问题】【iOS】segment 页面如何进行内存优化。需求描述:segment一次性把所有页面加载出来会导致内存爆增。几个segment 子页面的图片都是高清大图。【难度🌟🌟🌟】【出题人:中鼎iOS攻城狮】
下面答案由【BM-成都iOS】提供:
题目主要有2个核心:1.多个页面 2.高清大图
针对多个页面,用lazy的形式,用时加载就好了。所以题目主要是讨论高清大图。
如果是作为面试题回答:
苹果方法针对超大图片示例:点击查看
主要是2个方向:1.是压缩高清大图导致的内存暴增。2.是现实高清大图导致的内存暴增。(相关资料自行谷歌,太多太杂。)
http://blog.cnbang.net/tech/2578/
如果是作为项目回答:
几乎现在90%的后台服务器都使用的第三方云服务器。资源都是存在对应的云服务器的对象存储器中。
几乎所有的对象存储器都支持在线图片处理。(水印,缩放,格式转换等。):
所以正常开发的标准形式为:服务器下发高清的大图地址,客户端根据控件形式预估使用图片的大小。比如用户上传了一张2000像素的图片作为头像,而你当前只是渲染一个可能30像素左右的头像,那你应该直接使用第三方对象存储器的参数渲染一张50左右像素的图片就完全足够使用了。
https://helpcdn.aliyun.com/document_detail/44688.html?spm=a2c4g.11186623.6.1321.516e2e93zb9HsP
以阿里oos对象存储为例的图像缩放文档
使用webp格式,具体的对比:https://aotu.io/notes/2016/06/23/explore-something-of-webp/index.html
也可以使用在线接口返回webp的图片:文档如下:https://helpcdn.aliyun.com/document_detail/44703.html?spm=a2c4g.11186623.6.1336.cd4b35a8Hg5ETw
理论上只要作为这3点,在正常显示高清大图都不会出现什么问题。
作为另外一个补充:
关于高清大图上传问题。
理论应该尽可能还原用户创造的原始数据。比如用户上传一个头像,虽然现实控件只有100像素。但是理论上不应该客户端直接把图片压缩了上传给服务器,万一以后这张头像会作为背景图呢?
关于流程问题。很多对于资源类型的上传直接使用后台接口上传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](https://user-images.githubusercontent.com/2911921/57426727-fbdd9b80-7252-11e9-9f1e-0e403d56b5ca.png)