├── images ├── wechat.JPG └── iOS │ └── iOSDev-bang.png ├── Bilibili ├── 开发之设计模式.png ├── 组件化综述一.pdf └── iOS组件化项目本地资源加载技术方案.png ├── interview-iOS ├── 字节_面试.pdf ├── 16腾讯音乐iOS面试题2018年7月.md ├── 24阿里iOS五轮面经2019年10月.md ├── 27抖音快手等面试题2020年9月.md ├── 26腾讯iOS六轮面试分享2020年.md ├── 17阿里网易蘑菇街同花顺等面试题2018年7月.md ├── 09头条网易微信阿里美团硕士春招面试题2018年3月.md ├── 13秋招iOS面试总结2018年.md ├── 11天猫蚂蚁金服百度面试题2018年4月.md ├── 22快手X3岗面试题2020年3月.md ├── 14阿里腾讯百度头条美团iOS面试题2018年4月.md ├── 18苏州蜗牛iOS开发面试题2018年春.md ├── 07深圳iOS面试分享2018年4月.md ├── 23抖音面试题2020年3月.md ├── 25小米百度bigo滴滴快手等iOS面试题2020年上.md ├── 06iOS基础问题系列2017年.md ├── 04interview-iOS-4.md ├── 01一份"有点难"的iOS面试题MrPeak2016年.md ├── 02interview-iOS-2.md ├── 08字节跳动面试题:2018年4月.md ├── 15腾讯社招iOS面试记录2018年7月.md ├── 10美团饿了么面试题2018年4月.md ├── 05iOS宝库iOS开发笔试题2017年.md ├── 19新浪公司iOS面试题2019年6月.md ├── 03interview-iOS-3.md └── 12校招攻略43份优质面经汇总iOS开发2018年.md ├── iOSNote ├── images │ └── iOSAppThinPic.png ├── podBundleTargetError.md ├── iOS_Collection_article_List.md ├── iOSAppThin.md ├── CocoaPods │ ├── cocoapods.md │ ├── CocoaPodsHook.md │ ├── cocoapods-pod.md │ ├── cocoapods-plugins.md │ └── cocoapods-PodFile&spec.md ├── map-MobileDev-iOSDev.md ├── UnitTesting.md ├── iOS_StaticLibrary.md └── Analyze │ ├── SDWebImage │ └── 网络网络状态不同加载图片.md │ └── MJRefresh │ └── MJRefresh.md ├── LICENSE ├── .gitignore └── README.md /images/wechat.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevDragonLi/iOSInterviewsAndDevNotes/HEAD/images/wechat.JPG -------------------------------------------------------------------------------- /Bilibili/开发之设计模式.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevDragonLi/iOSInterviewsAndDevNotes/HEAD/Bilibili/开发之设计模式.png -------------------------------------------------------------------------------- /Bilibili/组件化综述一.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevDragonLi/iOSInterviewsAndDevNotes/HEAD/Bilibili/组件化综述一.pdf -------------------------------------------------------------------------------- /interview-iOS/字节_面试.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevDragonLi/iOSInterviewsAndDevNotes/HEAD/interview-iOS/字节_面试.pdf -------------------------------------------------------------------------------- /images/iOS/iOSDev-bang.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevDragonLi/iOSInterviewsAndDevNotes/HEAD/images/iOS/iOSDev-bang.png -------------------------------------------------------------------------------- /Bilibili/iOS组件化项目本地资源加载技术方案.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevDragonLi/iOSInterviewsAndDevNotes/HEAD/Bilibili/iOS组件化项目本地资源加载技术方案.png -------------------------------------------------------------------------------- /iOSNote/images/iOSAppThinPic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevDragonLi/iOSInterviewsAndDevNotes/HEAD/iOSNote/images/iOSAppThinPic.png -------------------------------------------------------------------------------- /iOSNote/podBundleTargetError.md: -------------------------------------------------------------------------------- 1 | ## 更新Xcode14后工程报错解决方案(Pod) 2 | 3 | > Pod工程中的Bundle target签名报错 4 | 5 | - 开启`generate_multiple_pod_projects` 参数工程 6 | 7 | ``` 8 | post_install do |installer| 9 | installer.generated_projects.each do |project| 10 | project.targets.each do |target| 11 | target.build_configurations.each do |config| 12 | config.build_settings['CODE_SIGN_IDENTITY'] = '' 13 | end 14 | end 15 | end 16 | end 17 | 18 | ``` 19 | 20 | - 未开启`generate_multiple_pod_projects` 参数工程 21 | 22 | ``` 23 | post_install do |installer| 24 | 25 | installer.pods_project.targets.each do |target| 26 | 27 | target.build_configurations.each do |config| 28 | config.build_settings['CODE_SIGN_IDENTITY'] = '' 29 | end 30 | end 31 | end 32 | 33 | ``` 34 | -------------------------------------------------------------------------------- /iOSNote/iOS_Collection_article_List.md: -------------------------------------------------------------------------------- 1 | # iOS_Collection_article List 2 | 3 | * **[Optimizing App Startup Time](#OptimizingStartupTime)** 4 | 5 | ## Optimizing App Startup Time 6 | 7 | - [今日头条iOS客户端启动速度优化](https://techblog.toutiao.com/2017/01/17/iosspeed/) 8 | 9 | - [阿里数据iOS端启动速度优化的一些经验 10 | ](https://www.jianshu.com/p/f29b59f4c2b9) 11 | 12 | - [优化 App 的启动时间实践 iOS](https://www.jianshu.com/p/0858878e331f) 13 | 14 | - [**掘金客户端体积瘦身**](./iOSNote/appThin/readme.md) 15 | 16 | ### other 17 | 18 | - [一份走心的iOS开发规范](https://www.jianshu.com/p/c818c00e0690) 19 | 20 | 21 | - [iOS Xcode 的汇编模式切换 22 | ](https://www.jianshu.com/p/bdd0578f356d) 23 | 24 | - 断点的实现原理 25 | - lldb命令行 26 | - [CFRunLoop 从CF层面了解由于CFRunLoopMode机制iOS程序ScrollView的滑动为何如此平滑的原因](https://www.jianshu.com/p/b4667267fd6b) 27 | - CFRunLoopMode 28 | - 使用RunLoop的案例: AFNetworking 29 | - TableView中实现平滑滚动延迟加载图片 30 | - 异步测试 31 | 32 | 33 | -------------------------------------------------------------------------------- /iOSNote/iOSAppThin.md: -------------------------------------------------------------------------------- 1 | ## 掘金iOS端体积瘦身 (2017年9月份) 2 | 3 | ![](./images/iOSAppThinPic.png) 4 | 5 | - **5.1.2版本上线前做了一小部分工作后(pics):** **4.7及以下尺寸机型体积为50.3mb**,**5.5尺寸机型体积为62.2mb** 6 | - **目标 :** **4.7及以下尺寸机型体积为43.2mb**,**5.5尺寸机型体积为52.4mb** 7 | 8 | ## tool 9 | - [检查每个类占用空间大小工具](https://github.com/huanxsd/LinkMap) 10 | - [解压APP 包中图片资源Assets.car](https://github.com/devcxm/iOS-Images-Extractor) 11 | - [未使用图片资源辅助工具](https://github.com/tinymind/LSUnusedResources) 12 | - [TinyPNG的Mac客户端](https://github.com/kyleduo/TinyPNG4Mac) 13 | 14 | ## ARM了解 15 | 16 | - ARMv6:ARM11内核用于iPhone2G和iPhone3G中的架构 17 | - ARMv7:modern ARM内核用于iPhone3GS和iPhone4/S中的架构 18 | - ARMv7s:A6内核用于iPhone5中的架构 19 | - ARM64:A7内核用于iPhone5S/C中的架构 20 | - 之前的支持 (arm64 armv7 armv7s)(删除 armv7) 21 | 22 | 23 | 24 | ## 常见方式 25 | - Architectures: armv7 and arm64 ,移除对**iphone5**以下机型的支持 26 | - Assets: 项目中收藏集版本图片占比75%,大图采取`tinyPNG`压缩. 27 | - pics: 项目中早前的图片资源整合/重复图片删除... 28 | - code: 负责对早前无用的类清理 29 | 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 DragonLi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata 19 | 20 | ## Other 21 | *.xccheckout 22 | *.moved-aside 23 | *.xcuserstate 24 | *.xcscmblueprint 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | *.ipa 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | -------------------------------------------------------------------------------- /iOSNote/CocoaPods/cocoapods.md: -------------------------------------------------------------------------------- 1 | 2 | ## 2021 install cocoapods 3 | 4 | 5 | > 备注:rbenv安装较慢【等】 6 | 7 | ``` 8 | 9 | brew install rbenv 10 | 11 | CFLAGS="-Wno-error=implicit-function-declaration" rvm install 2.6.3 12 | 13 | ``` 14 | 15 | > sudo gem install -n /usr/local/bin cocoapods -v 1.10.1 16 | 17 | ------------- 18 | ------------- 19 | ---------------- 20 | 21 | # ruby.taobao.org停止更新使用cocoapods更新rubychina源 22 | 23 | ## 1. 如何使用? 24 | 25 | ### 1.1请尽可能用比较新的 RubyGems 版本,建议 2.6.x 以上。 26 | 27 | ``` 28 | $ gem update --system # 这里请翻墙一下 29 | $ gem -v 30 | 2.6.3 31 | 32 | 33 | $ gem sources --add https://gems.ruby-china.org/ --remove https://rubygems.org/ 34 | $ gem sources -l 35 | https://gems.ruby-china.org 36 | 37 | // 确保只有 gems.ruby-china.org 38 | 39 | ``` 40 | ### 1.2如果你使用 Gemfile 和 Bundle (例如:Rails 项目) 41 | 42 | 你可以用 Bundler 的[ Gem 源代码镜像命令](http://bundler.io/v1.5/bundle_config.html#gem-source-mirrors) 43 | 44 | ``` 45 | $ bundle config mirror.https://rubygems.org https://gems.ruby-china.org 46 | 47 | 这样你不用改你的 Gemfile 的 source 48 | 49 | source 'https://rubygems.org/' 50 | gem 'rails', '4.2.5' 51 | 52 | ``` 53 | 54 | ## 2.常见问题? 55 | ### 2.1 如果遇到 SSL 证书问题,你又无法解决,请直接用 http://gems.ruby-china.org 避免 SSL 的问题。 56 | ### 2.2 如果你在意 Gem 下载的安全问题,请正确安装 Ruby、OpenSSL,建议部署 Linux 服务器的时候采用 这个 RVM 安装脚本 的方式安装 Ruby。 57 | ### 2.3 Bundler::GemspecError: Could not read gem at /home/xxx/.rvm/gems/ruby-2.1.8/cache/rugged-0.23.3.gem. It may be corrupted.,这类错误是网络原因下载到了坏掉的文件到本地,请直接删除那个文件。 58 | 59 | 60 | 61 | # 文章内容来自[点我](https://gems.ruby-china.org) -------------------------------------------------------------------------------- /iOSNote/CocoaPods/CocoaPodsHook.md: -------------------------------------------------------------------------------- 1 | # CocoaPods Hook 2 | 3 | > CocoaPods 会在其安装生命周期中提供各种 hook。这使用户可以自定义安装过程的多个时间点对其项目进行更改。 4 | 5 | > hook方法还可以做一些其他语言脚本的执行,比如执行shell脚本,使用exec 后面跟上具体命令即可 6 | sh命令文件是一样的 7 | 8 | 9 | 10 | ## pre_install 11 | 12 | > pod install 之前可以做一些其他处理 13 | 14 | ``` 15 | pre_install do |installer| 16 | puts "pre install hook" 17 | Pod::UI.puts "pre install hook " 18 | end 19 | 20 | ``` 21 | 22 | ## post_install 23 | 24 | - pod install 之后可以做一些其他处理 25 | 26 | ``` 27 | post_install do |installer| 28 | puts "post install hook" 29 | exec 'pwd' 30 | 31 | end 32 | 33 | 34 | 35 | post_install do |installer| 36 | # 遍历项目中所有target 37 | installer.pods_project.targets.each do |target| 38 | # 遍历build_configurations 39 | target.build_configurations.each do |config| 40 | # 修改build_settings中的ENABLE_BITCODE 41 | config.build_settings['ENABLE_BITCODE'] = 'NO' 42 | end 43 | end 44 | end 45 | 46 | 47 | # 开启 generate_multiple_pod_projects 48 | 49 | post_install do |installer| 50 | installer.generated_projects.each do |project| 51 | project.targets.each do |target| 52 | target.build_configurations.each do |config| 53 | config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '11.0' 54 | end 55 | end 56 | end 57 | end 58 | 59 | 60 | ``` 61 | 62 | ## post_integrate 63 | 64 | > **1.10新增** 集成是安装过程的最后一步,它负责将生成的 Pods.xcodeproj 与用户的项目集成。这个 hook 将在完成后立即执行。 65 | 66 | - 注意:这个 hook 在所有 .xcodeproj 保存(写入磁盘)之后执行。对 Pods.xcodeproj 进行更改将需要额外的 save 操作,但这可能会很慢。如果您预计在Pods.xcodeproj 保存到磁盘之前对其进行更改,则建议使用 post_install hook。 67 | 68 | 69 | ``` 70 | post_integrate do |installer| 71 | 72 | puts "post_integrate hook" 73 | 74 | end 75 | 76 | ``` 77 | -------------------------------------------------------------------------------- /iOSNote/CocoaPods/cocoapods-pod.md: -------------------------------------------------------------------------------- 1 | # CocoaPods 提交开源的框架之流程摘要 2 | 3 | > [ScreenAdaptationKit-example](https://github.com/DevDragonLi/ScreenAdaptationKit) 4 | 5 | ## pod project 6 | 7 | - 以 cocoapods 官方的`github`模板为基础,创建项目 8 | - `pod lib create nameKit` 9 | 10 | - 创建项目的podspec,如果项目已存在,并无 podspec的情况 11 | - `pod spec create name.podspec` 12 | 13 | ## podspec 14 | 15 | - [guides.cocoapods.org](https://guides.cocoapods.org/syntax/podspec.html) 16 | 17 | - [本仓库详细说明文档](cocoapods-PodFile&spec.md) 18 | 19 | ## lint && tag 20 | 21 | - 验证podspec文件,编辑完podspec文件后需要验证一下这个文件是否可用podspec文件不允许有任何的Warning或者Error:`pod lib lint ` 22 | - `--allow-warnings` 允许有任何的Warning 23 | - `--verbose` 获取更多错误信息 24 | - `--use-libraries` 包含.a 需要添加此参数: 25 | 26 | - `tag` 上传podspec文件中需要指定的tag, 完成上述操作后给项目打tag 27 | - `git tag -m"update lib podspec" "1.0.0"` 28 | - `git push --tags` 29 | 30 | ## 提交到CocoaPods的repo 31 | 32 | - Trunk 服务注册 33 | 34 | ``` 35 | `pod trunk register dragonli_52171@163.com 'DevDragonLi' --description='DevDragonLi' macbook pro' --verbose` 36 | ``` 37 | - 发布:`pod trunk push nameKit.podspec` 38 | 39 | ### 提交到个人的repo 40 | 41 | - 私有的远程索引 pod repo add LFLcocoapods URL 部署到`coding` ,`oschina`等 42 | 43 | - pod repo remove LFLcocoapods 44 | 45 | - pod repo update LFLcocoapods 46 | 47 | - pod spec lint 验证自有库 48 | 49 | - pod repo push LFLTest LFLTest.podspec 50 | 51 | 52 | ## **CocoaPods**管理库的使用技巧 53 | 54 | - pod install --verbose --no-repo-update 只查找本地,而且不联网更新库,快! 55 | 56 | - 使用shell的命名别名来简化 57 | 58 | ``` 59 | setup pod update alias name 60 | 61 | alias pod_update='pod update --verbose --no-repo-update' 62 | 63 | alias pod_install='pod install --verbose --no-repo-update' 64 | 65 | ``` 66 | 67 | 68 | -------------------------------------------------------------------------------- /interview-iOS/16腾讯音乐iOS面试题2018年7月.md: -------------------------------------------------------------------------------- 1 | # 腾讯音乐iOS面试题2018年7月 2 | 3 | > 前言:为防止背题,大部分题目不设标准答案 4 | 5 | > 重点考察面试者的基础知识和思维逻辑,答案的提示见后面&&jianshu.com/p/4d139a1b1863 6 | 7 | ## 正文 8 | 9 | * 题目1、举例两个遇到过印象深刻的外网Crash,并介绍如何发现、定位、解决; 10 | 11 | * 题目2、举例两个性能问题的优化,并介绍如何发现、定位、解决以及原理; 12 | 13 | * 题目3、介绍Objective-C的Runtime机制,并介绍在业务实际应用的例子; 14 | 15 | * 题目4、苹果是如何保证iPhone只安装来自App Store的App? 16 | 17 | * 题目5、你的App如何同后台进行通信?其通信过程包括哪些步骤; 18 | 19 | * 题目6、你有1元、5元、7元三种硬币,求一种方法,用最少的硬币凑出m元;(m∈[100, 1000]) 20 | 21 | * 题目7、产品希望实现一个功能,将10~100张图片直接拼成1个视频,你会如何实现? 22 | 23 | ## 参考答案 24 | 25 | ### 1、Tips 题目几个隐含点: 26 | 27 | * 1、Crash上报方式,考察业务如何监控Crash; 28 | 29 | * 2、Crash定位,考察iOS基础知识:常见Crash类型、Crash日志分析能力(符号化、堆栈分析等); 30 | 31 | * 3、Crash解决,是否为适当的解决方式,如何保证类似问题不再复发; 32 | 33 | ### 2、Tips题目几个隐含点: 34 | 35 | * 1、性能问题的发现,考察常见工具的使用,包括Xcode的Debug Session和Instruments; 36 | 37 | * 2、CPU占用和内存占用,要么是实现方案的优化,要么是空间和时间互换,以优化内存和CPU占用; 38 | 39 | * 3、GPU占用,如何定位和优化GPU占用; 40 | 41 | * 4、加分项:耗电量分析; 42 | 43 | * 5、原理:优化前后的方案对比,考察实现方案的算法分析能力以及基础的计算机体系结构知识; 44 | 45 | ### 3、Tips 46 | 47 | * Runtime是OC的特性,题目是为考察OC的了解程度; 48 | 49 | * 具体的应用过程要考虑到稳定性、性能消耗、可扩展性等。 50 | 51 | ### 4、Tips 52 | 53 | * 苹果的证书机制,考察对苹果生态的了解以及基础的不对称加密; 54 | 55 | * Certificate、Provisioning Profile、App ID、代码签名等。 56 | 57 | ### 5、Tips 58 | 59 | - 两方面考察: 60 | 61 | - 1、网络通信过程,对TCP/IP和HTTP的了解; 62 | 63 | - 2、APP的网络层和业务层如何通信; 64 | 65 | ### 6、Tips 66 | 67 | - 贪心或者动态规划。 68 | 69 | ### 7、Tips 70 | 71 | - 实现方案有几个考察点: 72 | 73 | - 技术选型,从业务的角度出发,细化产品的要求,比如使用场景、用户需求等,再决定用哪些技术解决问题;(Tips:待选方案有AVFoudation、GPUImage等) 74 | 75 | - 实现细节,如何保证使用过程中内存不占用过大、CPU使用不过高; 76 | 77 | 78 | 79 | ## 链接 80 | 81 | - [面试题系列目录](../README.md) 82 | - **上一份**: [腾讯社招iOS面试记录2018年7月](15腾讯社招iOS面试记录2018年7月.md) 83 | - **下一份**: [阿里网易蘑菇街同花顺等面试题2018年7月](17阿里网易蘑菇街同花顺等面试题2018年7月.md) 84 | 85 | ## 赞赏一下旺仔(收集整理不易,且赞且珍惜) 86 | 87 |

88 | 89 | 90 |

91 | 92 | -------------------------------------------------------------------------------- /iOSNote/map-MobileDev-iOSDev.md: -------------------------------------------------------------------------------- 1 | # designbyStuQ 2 | 3 | # iOS 技能图谱 4 | 5 | ## 编程语言 6 | - Swift 7 | - Objective-C 8 | - C++/C 9 | - JavaScript 10 | 11 | ## 操作系统 12 | - Mac OSX 13 | - iOS 14 | - watchOS 15 | - tvOS 16 | - Linux 常用命令 17 | 18 | ## 开发基础 19 | - UI 控件 20 | - Storyboard & Xib 21 | - Core Data & Sqlite 22 | - Core Graphics 23 | - Animation 24 | - Block & GCD 25 | - Test Case 编写 26 | - Framework 27 | - Autolayout 28 | - 手势识别,重力感应 29 | 30 | 31 | ## 开发进阶 32 | - 引用计数 33 | - Runtime 34 | - Runloop 35 | - 对象模型 36 | - Hybrid 37 | - 沙盒机制 38 | - AVFoundation 39 | - Core Text 40 | - 逆向与安全 41 | - class dump 42 | - IDA Pro 43 | - Hopper 44 | - iOS Class Guard 45 | 46 | ##设计模式 47 | - MVC 48 | - MVVM 49 | - 通知 50 | - 代理 51 | - KVO 52 | - 工厂模式 53 | - 命令模式 54 | 55 | ## 函数式编程 56 | - ReactiveCocoa 57 | - RxSwift 58 | 59 | ## 开发工具 60 | - IDE 61 | - Xcode 62 | - AppCode 63 | - 调试工具 64 | - Charles、Wireshark 65 | - Reveal 66 | - Instruments 67 | - 插件 68 | - Alcatraz 69 | - VVDocument 70 | - XVim 71 | - FuzzyAutocompletePlugin 72 | - KSImageNamed-Xcode 73 | - 辅助工具 74 | - xScope 75 | - ImageOptim 76 | - 马克鳗 77 | - Dash 78 | - Deploymate 79 | - FauxPas 80 | - PaintCode 81 | - 命令行工具 82 | - xcodebuild、xcode-select 83 | - nomad 84 | - xctool 85 | - fastlane 86 | - 持续集成 87 | - Jenkins 88 | - Travis CI 89 | - Bot 90 | 91 | ## 开源项目 92 | - AFNetworking & Alamofire 93 | - Masonry 94 | - SDWebImage 95 | - SwiftyJSON 96 | - JSPatch 97 | - React Native 98 | 99 | ## 包管理 100 | - CocoaPods 101 | - Carthage 102 | - Swift Package Manager 103 | 104 | ## App 打包上传与审核 105 | - Apple Developer 网站 106 | - Itunes Connect 网站 107 | - IAP 108 | - 加急审核申请 109 | - 打包脚本 110 | 111 | ## 第三方服务 112 | - 崩溃收集 113 | - Bugly 114 | - Crashlytics 115 | - BugHD 116 | - 数据统计 117 | - Google Analytics 118 | - 友盟 119 | - MTA 120 | - Flurry 121 | - App Annie 122 | - 应用分发 123 | - TestFlight 124 | - 蒲公英 125 | - FIR 126 | 127 | 128 | 129 | 130 | 131 | -------------------------------------------------------------------------------- /interview-iOS/24阿里iOS五轮面经2019年10月.md: -------------------------------------------------------------------------------- 1 | # 阿里 iOS 五轮面经分享 2 | 3 | > https://www.nowcoder.com/discuss/302113 4 | 5 | > 作者:aaaaaazzzz 6 | 7 | > 感觉牛客很少看到iOS的面经了,今天收到了阿里的意向书,来分享下面经,希望大家都Offer++~! 8 | 总体感觉面试官都非常好,会提前沟通面试时间,交流沟通顺畅,团队也切合。 9 | 10 | >面试主要问基础知识+实习项目经历。 11 | 12 | 13 | ## 阿里一面 14 | * Objective-C和Swift对比,安全性体现在什么方面? 15 | * 你觉得苹果在设计OC和Swift时候,都有哪一些考虑?为什么这样设计,这两门语言。 16 | * 有没有读过iOS相关的源码? 17 | * RunLoop 18 | * RunTime 19 | * @property 调换顺序之后是否会重新编译 20 | * 是否看过第三方库的源码,说一下设计巧妙的地方 21 | * 你们写的App中,有没有遇到什么大的bug,是怎么调试的? 22 | * Block 23 | * 两个链表判断成环 24 | * 你有什么优点和缺点(突然问个非技术问题hhhh) 25 | * Block循环引用,怎么解决 26 | * 不可变量进行Copy 深拷贝,还是浅拷贝 27 | * @property 哪些关键字 28 | * GCD有哪些类型 29 | * 串行和并发队列 30 | * 队列的优先级 31 | * JSPatch 怎么做的,原理是? 32 | * Google Summer of Code 主要是做了什么事情? 33 | * 卷积神经网络原理?怎么减少参数的? 34 | * 你们的APP是怎么分工的?你主要做的什么?怎么设计的,可以说一下吗? 35 | * 你们的APP相对于市面上已经有的APP,有什么样的优势?集成以及一些新的功能。 36 | * 平时是怎么学习iOS的? 37 | ## 阿里二面 38 | * JSPath的原理,热修复是怎么做的?热修复如果用Python的话要怎么做? 39 | * 你们APP的优势体现在哪里?为什么做? 40 | * 相似照片算法是怎么样的一个过程? 41 | * 说一下你的一个项目?需求是什么,遇到的问题是什么,你是怎么解决的? 42 | * 快速排序 43 | * 源代码到可执行程序的过程 44 | * 词法分析做什么? 45 | * 卷积神经网络的原理,怎么减少参数的? 卷积核 46 | * ARKit 了解吗? 47 | * 实验室工作,技术问题 48 | * 其他的忘记了 49 | 50 | ## 阿里三面 51 | > 交叉面。主要是根据项目进行询问。 52 | 53 | * 点击APP启动过程 54 | * MVC中C的理解 55 | * JSPath,是如何实现的? 56 | * 百度实习的难点 57 | * 未来的计划 58 | * A-B-C 三个任务分别指向,如何控制顺序? 59 | * 其他的忘记了 60 | 61 | ## 阿里四面 62 | 63 | > 交叉面。主要是根据项目进行询问。 64 | 65 | * 豆瓣和百度的不同风格 66 | * 架构上的区别 67 | * 怎么保证界面的流程性? 68 | * UI优化 69 | * 数据优化 70 | * 如何用Core Graph画圆 71 | * 你自己的APP用的什么架构 72 | * IP 地址用 int 保存和读取转化(当时。。卡住了,Python写多了都忘记了int第一位是符号位) 73 | * APP的相似照片检测算法 74 | * 相似还是相同 75 | * 性能怎么样 76 | * 人脸识别能做吗? 77 | * 除了 iOS 还学了别的什么吗?(那很多了......) 78 | * 其他的忘记了 79 | 80 | ## HR面 81 | 82 | > HR面一半时间都是在问技术。 83 | 84 | * 讨论下详细的APP设计(讨论了很久) 85 | * 多线程是怎么选个数的?有没有大小的限制? 86 | * 未来的职业规划 87 | * 希望有帮助,十月大家一起加油呀~!希望大家都Offer++~! 88 | 89 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 90 | 91 |

92 | 93 |

94 | 95 | ## 链接 96 | 97 | - [面试题系列目录](../README.md) 98 | - **上一份**: [第23份:抖音面试题2020年3月](./23抖音面试题2020年3月.md) 99 | - **下一份**: [第25份:小米百度bigo滴滴快手等iOS面试题2020年上](./25小米百度bigo滴滴快手等iOS面试题2020年上.md) 100 | = -------------------------------------------------------------------------------- /interview-iOS/27抖音快手等面试题2020年9月.md: -------------------------------------------------------------------------------- 1 | > 备注:此题目为掘金技术群某帅哥授权分享【Along】😁 2 | 3 | 4 | ## 抖音商业化团队 5 | 6 | > 自我介绍 7 | 8 | > 聊聊之前的项目 9 | 10 | ### 你对iOS多线程的认识 11 | 12 | ### OC消息发送机制,objc_msgSend那一套 13 | 14 | ### runloop理解 15 | 16 | ### 做过哪些性能优化 17 | 18 | ### 一道算法题,求数组逆序数,要求说出来思路,并且白板编程 19 | 20 | ## 快手公共平台组 21 | 22 | > 1.自我介绍,聊聊之前的项目巴拉巴拉。 23 | 24 | ### 多线程,runtime,runloop,objc_msgSend 流程 25 | 26 | ### 做过哪些性能优化,哪些情况会引起离屏渲染 27 | 28 | ### autorelease pool 29 | 30 | ### setneeddisplay 和 layoutifneed 的区别 31 | 32 | ### 什么情况会触发layoutsubviews 33 | 34 | ### 大概问了下数据结构的一些问题,堆排序 35 | 36 | 37 | ## 其他家的面试题目 38 | 39 | ### websocket说下你对这个协议的理解 40 | 41 | ### 让你实现一套小程序框架,你怎么实现(有点变态) 42 | 43 | ### https/http 区别。https 过程 44 | 45 | ### 排序算法用过哪些,原理 46 | 47 | ### C++智能指针了解过么? 48 | 49 |
50 | 参考内容 51 | 52 | > c++里面的四个智能指针: auto_ptr, shared_ptr, weak_ptr, unique_ptr 其中后三个是c++11支持,并且第一个已经被c++11弃用。 53 | 54 | - 我们知道c++的内存管理是让很多人头疼的事,当我们写一个new语句时,一般就会立即把delete语句直接也写了,但是我们不能避免程序还未执行到delete时就跳转了或者在函数中没有执行到最后的delete语句就返回了,如果我们不在每一个可能跳转或者返回的语句前释放资源,就会造成内存泄露。使用智能指针可以很大程度上的避免这个问题,**因为智能指针就是一个类,当超出了类的作用域是,类会自动调用析构函数,析构函数会自动释放资源** 55 | 56 |
57 | 58 | ### NSNotification 为啥要设计成在同一个线程里面执行任务 59 | 60 |
61 | 参考内容 62 | 63 | > 官方的文档,是这样写的: 64 | 65 | ``` 66 | In a multithreaded application, notifications are always delivered in the thread in which the notification was posted, which may not be the same thread in which an observer registered itself. 67 | 68 | 在多线程应用中,Notification在哪个线程中post,就在哪个线程中被转发,而不一定是在注册观察者的那个线程中。 69 | 70 | ``` 71 | - 出于线程安全的角度来考量的。官方文档告诉我们,**NSNotificationCenter是一个线程安全类,我们可以在多线程环境下使用同一个NSNotificationCenter对象而不需要加锁**。 72 | 73 | 74 |
75 | 76 | 77 | ### HTTP2.0 有什么变化 78 | 79 | ### js里面的变量let var 区别,js里面的原型和继承了解么 80 | 81 | ### 单向链表相交怎么判断 82 | 83 | ### SwiftUI 和 绑定技术 84 | 85 | ### 强引用弱引用的区别,是怎么实现的 86 | 87 | ### block原理 88 | 89 | ### 设计模式知道哪些,在项目里面用到哪些,你的项目架构是怎么设计的 90 | 91 | ### 如果类似数组越界这种随机崩溃情况,交给你处理,你有什么处理的思路么?从哪些方面入手。 92 | 93 | 94 | ## 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 95 | 96 |

97 | 98 |

99 | 100 | ## 链接 101 | 102 | - [面试题系列目录](../README.md) 103 | - **上一份**: [第26份:腾讯iOS六轮面试分享2020年](./26腾讯iOS六轮面试分享2020年.md) 104 | 105 | -------------------------------------------------------------------------------- /interview-iOS/26腾讯iOS六轮面试分享2020年.md: -------------------------------------------------------------------------------- 1 | # 26 腾讯六轮面试分享 2020年 2 | 3 | > 原地址 jianshu.com/p/002294f9627b (暂无参考答案,后续此处更新) 4 | 5 | ## 第一面,视频面试 6 | 7 | > 两个人分别面试,问的基础的比较多,因为还涉及到音视频的开发,所以音视频方面的知识点也问了一些 8 | 9 | * 常见的属性修饰符有哪些,使用copy应该注意些什么 10 | * 深拷贝和浅拷贝区别 11 | * atomic 真的安全么,加的锁是哪种锁 12 | * iOS中内存管理是怎么样的 13 | * 自动释放池原理,本质 14 | * 常见的内存泄漏有哪些 15 | * block 出现循环引用的原因 16 | * 线程和runloop之间的关系是怎么样的 17 | * GCD 中串行并行队列,同步异步的区别 18 | * 有遇到过死锁么,怎么产生的 19 | * runtime查找方法的过程 20 | * runtime 是怎么实现weak置nil的 21 | * 关联对象是线程安全的么 22 | * isKindOf 和 isMemberOf 区别 23 | * ios Class结构 24 | * load 和 initialize 区别 25 | * 说一下kvo实现的原理,使用kvo需要注意什么,手动触发应该怎么做 26 | * 有多个分类实现同一个方法,最后会执行哪个 27 | * iOS 产生卡顿的原因,什么是离屏渲染 28 | * 沙盒文件目录 29 | * 说一下从点击屏幕开始到某个按钮触发中响应链传递机制,如果要更改响应范围怎么做 30 | * 常用的锁有哪些,性能怎么样 31 | * xcode从开始编译到app出现第一个界面中之间进行了哪些工作(分成xcode编译成功和app启动讲的) 32 | * 音视频开发的简单流程 33 | * PCM 数据格式是怎么样构成的 34 | * 常见的音频压缩方式,优缺点 35 | * 算法题:链表的反转 36 | * 有什么要问的么 37 | 38 | ## 第二面,视频面试 39 | * 项目中哪个功能最能体现自己的技术实力?具体讲一下 40 | * 对mvvm,mvc的理解,项目中怎么体现的 41 | * 有用过多线程技术么,在项目中怎么做的 42 | * iOS 单元测试简单流程 43 | * 查找算法的实现 44 | * 对hash算法了解么,iOS中哪些地方用到了hash算法,hash冲突怎么解决 45 | * 有什么要问的么 46 | 47 | ## 第三面,电话面试 48 | * 项目中哪个功能最能体现自己的技术实力?具体讲一下 49 | * 常见的崩溃有哪些,遇到崩溃问题怎么查找解决,遇到无符号化的崩溃怎么处理 50 | * 数据库读写安全,表结构发生变化,怎么合理更新数据库缓存 51 | * 设计模式有哪些,在项目中怎么体现的 52 | * app性能优化(分别从cpu和gpu优化去讲的) 53 | * 除了oc,有学习别的语言么,一般是怎么学习的 54 | * 为什么离职,离职原因说一下 55 | 56 | ## 第四面,视频面试,是交叉面试,别的部门的面试官来面的 57 | 58 | * 为什么离职,为什么不考虑转岗 59 | * 项目中哪个功能最能体现自己的技术实力?具体讲一下 60 | * 选一个功能实现,讲一下实现思路和方案,遇到问题是怎么解决的 61 | * 为什么做iOS, 有看过iOS相关的书籍么 62 | * 讲一下https 数据发送过程 63 | * 看过iOS相关的源码实现么,realizeClass做了哪些, class_rw_t和class_ro_t 区别 64 | * 手画一下mvvm结构图,讲一下你的理解 65 | * 不用临时变量交换两个int类型数(加减法,但要注意边界值溢出问题,有符号 -231~231-1,无符号 0~2^32-1) 66 | * 设计一个缓存机制需要注意哪些点(lru算法,线程读写安全) 67 | * 写一下lru算法(双向链表+hash) 68 | * 有什么要问的么 69 | 70 | ## 第五面,电话面试,面试委员会面 71 | * 涉及的知识点是更为广泛 72 | * 项目中哪个功能最能体现自己的技术实力?具体讲一下 73 | * http1.1和2.0有什么区别,Keep-Alive模式 74 | * tcp长连接和短连接的区别 75 | * mvvm,mvp,mvc的区别 76 | * 面向对象设计的六大设计原则是什么 77 | * 红黑树有了解么 78 | * 如何用两个栈实现队列功能 79 | * 常见的锁有哪些,实现奇偶数交叉打印 80 | 81 | ## 第六面,hr面试 82 | 83 | > 未完,待续。。。 84 | 85 | 86 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 87 | 88 |

89 | 90 |

91 | 92 | ## 链接 93 | 94 | - [面试题系列目录](../README.md) 95 | - **上一份**: [第25份:小米百度bigo滴滴快手等iOS面试题2020年上](./25小米百度bigo滴滴快手等iOS面试题2020年上.md) 96 | - **下一份**: [第27份:抖音快手等面试题2020年9月](./27抖音快手等面试题2020年9月.md) 97 | 98 | -------------------------------------------------------------------------------- /iOSNote/UnitTesting.md: -------------------------------------------------------------------------------- 1 | # Unit Testing 2 | 3 | 4 | ### 前言 5 | 6 | - `维基百科` 模块测试 7 | - 通常来说,程序修改一次就至少需要一次单元测试 8 | - 一般开发人员编写 (敏捷开发注重) 9 | - 测试是技术,但更是文化,测试你的软件,不然你的用户就要测试. 10 | 11 | 12 | ### 单元测试流程 13 | - 需求分析 -> 流程设计-> 技术选型-> 实现架构(方案)-> 编码-> 高保真实现-> `测试`-> 重构 14 | - 在编码前 ,我们会罗列功能点,我们自己加以验证,对这些功能细化,就属于测试用例 15 | 16 | ### 出发点 17 | 18 | - 正常使用覆盖足够多的场景,(错误场景程序依然足够健壮) 19 | - 异步API调用在多线程下没有异常 20 | - 良好的性能 21 | 22 | - `Mock` 23 | 24 | ### 测试用例: `条件`.`动作`.`结果` 25 | 26 | - 编写条件和动作,设置预期结果然后系统决定最终的结果. 27 | 28 | ### 好处 29 | 30 | - 发现代码缺陷 ,职称不断重构和演进 31 | - 会让我们的代码更加模块化,低耦合 32 | 33 | 34 | ### 开发性质 35 | 36 | - UI 37 | - 业务逻辑 `部分` 38 | - SDK/公共组件/能力层开发 `一定要有对应单元测试` 39 | 40 | 41 | ### iOS单元测试代码部分 42 | - 一些常见的宏 43 | 44 | 45 | ``` 46 | // XCTAssertNil(<#expression, ...#>) // expression为空测试通过不然失败,接受id 类型数据 47 | // XCTAssertNotNil(<#expression, ...#>) // expression不为空测试通过不然失败,接受id 类型数据 48 | 49 | // XCTAssert(<#expression, ...#>)// expression为true测试通过不然失败,接受 bool 类型数据 50 | // XCTAssertFalse(<#expression, ...#>) expression为false测试通过不然失败,接受 bool 类型数据 51 | 52 | // XCTAssertEqualObjects(<#expression1#>, <#expression2, ...#>) expression1 和expression2 地址相同就是通过 53 | // XCTAssertNotEqual(<#expression1#>, <#expression2, ...#>)expression1 和expression2 地址不相同就是通过 54 | 55 | // XCTAssertEqual(<#expression1#>, <#expression2, ...#>)expression1 和expression2 相等就是通过,接收基本数据类型 56 | // XCTAssertNotEqual(<#expression1#>, <#expression2, ...#>)expression1 和expression2 相等就是通过 57 | 58 | //XCTAssertEqualWithAccuracy(<#expression1#>, <#expression2#>, <#accuracy, ...#>) 如果expression1 和expression2都打与accuracy 测试失败 接收基本类型 59 | 60 | //XCTAssertGreaterThan(<#expression1#>, <#expression2, ...#>) expression1 <=expression2 失败 61 | //XCTAssertGreaterThanOrEqual(<#expression1#>, <#expression2, ...#>) expression1 < expression2 失败 62 | // XCTAssertLessThan(<#expression1#>, <#expression2, ...#>) expression1 >expression2 失败 63 | 64 | // 抛异常 65 | // XCTAssertThrows(<#expression, ...#>) 没抛异常,测试失败 expression 是一个表达式 66 | 67 | 68 | ``` 69 | 70 | 71 | ``` 72 | @weakify_self; 73 | [self.testItem addKVOForPath:@"desc" withBlock:^(id newValue) { 74 | @strongify_self; 75 | XCTAssertEqualObjects(newValue, @"A cup of wine"); 76 | [KVOExpectation fulfill]; // 被调用才是成功 77 | }]; 78 | 79 | self.testItem.desc = @"A cup of wine"; 80 | 81 | [self waitForExpectationsWithTimeout:0.001f handler:^(NSError *error) { 82 | [weakSelf.testItem removeAllKVOs]; 83 | }]; 84 | 85 | 86 | ``` 87 | 88 | 89 | ``` 90 | NSInteger targetCount = 1000; 91 | @weakify_self; 92 | [self measureBlock:^ 93 | { 94 | @strongify_self; 95 | for (NSUInteger i = 0; i < targetCount; i++) 96 | { 97 | @autoreleasepool 98 | { 99 | [self.testItem addKVOForPath:@"weight" withBlock:^(id newValue) 100 | { 101 | //NSNumber *weight = (NSNumber *)newValue; 102 | }]; 103 | [self.testItem removeAllKVOs]; 104 | } 105 | } 106 | }]; 107 | 108 | ``` 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /interview-iOS/17阿里网易蘑菇街同花顺等面试题2018年7月.md: -------------------------------------------------------------------------------- 1 | 2 | ## 阿里网易蘑菇街同花顺等面试题2018年7月 3 | 4 | > 作者:费宇超&&jianshu.com/p/7b0eb24b567b 5 | 6 | 7 | ### 阿里 去年面的 8 | 9 | #### 一面(电面) 看了app 主要问功能的具体实现,有没有其他更好的思路 10 | * 1 arc什么时候起作用? 11 | * 2 weak的底层实现,从对象alloc开始,不是我们平时讲讲hash表,key,value是什么就好了。要求答得很细节,估计得debug过源码才行 12 | * 3 富文本渲染的方案,(textkit coretext) 13 | * 4 表视图的优化有什么方案,问对asdk (现更名为 Texture) 第三方库的了解程度 14 | * 5 项目当中遇到了什么困难,是怎么解决的 主要看思路 15 | * 6 怎么看内存泄漏的,除了instruments 16 | * 7 @property (copy)nsmutablearr *arr; 这样的arr调用了addobject方法会有什么问题? 17 | #### 二面(电面) 18 | - 记不清了 问的比较宏观 19 | 20 | ### 网易 21 | 22 | #### 一面(电面) 23 | * 1 scoket是怎么建立连接的?不是TCP三次握手吗 24 | * 2 微信搜索聊天记录是怎么实现的,怎么优化 25 | * 3 wkwebview。webview 区别 26 | * 4 avplayer 怎么做离线缓存 27 | * 5 ijkplayer 用的时候遇到什么坑了吗 28 | * 6 开机优化怎么做?静态库和动态库有什么区别 29 | #### 二面(现场) 30 | * 1 继续问昨天的“微信搜索聊天记录是怎么实现的,怎么优化” 31 | * 2 im的离线消息 未读消息数有什么方案 写一下 (我没做过im) 32 | * 3 项目中的一些具体问题,scrollview 嵌套 scrollview,滑动怎么处理 33 | #### 三面(现场) 34 | * 1 ouath通信是什么。密码加密怎么加?为什么之前的项目做了公钥和私钥2层加密 35 | * 2 https和http区别,回答的要很详细 如何结合公钥私钥加密 36 | * 3 sdwebimage 讲一下它里面的东西是怎么实现的 37 | * 我讲了 lru算法就让我手写一个,我用数组实现,让我继续优化 38 | * 4 如果要做群组头像,怎么结合sdwebimage去做,写一下方案 39 | #### 四面 hr 五面 负责人 都是闲聊 闲聊都是套路 40 | 41 | ### 蘑菇街 42 | 面的是新项目,更看重个人综合素质 43 | #### 一面 负责人和iOS 44 | * 1 最近看了什么技术书,介绍一下 45 | * 2 怎么对整个sqlite加密,注意不是数据加密,表结构也不能被看到 46 | * 3 平时怎么和产品经理沟通,遇到不合理的怎么沟通 47 | * 4 app从点击屏幕(硬件)到完全渲染,中间发生了什么?越详细越好 要求讲到进程间通信 48 | * 5 对算法的了解程度 49 | * 6 对前端后端的了解程度,对人工智能,区块链的了解程度 50 | * 7 有没有推什么东西给组内其他人用?有用的合理的 51 | #### 二面 hr 闲聊 52 | 53 | 54 | ### 涂鸦智能 55 | 56 | #### 一面 两位iOS 都是蘑菇街出来的小伙子,感觉下来是最厉害的面试官 57 | * 1 组件和路由,自己抨击了url的方案 58 | * 2 对象型数据库,除了将model操作动态解析成sql语句之外,做了什么性能优化? 59 | * 3 gcd 如何控制开辟的队列数 60 | * 4 h5 js 交互,除了常见的2种方案,有没有其他思路,如果一个业务下有10000个接口需要开辟,怎么做? 61 | * 5 写了一个不完全二叉树,给出最快遍历 62 | * 6 对前端后端的了解程度,对人工智能,区块链的了解程度 63 | 64 | ### 大华 65 | 66 | 大华面试官很厉害,但整个公司很压抑,流程很拖沓 67 | 68 | * 1 路由和组件化 69 | * 2 arc mrc 下的内存管理区别,如何结合自动释放池 70 | * 3 对算法和解决问题能力的考察,手写冒泡等 71 | * 4 为什么category能加方法不能加实例变量,category里没有实例变量这个结构,那为什么这么设计 72 | 73 | 74 | ### 海拍客 75 | 76 | 这家刚融资很有钱,年底会给期权(数目未知)环境也不错,问题比较简单 77 | 78 | * 1 路由和组件化 79 | * 2 wkwebview。webview 区别,因为是电商,问的最多的还是webview优化 80 | * 3 app日活,崩溃率现在是多少,怎么控制 81 | * 4 图片做高斯模糊会很卡,有什么解决方案 82 | * 5 app从点击屏幕(硬件)到完全渲染,中间发生了什么?越详细越好 83 | 84 | ### 铭师堂 85 | 86 | 到手多,视频sdk用的登虹sdk,不是自研,唯一一家看了我博客从博客开始问东西的,好感 87 | 88 | * 1 一个对象是如何生成的,要求从runtime源码来讲,问有没有debugruntime源码,看过,没debug过 89 | * 2 对象的结构,isa指针是做什么的。imp,selector,method,是什么关系 90 | * 3 然后就是疯狂问第三方库,比如lottie源码怎么实现,讲了大概,会继续问到细节 91 | * 4 链式语法 92 | * 5 响应式编程,rac怎么实现,是你你怎么写? 93 | 94 | #### 总监面 喜欢听情怀 95 | 96 | ### 登虹 97 | 98 | * 1 组件,路由 99 | * 2 数据库如何保证线程安全? 100 | * 3 其他就是笑笑聊聊,不知道在说啥 101 | 102 | ### 小影(视频剪辑) 103 | 104 | * 1 组件,路由 105 | * 2 编译优化,开机优化 106 | * 3 离屏渲染是怎么一回事情,为什么会卡 107 | * 4 socket心跳包机制,几秒比较合适 108 | * 5 cpu,gpu如何协同合作的 109 | 110 | 111 | ### 曹操专车 众成就 咔哒 同花顺 这几家公司给我感觉都非常差 112 | 113 | * 1 app签名机制 114 | * 2 class 和 对象 区别 115 | * 3 bool 和 BOOL 区别 116 | 117 | 118 | ### 同花顺笔试 119 | 120 | - 1二叉树 121 | - 2 isa 实例,类,元类画图说清楚 122 | - 3 实现单写多读 123 | - 4 消息转发的3个步骤 124 | 125 | 126 | *大搜车,有赞,青团,恒生电子等面试邀请来的太晚,都没去 127 | 区块链公司不去 明天的p2p 128 | 有些题目少不是面试时间短 是很多问题记不清了* 129 | 130 | * 1 内存管理和自动释放池在arc,mrc下的不同 131 | * 2 block在arc,mrc下的不同 132 | * 3 架构设计有什么心得,不要说虚的,高内聚什么的 133 | 134 | 135 | ## 链接 136 | 137 | - [面试题系列目录](../README.md) 138 | - **上一份**: [腾讯音乐iOS面试题2018年7月](16腾讯音乐iOS面试题2018年7月.md) 139 | - **下一份**: [2018苏州蜗牛iOS面试](18苏州蜗牛iOS开发面试题2018年春.md) 140 | 141 | ## 赞赏一下旺仔(收集整理不易,且赞且珍惜) 142 | 143 |

144 | 145 | 146 |

147 | -------------------------------------------------------------------------------- /interview-iOS/09头条网易微信阿里美团硕士春招面试题2018年3月.md: -------------------------------------------------------------------------------- 1 | ## 头条网易微信阿里美团硕士春招面试题2018年3月 2 | 3 | > 作者:Nil_Lu&&juejin.im/post/5ad541e0f265da23994f032c 4 | 5 | #### 不能直接po原题,但是我总结了下背后的知识点 6 | 7 | * 异步绘制&离屏幕渲染&CPU渲染和GPU渲染(说白了就是一些性能优化,这块比较看功底) 8 | * UIView 生命周期,UIViewController的生命周期 9 | * iOS中有哪些锁(原理+应用+优化):[参考第一份面试题](01一份"有点难"的iOS面试题MrPeak2016年.md) 10 | * 怎么看待审核被拒 11 | * runloop中将一个任务放到第二次runloop中执行:利用socket/port做一些事情(封装一个source) 12 | * UIKit框架架构图多看看 13 | * id和instencetype的区别 14 | * instrument的插件的使用(尽量都用一下) 15 | * IMP和SEL以及具体执行的操作 16 | * 在项目什么时候选择使用GCD,什么时候选择NSOperation?(根据项目规模以及接口的策略决定以及线程操作复杂程度) 17 | * 发现程序崩在一个objc_msgSend函数里面,这时候可以看的到当前正在调用哪个对象的哪个selector吗?(可以的,可以查到调用的堆栈信息。还可以将这个堆栈信息dump下来) 18 | * NSString类型的property常用copy的原因 19 | * 如何把异步线程转化成同步线程进行单元测试 20 | * autoreleasepool的使用场景和原理:基于runloop回答,并且提及autoreleasepage的实现(基于双向链表)) 21 | * 对于Objective-C,你认为它最大的优点和最大的不足是什么?对于不足之处,现在有没有可用的方法绕过这些不足来实现需求。 22 | * app内存是怎么分析的:Xcode有两种方法(有区别:是否计入图片缓存) 23 | * 内存的使用和优化的注意事项 24 | * 怎样使用performSelector传入3个以上参数,其中一个为结构体。 25 | * nsstring对象的retainCount问题:(细抠下) 26 | * isMemberOfClass 和 isKindOfClass 联系与区别 27 | * 实现准确的定时器: 28 | * NSObject实现了哪些协议 29 | * 消息转发的机制(基于runtime讲全点) 30 | * 使用runtime Associate方法关联的对象,需要在主对象dealloc的时候释放么 31 | * 能否向编译后得到的类中增加实例变量?能否向运行时创建的类中添加实例变量 32 | * 手势相应和触摸事件传播的优先级以及处理等 33 | 34 | 35 | ### 计算机网络 36 | * NSURLConnection 相比,NSURLsession 改进: 37 | * AFN用什么方式实现多线程 38 | * TCP是基于流式传输的,怎么设计协议,进行协议的解析? 39 | * 怎么实现上传/下载任务的断点续传 40 | * 发送网络请求,什么时候连IP、什么时候连域名 41 | * socket编程有了解吗?用在项目的哪里? 42 | * 客户端编程的时候,客户端send成功了,服务端没收到,有什么可能的原因 43 | * 只用TCP,如何设计这个聊天协议? 44 | * http和scoket通信的区别。 45 | * CFSocket使用有哪几个步骤。Core Foundation中提供了哪几种操作Socket的方法? 46 | * HTTPS具体过程,7次握手,以及如何防止中间人攻击的 47 | * 常见的状态码(应用层次) 48 | * URL重定向 49 | * TCP、UDP的特点以及具体应用 50 | * 滑动窗口的理解以及慢开始的措施 51 | 52 | 53 | ### 数据结构 54 | * 哈希表的实现(抠的很细):当拉链长度超过阀值时,会有什么优化(参照JDK的处理思想) 55 | * 常见的链表算法(参照《剑指 offer》) 56 | * stack&queue算法(参照《剑指 offer》) 57 | 58 | 59 | ### 编程基础 60 | * 浮点类型为什么不能精确 61 | * 几种容器的查询、插入效率 62 | * 可变容器的实现原理 63 | * C++如何实现一个不能被继承的class 64 | * C的编译过程 65 | * 动态链接和静态链接库的区别 66 | * C++和OC的区别 67 | * GC和ARC的比较(GC是runtime的) 68 | * 单例的实现(加锁和性能优化) 69 | * 内存的五大区域 70 | * 代码文件编译生成过程完成的事情 71 | 72 | ### 操作系统 73 | * 操作系统里线程切换是怎么实现的,怎么把线程调用函数的参数抛到另一个线程 74 | * 流水线的概念 75 | * 虚拟存储器的页面置换算法(编程实现) 76 | * 死锁的4个必要条件 77 | * 进程间通信的方式 78 | * 缓冲区概念 79 | * 死锁的预防算法 80 | 81 | 82 | ### 算法基础相关: 83 | #### 1.3.1图:注意算法的灵活运用 84 | 85 | * 最小生成树(prime算法、kruskal算法) 86 | * 最短路径算法(floyd、dijkstra) 87 | * 图中是否存在环 88 | * DFS&BFS的应用:迷宫问题比较多 89 | * 拓扑排序 90 | 91 | ### 树:基本都是2叉树的算法 - 这块参照《剑指 offer》+自行百度常见的二叉树算法 92 | #### 排序算法: 93 | - 一定要深入理解三种排序的原理以及优化方法:比如大文件排序算法的优化,可利用快排和归并的特点,利用两种排序的特点,混合使用。 94 | * 堆排序 95 | * 快排:递归&非递归 96 | * 归并:递归&非递归 97 | * 内排序和外排序 98 | 99 | #### DP:问的比较多,但是种类有限 ->LCS类: 100 | 101 | #### 字符串最长公共子序列 102 | - 最长单调递增子序列:先sort 然后转化为LCS问题 103 | 104 | #### 背包问题: 105 | * 背包问题: 106 | * 数组分为两个sum和尽量相等的子数组:背包容量=sum/2,转化为0-1背包问题 107 | * 多背包问题:n个背包,求最大和 108 | * 完全背包问题: 109 | * 硬币组合问题: 110 | 111 | #### 所有组合数问题 112 | 113 | - 1分2分5分的硬币三种,组合成1角,共有多少种组合? 114 | - 一个人上台阶可以一次上1个,2个,或者3个,问这个人上n层的台阶,总共有几种走法 115 | 116 | 117 | #### 最小路径和问题: 118 | 119 | * 矩阵的最小路径和 120 | * 三角形的最小路径和 121 | 122 | ### 编程思想&设计模式等: 123 | 124 | * 编程思想参照《iOS编程之道》 125 | * 设计模式主要是MVC&MVVM&MVCS的理解 126 | * 组件化需要了解下 127 | * 解耦的常用方法 128 | * 设计模块的设计思路: 129 | 130 | - 操作队列如何封装GCD 131 | - 达到设置最大并发数(信号量实现) 132 | - NSNumber的设计(类簇的设计思想) 133 | - 宽窄接口的设计等 134 | 135 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 136 | 137 |

138 | 139 |

140 | 141 | ## 链接 142 | 143 | - [面试题系列目录](../README.md) 144 | - **上一份**: [字节跳动面试题:2018年4月](08字节跳动面试题:2018年4月.md) 145 | - **下一份**: [美团饿了么面试题2018年4月](10美团饿了么面试题2018年4月.md) 146 | 147 | -------------------------------------------------------------------------------- /iOSNote/CocoaPods/cocoapods-plugins.md: -------------------------------------------------------------------------------- 1 | ## cocoapods plugins 2 | 3 | > sudo gem update --system 4 | 5 | > User:【podfile : plugin 'plugin name'】 6 | 7 | > install:`$ sudo gem plugin name` 8 | 9 | - binary 10 | - dependencies 11 | - cocoapods-user-defined-build-types 12 | - cocoapods-static-swift-framework 13 | 14 | ### [cocoapods-binary ](https://github.com/leavez/cocoapods-binary/) 15 | 16 | > 构建二进制适合本地Debug使用 17 | 18 | - remote pod transfer to framework 19 | 20 | - sudo gem install cocoapods-binary 21 | 22 | ### [cocoapods-pod-merge](https://github.com/grab/cocoapods-pod-merge) 23 | 24 | > group Pod组件合并插件 25 | 26 |
27 | 点击展开示例说明 28 | 29 | > pod install 源码OK,二进制需要对应remote自身再桥接。 30 | 31 | - sudo gem install cocoapods-dependencies 32 | 33 | - This plugin requires a file called `MergeFile`. This is how it looks: 34 | - touch Gemfile 35 | - gem 'cocoapods-pod-merge' 36 | - bundle install 37 | - bundle exec pod install 38 | 39 | ``` 40 | 41 | group 'Networking' 42 | pod 'AFNetworking' 43 | pod 'SDWebImage' 44 | end 45 | 46 | plugin 'cocoapods-pod-merge' 47 | 48 | target 'MyApp' 49 | pod 'Networking', :path => 'MergedPods/Networking' 50 | pod 'UI', :path => 'MergedPods/UI' 51 | end 52 | 53 | ``` 54 |
55 | 56 | 57 | ### [pod-dependencies](https://github.com/segiddins/cocoapods-dependencies) 58 | 59 | > dependencies:分析当前组件依赖细节 60 | 61 | - sudo gem install cocoapods-dependencies 62 | 63 | 64 | ### [cocoapods-static-swift-framework](https://github.com/leavez/cocoapods-static-swift-framework) 65 | 66 | - sudo gem install cocoapods-static-swift-framework 67 | 68 | ### [cocoapods-packager](https://github.com/CocoaPods/cocoapods-packager) 69 | 70 | > 只适用于远端库(本质从远端clone再处理) 71 | 72 | > M1并无适配及产物架构不可自定义,不建议使用! 73 | 74 | - sudo gem install cocoapods-packager 75 | 76 | - your Gemfile:gem "cocoapods-packager" && bundle install 77 | 78 | - pod package name.podspec 79 | 80 | ``` 81 | 如果需要排除源码中依赖的第三方库,可以在打包命令中添加 --exclude-deps 选项。 82 | //静态framework 83 | pod package name.podspec --force --no-mangle --embedded 84 | //静态.a 85 | pod package name.podspec --library --force 86 | // .a 调整 87 | s.vendored_libraries = "Path/to/xxx.a" 88 | s.source_files = "xxx/**/*.h" 89 | 90 | /强制覆盖之前已经生成过的二进制库 91 | --force 92 | 93 | //生成静态.framework 94 | --embedded 95 | 96 | //生成静态.a 97 | --library 98 | 99 | //生成动态.framework 100 | --dynamic 101 | 102 | //动态.framework是需要签名的,所以只有生成动态库的时候需要这个BundleId 103 | --bundle-identifier 104 | 105 | //不包含依赖的符号表,生成动态库的时候不能包含这个命令,动态库一定需要包含依赖的符号表。 106 | --exclude-deps 107 | 108 | //表示生成的库是debug还是release,默认是release。--configuration=Debug 109 | --configuration 110 | 111 | --no-mangle 112 | //表示不使用name mangling技术,pod package默认是使用这个技术的。我们能在用pod package生成二进制库的时候会看到终端有输出Mangling symbols和Building mangled framework。表示使用了这个技术。 113 | //如果你的pod库没有其他依赖的话,那么不使用这个命令也不会报错。但是如果有其他依赖,不使用--no-mangle这个命令的话,那么你在工程里使用生成的二进制库的时候就会报错:Undefined symbols for architecture x86_64。 114 | 115 | --subspecs 116 | 117 | //如果你的pod库有subspec,那么加上这个命名表示只给某个或几个subspec生成二进制库,--subspecs=subspec1,subspec2。生成的库的名字就是你podspec的名字,如果你想生成的库的名字跟subspec的名字一样,那么就需要修改podspec的名字。 118 | 这个脚本就是批量生成subspec的二进制库,每一个subspec的库名就是podspecName+subspecName。 119 | 120 | --spec-sources 121 | 122 | //一些依赖的source,如果你有依赖是来自于私有库的,那就需要加上那个私有库的source,默认是cocoapods的Specs仓库。--spec-sources=private,https://github.com/CocoaPods/Specs.git。 123 | 124 | ``` 125 | 126 | ### [cocoapods-user-defined-build-types](https://github.com/joncardasis/cocoapods-user-defined-build-types) 127 | 128 | - sudo gem install cocoapods-user-defined-build-types 129 | 130 | ``` 131 | plugin 'cocoapods-user-defined-build-types' 132 | 133 | enable_user_defined_build_types! 134 | 135 | target "CoffeeApp" do 136 | pod 'Alamofire' 137 | pod "SwiftyJSON", :build_type => :dynamic_framework 138 | 139 | dynamic_library 140 | dynamic_framework 141 | static_library 142 | static_framework 143 | 144 | ``` -------------------------------------------------------------------------------- /iOSNote/iOS_StaticLibrary.md: -------------------------------------------------------------------------------- 1 | 2 | # 静态库 3 | 4 | ## 一. 静态库的简介 5 | 6 | - 库, 就是讲程序代码集合, 封装为一个库文件, 他是共享代码的一种方式, 可以将自己的代码共享给他人使用 7 | 8 | - 库的分类 9 | * 开源库: 公开代码, 能看到代码的具体实现 10 | * 闭源库:不公开代码, 将代码的实现编译为二进制文件, 只将API接口提供给使用者 11 | * 静态库: .a和.framework 12 | * 动态库: .dylib和.framework 13 | 14 | - 静态库和动态库的区别 15 | - 静态库在链接时, 会被完整的复制到可执行文件中; 多次使用, 就会有多次的拷贝(import) ? 16 | - 动态库则不会复制, 只有一份, 当程序运行时动态加载到内存; 系统只加载一次, 多个程序可以共用, 节省内存 17 | - 注意: 项目如果使用到自己的动态库, 苹果就不会上架你的APP,但是, 在WWDC2014上公布的, 苹果对iOS8开放动态加载dylib的接口, 也就是说开放了动态库挂载 18 | 19 | 20 | - 静态库的主要用途 21 | 22 | - **保护自己的代码**: 将自己的技术分享给其他人使用, 但是又不希望自己的代码暴露给别人, 就可以使用静态库:如一些技术公司提供的SDK: 支付宝/GrowingIO... 23 | - 将MRC的项目, 打包成静态库, 可以直接在ARC的环境下直接使用, 不需要转换 24 | - 实现iOS程序的模块化。可以把固定的业务模块化成静态库。 25 | - 开发第三方sdk的需要 26 | 27 | - 静态库的几个特点: 28 | 29 | * 在App项目编译的时候会被拷贝一份编译到目标程序中,相当于将静态库嵌入了,所以得到的App二进制文件会变大。 30 | * 在使用的时候,需要手动导入静态库所依赖的其他类库。(比如说某个SDK中使用到了CoreMotion.framework,在使用的时候需要手动导入。有的SDK需要link十几个系统库,这个时候非常恶心,只能一个一个手动加,这是静态库一个很大的不便之处。) 31 | * 导入静态库的应用可以减少对外界的依赖,如果导入的是第三方动态库,动态库找不到的话应用就会崩掉,例如Linux上经常出现的lib not found。 32 | * 静态库很大的一个优点是减少耦合性,因为静态库中是不可以包含其他静态库的,使用的时候要另外导入它的依赖库,最大限度的保证了每一个静态库都是独立的,不会重复引用。 33 | 34 | 35 | ## 静态库的制作 36 | 37 | 1. 创建一个项目, 在选择工程文件时: iOS(Framework & Library) -> Cocoa Touch Static Library 38 | 2. 选择当生成静态库时, 要暴露给外人使用的头文件 39 | 3. TARGETS(项目文件) -> Build Phases -> Copy Files -> 需要暴露的头文件后面打钩(Code Sign On Copy) 40 | 4. 如果当前是模拟器环境, 编译程序的话, 就会得到模拟器状态下的静态库,如果当前是真机环境, 编译程序就会得到真机状态下的静态库 41 | 5. 编译之后, 在项目工程文件处查看, 如果Products中的.a文件是红色的, 代表创建失败 42 | 6. 如果.a文件变为白色, 代表创建成功, 右击Show In Finder就可以查看对应版本的静态库 43 | 7. 静态库的版本说明 44 | * Debug-iphoneos: 调试版本的真机静态库 45 | * Debug-iphonesimulator: 调试版本的模拟器静态库 46 | * Release-iphoneos: 发布版本的真机静态库 47 | * Release-iphonesimilator: 发布版本的模拟器静态库 48 | 8. 生成的静态库一般包括两个文件 ,参考GrowingIO 49 | 9. include文件夹, 存放暴露出来的头文件, 有各种属性/方法的声明 50 | 10. .a文件: 将实现文件编译为二进制后生成的文件 51 | 52 | * ![](1.png) 53 | * ![](2.png) 54 | 55 | ## 静态库使用 56 | 57 | ### 静态库对应的CPU架构 58 | - 模拟器: 59 | - 4s---5: i386架构 60 | - 5s---6sPlus: x86_64架构 61 | - 真机: 62 | * 4s: armv7 63 | * 5/5c: armv7s(但是他兼容armv7) 64 | * 5s---6sPlus: arm64 65 | 66 | ### 查看当前静态库支持的架构 67 | - 使用终端, 进入静态库.a文件所在的目录 68 | - 使用命令: lipo -info .a文件名称, 即可查看静态库所支持的系统架构,参考下图 69 | ![](3.png) 70 | 71 | ### 生成支持多个架构的静态库 72 | 默认情况下, 需要选中不同的模拟器分别进行编译, 才会生成支持对应架构的静态库, 然后再合并静态库 73 | - 点击TARGET项目工程文件 -> Build Settings -> Build Active -> NO 74 | - 该选项表示不知编译活跃的架构(当前架构), 而是编译所有的架构 75 | 76 | ### 生成一个既支持模拟器又支持真机的静态库 77 | - 由于静态库针对于模拟器和真机, 生成的静态库版本是不一样的(为了不同的CPU架构), 因此无法同时运行 78 | 79 | - 静态库的合并 80 | - 在终端, 使用lipo -info .a文件名称的方法, 查看静态库的版本 81 | - 合并.a文件 82 | 83 | ``` 84 | lipo -create Debug-iphoneos/libBlowTool.a Debug-iphonesimulator/libBlowTool.a -output libBlowToolNew.a 85 | 86 | 文件合并之后, 可以查看该静态库目前已经支持armv7 i386 x86_64 arm64 87 | ``` 88 | 89 | 90 | ## 静态库开发中遇到的常见问题 91 | 92 | - 一些静态库包含的资源文件可能与我们自己的资源文件重名 93 | 94 | * Xcode在编译的时候, 会把所有的资源文件导入mainBundle中, 这样可能出现重名冲突 95 | * 因此在静态库中使用图片素材, 需要利用bundle文件 96 | * 建立一个bundle文件, 然后向其中添加静态库所需的图片 97 | * 在库中创建一个类方法, 返回图片 98 | * 编译 99 | * 外界如果需要使用图片, 需要导入.h + .a + XXX.bundle文件 100 | 101 | - 如果用户需要导入的头文件过多, 就可以使用一个主头文件, 包含其他所有的头文件, 这样用户只需要导入一个主头文件就可以了 102 | - Swift不支持静态库? (只要思想不滑坡,办法总比困难多) 103 | * Xcode只要加入Swift文件就压根编译不过会报Swift is not supported for static libraries 104 | * 其实OC调用Swift,系统也是帮我们把Swift转换成OC再来编译,那么是不是我们只需要拿到Xcode编译过后的文件,然后就算删除掉Swift库也可以正常运行呢,我的测试是是的。所以打包静态库也是如此。 105 | 106 | 107 | ## 解压静态库.a文件 108 | 109 | ``` 110 | 1. file libBlowTool.a 111 | libBlowTool.a: Mach-O universal binary with 2 architectures: [arm_v7: current ar archive random library] [arm64: current ar archive random library] 112 | libBlowTool.a (for architecture armv7): current ar archive random library 113 | libBlowTool.a (for architecture arm64): current ar archive random library 114 | DragonLi:Desktop LFL$ lipo libBlowTool.a -thin armv7 -output v7.a 115 | 116 | 2. 抽离object的时候必须是要单一的库,所以这里我们之抽出armv7并命名为v7.a 117 | lipo libBlowTool.a -thin armv7 -output v7.a 118 | 3. 抽离.a文件的object,多出一些.o文件 119 | ar -x v7.a 120 | 4. nm libBlowTool.o > libBlowTool.m 121 | 122 | ``` 123 | 124 | 125 | 126 | 127 | -------------------------------------------------------------------------------- /interview-iOS/13秋招iOS面试总结2018年.md: -------------------------------------------------------------------------------- 1 | ## 秋招iOS面试总结2018年 2 | 3 | > 出处:jianshu.com/p/834878284b99 4 | 5 | 6 | ## 【百度】(二面挂) 7 | 8 | ### 一面: 9 | 10 | * 1.说下线程和进程的区别 11 | 12 | * 2.如何保证线程安全 13 | 14 | * 3.写个算法,输出2~100的素数(然后问你怎么优化,还可以怎么优化,然后还可以怎样优化.....) 15 | 16 | * 4.了解哪些设计模式 17 | 18 | * 5.MVC设计模式的思想是什么?在项目中的运用,然后对比MVVM设计模式 19 | 20 | * 6.堆和栈的区别,工程项目中的哪些数据是储存在堆哪些在栈中 21 | 22 | * 7.iOS中的NSCopying协议,copy,MutableCopy的区别 23 | 24 | * 8.解释属性修饰关键词的作用(weak,strong,copy,readOnly,assgin,nonatomic等) 25 | 26 | * 9.最近看过哪些书?目录结构是怎样的?哪部分内容印象最深?了解过作者吗? 27 | 28 | * 10.你还有什么问题问我? 29 | 30 | ### 二面: 31 | 32 | * 1.写二叉树的先序遍历,然后用非递归写 33 | 34 | * 2.写快排,并分析原理 35 | 36 | * 3.http协议 37 | 38 | * 4.http为什么底层是tcp不是udp ? 39 | 40 | * 5.tcp是基于流式传输的,怎么设计协议,进行协议的解析? 41 | 42 | * 6.tcp为什么要进行三次握手?不是2次,4次? 43 | 44 | * 7.抓包工具的原理是啥? 45 | 46 | * 8.socket异常断开时,设计一个合理的重连机制。 47 | 48 | * 9.内存管理 49 | 50 | * 10.iOS开发中用过哪些测试性能的工具 51 | 52 | * 11.instruments它为什么能检测内存泄漏 53 | 54 | * 12.做过的项目有什么技术难点(我说的难点在面试官看来都不是难点)? 55 | 56 | * 13.在10亿个数中如何快速找到最大的前100个数? 57 | 58 | * 14.你有什么创新能力? 59 | 60 | * 15.你还有什么问题问我? 61 | 62 | ### 总结:偏向基础,问题逐步深入。 63 | 64 | 65 | ## 【京东】(二面莫名其妙挂) 66 | 67 | ### 一面: 68 | 69 | * 1.解释属性修饰关键词的作用(weak,strong,copy,readOnly,assgin,nonatomic等) 70 | 71 | * 2.项目中用过哪些设计模式 72 | 73 | * 3.结合响应者链条和设计模式,解释事件怎样传递和处理 74 | 75 | * 4.blcok,NSNotification,delegate,Observer比较 76 | 77 | * 5.block为什么会导致循环引用 78 | 79 | * 6.为什么想来京东 80 | 81 | * 7.聊人生 82 | 83 | 84 | 85 | ### 二面: 86 | 87 | > (项目:因为实习的公司用的SDK组件化的开发模式,拿出来作品一边演示他一边提问,1-6点都是对于我的SDK项目提问) 88 | 89 | * 1.为什么需要组件化? 90 | 91 | * 2.tableView的性能优化 92 | 93 | * 3.SDK的接口设计过程(一般设计为进入业务线提供一个注册方法,在需要的时候使用代理回调。向SDK里传递数据一般用单利模式,开出相应的方法) 94 | 95 | * 4.cocoaPods的实现思路,为什么没有使用cocoaPods管理自己的SDK 96 | 97 | * 5.项目中缓存SDK采用的策略(我们项目主要借鉴了YYCache,采用lru算法,使用sqlite) 98 | 99 | * 6.相对复杂业务交互的处理,采用的设计模式(单利模式配合模板方法模式实现) 100 | 101 | * 7.AFN实现思路,对源码的理解程度 102 | 103 | * 8.项目中如何保证数据的安全性 104 | 105 | 9.runtime在奇葩需求当中的运用(比如产品要求5和6上面显示不同的字体大小,可以用runtime的交换方法) 106 | 107 | 9.快排的原理 108 | 109 | 10.C语言中strlen和sizeof的区别 110 | 111 | 11.职业规划(开始聊人生) 112 | 113 | ### 总结:偏向项目,主要考察对业务的处理熟练度。(这是我最拿手的,二面差不多聊了1个多小时,没有答不上来问题,走的时候我跟面试官都很开心,晚上回去一看官网状态为未通过,伤心极了) 114 | 115 | 116 | 117 | ## 【同花顺】 118 | 119 | 120 | 121 | ### 一面:(问的太基础) 122 | 123 | * 1.对于面向对象的理解 124 | 125 | * 2.内存管理 126 | 127 | * 3.多线程 128 | 129 | * 4.保证线程安全的方式(加锁和GCD栅栏,队列组相关知识) 130 | 131 | * 5.KVC和KVO的使用和注意事项 132 | 133 | * 6.推送的原理 134 | 135 | * 7.tableViewCell的自适应如何实现,如何保证性能 136 | 137 | * 8.堆和栈的区别 138 | 139 | 140 | 141 | ### 二面: 142 | 143 | * 1.SDWebImage的底层实现(我只答到了没有沙盒的时如何实现) 144 | 145 | * 2.简述下runLoop(问了应用程序在不同条件下各个线程runLoop所处模式) 146 | 147 | * 3.一个页面可以由几个控制器共同管理吗 148 | 149 | * 4.http和socket的区别 150 | 151 | * 5.什么时候用集合(NSSet) 152 | 153 | * 6.项目上线或者版本迭代,有过被拒吗?是什么原因?怎么解决? 154 | 155 | * 7.转场动画相关操作 156 | 157 | * 8.绘图相关知识(coreGraphics框架的使用) 158 | 159 | * 9.数据持久化 160 | 161 | * 10.xib和代码适配界面有什么不一样 162 | 163 | * 11.项目中遇到的问题,如何解决(我从所做的项目的框架搭建,模块分布,设计类图,开发,自测,上线一直扯) 164 | 165 | * 12.最早什么时候能够来实习(感觉他们很缺人,但是我问了下他们部门都有30多个iOS开发者!!) 166 | 167 | 168 | 169 | ### 三面:(因为薪资没谈拢加了一次技术面) 170 | 171 | * 1.assgin和weak的区别,代理为什么用assgin 172 | 173 | * 2.类方法:load 和 initialize 有什么区别,一般怎么用它们 174 | 175 | * 3.OC语言的动态机制的理解(开始浅谈runtime) 176 | 177 | * 4.设计模式:代理和观察者模式的对比,单利模式的使用注意点 178 | 179 | * 5.如何设计网络请求框架(我按照AFN的理解去解释了一波) 180 | 181 | * 6.响应者链条 182 | 183 | * 7.iPhone自带的AssistiveTouch你如何实现 184 | 185 | * 8.App包的大小受哪些影响 186 | 187 | * 9.关于debug和release 188 | 189 | * 10.view的生命周期 190 | 191 | 192 | 193 | ### 四面: 194 | 195 | > (HR面,基本上是闲扯,想着反正拿到offer也不得去,我问他的问题都比他问我的还要多。。。基本上也记不住了) 196 | 197 | * 1.说出你的三个缺点和优点 198 | 199 | * 2.为什么选择同花顺 200 | 201 | * 3.说出你在大学期间干过的最牛逼的一件事 202 | 203 | * 4.对于我们企业文化的理解(我把我实习公司的企业文化吹嘘了一遍,发现这几点基本上放在任何私企都好使:客户至上,团队合作,诚信正直,务实创新) 204 | 205 | 206 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 207 | 208 |

209 | 210 |

211 | 212 | ## 链接 213 | 214 | - [面试题系列目录](../README.md) 215 | - **上一份**: [校招攻略43份优质面经汇总iOS开发2018年](12校招攻略43份优质面经汇总iOS开发2018年.md) 216 | - **下一份**: [阿里腾讯百度头条美团iOS面试题2018年4月](14阿里腾讯百度头条美团iOS面试题2018年4月.md) 217 | -------------------------------------------------------------------------------- /interview-iOS/11天猫蚂蚁金服百度面试题2018年4月.md: -------------------------------------------------------------------------------- 1 | ## 天猫蚂蚁金服百度面试题2018年4月 2 | 3 | > 作者:ZhHS&&juejin.im/post/5ad80ad35188252eae3b22a4 4 | 5 | - [天猫 面试通知](#天猫-面试通知) 6 | - [NAVER China 整个面试过程三个小时](#naver-china-整个面试过程三个小时) 7 | - [蚂蚁金服](#蚂蚁金服) 8 | - [百度一面](#百度一面) 9 | - [百度一面](#百度一面-1) 10 | 11 | ### 天猫 面试通知 12 | 13 | * Runtime的消息转发机制 14 | * [字节面试相关问题及解答](./08字节跳动面试题:2018年4月.md) 15 | * Runloop的工作原理 16 | * CFRunLoop开源代码:http://opensource.apple.com/source/CF/CF-855.17/ 17 | * RunLoop实际上是一个对象,这个对象在循环中用来处理程序运行过程中出现的各种事件(比如说触摸事件、UI刷新事件、定时器事件、Selector事件),从而保持程序的持续运行;而且在没有事件处理的时候,会进入睡眠模式,从而节省CPU资源,提高程序性能。 18 | * 内存管理 19 | * [类似参考问题:ARC的工作原理](./03interview-iOS-3.md) 20 | * block 21 | * [类似参考问题](./07深圳iOS面试分享2018年4月.md) 22 | 23 | ### NAVER China 整个面试过程三个小时 24 | * GCD 25 | * 定时器的几个类方法底层分别是怎么实现的([NSTimer timerWithTimeInterval:repeats: block:]等) 26 | * KVO、delegate、通知的区别以及底层实现 27 | * Struct与Union主要区别 28 | * 思维题:情景:20个主人,20条狗,在同一个小区每天在同一个地方同时遛狗,狗主人绝对聪明,一旦发现自己家的狗是疯狗,回家之后就会用枪把狗打死。第一天晚上遛狗回家后没有听见枪响,第二天晚上遛狗回家后没有听见枪响,第三天晚上遛狗回家后听见多声枪响,请问有多少条疯狗。 29 | 条件: 30 | ①狗主人不能直接发现自己家的狗是否是疯狗,可以发直接现别人家的狗是否是疯狗,凭此可以推断自己家的狗是否是疯狗 31 | ②狗主人遛狗期间不会有任何交谈 32 | ③疯狗不会传染 33 | 34 | ### 蚂蚁金服 35 | 36 | * iOS11的新特性 37 | * 参考Apple 官网 38 | * 点击应用图标到启动应用整个过程,系统进行了什么操作 39 | * swift相关知识 40 | * Apple pay的支付流程 41 | * 参考Apple 官网流程即可 42 | 43 | 44 | ### 百度一面 45 | 46 | * 写一段程序判断文本框内输入的IP地址是否合法 47 | * `@"^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$"` 48 | * 开头结尾是否空格,是否为空,是否字符串类型 49 | * 0.0.0.0 合法, 00.0.0.0 不合法, 50 | * IP地址是一个32位的二进制数,通常被分割为4个“8位二进制数”(也就是4个字节)。IP地址通常用“点分十进制”表示成(a.b.c.d)的形式,其中,a,b,c,d都是0~255之间的十进制整数。 51 | 52 |
53 | IP地址是否合法:Java代码参考内容 54 | 55 | ```Java 56 | if(addr.length() < 7 || addr.length() > 15 || "".equals(addr)) 57 | { 58 | return false; 59 | } 60 | /** 61 | * 判断IP格式和范围 62 | */ 63 | String rexp = "([1-9]|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])(\\.(\\d|[1-9]\\d|1\\d{2}|2[0-4]\\d|25[0-5])){3}"; 64 | 65 | Pattern pat = Pattern.compile(rexp); 66 | 67 | Matcher mat = pat.matcher(addr); 68 | 69 | boolean ipAddress = mat.find(); 70 | 71 | //============对之前的ip判断的bug在进行判断 72 | if (ipAddress==true){ 73 | String ips[] = addr.split("\\."); 74 | 75 | if(ips.length==4){ 76 | try{ 77 | for(String ip : ips){ 78 | if(Integer.parseInt(ip)<0||Integer.parseInt(ip)>255){ 79 | return false; 80 | } 81 | 82 | } 83 | }catch (Exception e){ 84 | return false; 85 | } 86 | 87 | return true; 88 | }else{ 89 | return false; 90 | } 91 | } 92 | 93 | return ipAddress; 94 | 95 | ``` 96 |
97 | 98 | 99 | * ➕ 的`实现逻辑` 100 | 101 | * runtime的相关知识 102 | * [字节面试相关问题及解答](./08字节跳动面试题:2018年4月.md) 103 | 104 | * autorelease的使用场景 105 | * for循环中,创建大文件 106 | 107 | * plist读写操作如何进行锁管理 108 | * 使用`dispatch _barrier` 109 | * 赋值时候不可以读和其他读写,读取的时候可以多处读取 110 | 111 | * NSNotification实现逻辑,子线程中给主线程发送通知,主线程是否会处理通知 112 | * 在多线程应用中,Notification在哪个线程中post,就在哪个线程中被转发,而不一定是在注册观察者的那个线程中。 113 | * **苹果之所以采取通知中心在同一个线程中post和转发同一消息这一策略,应该是出于线程安全的角度来考量的**。官方文档告诉我们,NSNotificationCenter是一个线程安全类,我们可以在多线程环境下使用同一个NSNotificationCenter对象而不需要加锁。 114 | * 尽量在一个线程中处理通知相关的操作,大部分情况下,这样做都能确保通知的正常工作。不过,我们无法确定到底会在哪个线程中调用dealloc方法 115 | 116 | * 编译器怎么检测#import和#include导入多次的问题,三方库导入时如何设置**""和<>** 117 | * ifdef def #endif 118 | * if __has_include(<>) 119 | 120 | ### 百度一面 121 | 122 | * 关于业务方面以及性能方面的问题 123 | * 组件化的问题 124 | * 怎么修复线上卡顿、崩溃问题, 125 | * 项目结构等等 126 | 127 | 128 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 129 | 130 |

131 | 132 |

133 | 134 | ## 链接 135 | 136 | - [面试题系列目录](../README.md) 137 | - **上一份**: [美团饿了么面试题2018年4月](10美团饿了么面试题2018年4月.md) 138 | - **下一份**: [校招攻略43份优质面经汇总iOS开发2018年](12校招攻略43份优质面经汇总iOS开发2018年.md) 139 | 140 | -------------------------------------------------------------------------------- /interview-iOS/22快手X3岗面试题2020年3月.md: -------------------------------------------------------------------------------- 1 | ## 2020年3月快手X3岗iOS面试题 2 | 3 | 4 | > 来源地址&&jianshu.com/p/0eb02402f730 5 | 6 | > 2020年3月 7 | 8 | > 面的是快手X3岗位,视频面试,不支持周末,但是可以选择晚上时间。视频面试是通过牛客网进行的,以下是记下来的各轮面试题,对于一些iOS基础知识就不做解答了。 9 | 10 | - [一面](#一面) 11 | - [二面](#二面) 12 | - [三面](#三面) 13 | - [总结](#总结) 14 | 15 | ### 一面 16 | 17 | 1、用递归写一个算法,计算从1到100的和。[Swift] 18 | 19 |
20 | 参考内容 21 | 22 | ``` swift 23 | func sum(value: Int) -> Int { 24 | if value <= 0 { 25 | return 0 26 | } 27 | var number = value 28 | return value + sum(value: number - 1) 29 | } 30 | // 计算过程 31 | let result = sum(value: 100) 32 | print(result) 33 | 34 | ``` 35 | 36 |
37 | 38 | 39 | 写完算法之后又围绕着问了几个问题,都是算法基础: 40 | 41 | - 算法的时间复杂度是多少 42 | - 递归会有什么缺点 43 | - 不用递归能否实现,复杂度能否降到O(1) 44 | 45 | 2、property的作用是什么,有哪些关键词,分别是什么含义? 46 | 47 | 3、父类的property是如何查找的? 48 | 49 | 4、NSArray、NSDictionary应该如何选关键词? 50 | 51 | 5、copy和muteCopy有什么区别,深复制和浅复制是什么意思,如何实现深复制? 52 | 53 | 6、用runtime做过什么事情?runtime中的方法交换是如何实现的? 54 | 55 | 7、讲一下对KVC合KVO的了解,KVC是否会调用setter方法? 56 | 57 | 8、__block有什么作用 58 | 59 | 9、说一下对GCD的了解,它有那些方法,分别是做什么用的? 60 | 61 | 10、对二叉树是否了解? 62 | 63 | ### 二面 64 | 65 | 1、ARC和MRC的区别,iOS是如何管理引用计数的,什么情况下引用计数加1什么情况引用计数减一? 66 | 67 | 2、在MRC下执行[object autorelease]会发生什么,autorelease是如何实现的? 68 | 69 | 3、OC如何实现多继承? 70 | 71 | > 这个当时没有答好。其实借助于消息转发,protocol和类别都可以间接实现多继承。 72 | 73 | 4、对设计模式有什么了解,讲一下其中一种是如何使用的。 74 | 75 | 5、有没有哪个开源库让你用的很舒服,讲一下让你舒服的地方。 76 | 77 | 6、一张100*100,RGBA的png图像解压之后占多大内存空间。 78 | 79 | 5、算法题:给定一个个数字arry,判断数组arry中是否所有的数字都只出现过一次。 80 | 81 | - 这个并没有要求写出来,说是提供思路就行了。我当时给的方案是在便利数组的时候,用一个字典把便利的元素存起来,如果在后面的便利过程中新元素在字典中存在过就说明,有重复数字出现。时间复杂度是O(n)。 82 | 83 | - 当时也问了有没有办法进行优化,我当时想到了将数组转成Set,然后和原数组比较,两个集合的数量是否变化。 84 | 85 | 7、因为我跟他介绍自己Swift用的多一些,然后问了些Swift跟OC的区别,各自的优缺点。 86 | 87 | 8、为什么离职,有什么职业规划。 88 | 89 | 90 | ### 三面 91 | 92 | 1、给定一个Int型数组,用里面的元素组成一个最大数,因为数字可能非常大,用字符串输出。 93 | 94 | ``` 95 | 输入: [3,30,34,5,9] 96 | 输出: 9534330 97 | 98 | ``` 99 |
100 | 参考内容 101 | 102 | - 这个是[leetcode的179题](https://leetcode-cn.com/problems/largest-number/),难度中等。面试官让先说思路,再去做题。事先说一下这个题我没有做过。当时的思路是用冒泡法进行排序,排序的前提是将较少位数的数字进行循环补齐,例如3和30的比较,变成33和30的比较,34和4的比较变成34和44的比较,然后将结果从大到小整合成字符串输出。 103 | 104 | - 但是做题是却发现没那么简单,位数的补齐对于2位和3位数的比较还需要求位数的最小公倍数,将他们都转成6位数才能比较。在挣扎了5分钟做了就做罢了。 105 | 106 | - 后来再去做这道题,其实这就是一个排序而已,只不过他的规则是按高位优先级更高的原则,而这一点跟字符串的比较保持一致,如果再加一些Swift的高阶函数,就可以写成: 107 | 108 | ``` 109 | func largestNumber(_ nums: [Int]) -> String { 110 | let sort = nums.map {"\($0)"}.sorted { (lStr, rStr) -> Bool in 111 | return lStr + rStr > rStr + lStr 112 | } 113 | let result = sort.joined() 114 | if result.prefix(1) == "0" { 115 | return "0" 116 | } else { 117 | return result 118 | } 119 | } 120 | 121 | ``` 122 | 123 |
124 | 125 | 126 | 2、项目中有这么一个方法func findfile(dir: String suffix: String) -> [String] ,可以通过输入文件夹目录,和后缀检索出所需的文件。 127 | 128 | - 例如需要在某个文件中检索txt文件或者mp4文件,那就传入dir和suffix就行了。现在又有一些需求,例如需要检索utf8格式的txt或者h264编码的mp4,也会有一些例如查找最近一周更新过的文件这样的需求,你如何优化这个类,让它满足这些情况? 129 | 130 | - 我首先想到的是这么多需求不可能一个方法就完成,需要根据不同场景拆出不同的方法,但是这些同属于文件操作,会有一个共同使用的方法就是检索文件。这个方法需要传入文件目录,然后递归的返回当前目录所有文件路径。外部不同场景的调用逻辑就用一个enum完成,不同值对应相同范围的不同种类。 131 | 132 | - 面试官比较关注内部共用的文件检索怎么写,他说子文件如果过多怎么办,如何优化。我有点懵,查找文件至少是要遍历一遍的,子文件过多,这个应该是没法优化的啊。中间卡了一段时间,后来他给了提示说是不是可以用block实现,将文件路径返回出去,由外部决定当前文件是否可用,最终外部的调用类是这个样子。 133 | 134 | ``` 135 | //我的方案 136 | //func findDir(_ dir: String) -> [String] 137 | //block方案 138 | func findDir(_ dir: String, block: ((String) -> Bool)) 139 | 140 | ``` 141 | - 我想来确实没毛病,用block返回内容至少不会将该目录的所有文件都由一个对象持有,而前面一堆的铺垫其实也都是为验证block方案的好处。 142 | 143 | - 其实事后想下这个问题没啥难的,这种写法自己也有写过,但当时就是没想起来,可能前面一圈的铺垫给我带偏了吧,说亏也不亏,以后多多努力吧。 144 | 145 | ### 总结 146 | 147 | - 整体来看,快手的面试题跟我在别处看到的iOS面试题对比要简单些。一面主要是基础知识,二面考察更全面一些,更多让自己谈一些对技术的理解,三面则是更偏实践一些。 148 | 149 | - 算法虽然三轮都有,但相对比较简单,即使写不出来,有思路也是可以的。当然写出来肯定是加分项,所以大家准备面试时,应该都看一下。算法相关的,排序,数组,二叉树,这几类是重点。 150 | 151 | 152 | ## 链接 153 | 154 | - [面试题系列目录](../README.md) 155 | - **上一份**: [出一套iOS高级面试题J_Knight_](21出一套iOS高级面试题2018年7月.md) 156 | - **下一份**: [抖音面试题2020年3月](23抖音面试题2020年3月.md) 157 | 158 | 159 | ## 赞赏一下旺仔(收集整理不易,且赞且珍惜) 160 | 161 |

162 | 163 | 164 | 165 |

166 | -------------------------------------------------------------------------------- /interview-iOS/14阿里腾讯百度头条美团iOS面试题2018年4月.md: -------------------------------------------------------------------------------- 1 | ## 阿里腾讯百度头条美团iOS面试题 2 | 3 | > Tamp__&&jianshu.com/p/a992b5f697ca 4 | 5 | - Effective Objective-C 6 | - 和Objective-C高级编程(多线程和内存管理) 7 | - 程序员的自我修养 8 | - 一个程序是如何被机器运行起来的? 9 | - 《剑指Offer》 (三遍) 10 | - 图解HTTP 11 | - 图解TCP/IP 12 | 13 | 14 | ### 美团一面 15 | * 算法奇数排在前面,偶数排在后面 16 | - [julycoding](https://github.com/julycoding/The-Art-Of-Programming-By-July/blob/master/ebook/zh/02.06.md) 17 | * 智力题,一个骑手送餐,ABCD商店,送给abcd四个人 18 | * kvo的实现原理 19 | * 消息调用的过程 20 | * get和post的区别 21 | * http有哪些部分 22 | * tcp和udp的区别 23 | * 七层模型 24 | 25 | ### 美团二面 26 | * 讲一讲响应链 27 | * 如何通过一个view查找它所在的viewController 28 | * 如何扩大view的响应范围 29 | * 微信分享大图如何实现,从进程的角度 30 | * 进程间的通信方式,并举例 31 | * 两个进程分别指向同一个地址空间并初始化一个值,分别输出是什么 32 | * 算法,判断一个字符串是否所有的大写字母都在小写字母前面 33 | * 修改podfile文件后,怎么用git diff显示出修改后版本和当前版本的不同,让我来设计 34 | * 程序执行的过程 35 | * 如果想要删除自己的一段代码,如何删除(在程序执行的过程中删除) 36 | * `编译链接的过程` 37 | * 用过脚本编程吗 38 | * 了解前后端吗 39 | * 各科成绩,成绩排名 40 | 41 | ### 阿里一面 42 | > 先介绍了项目,然后问了一些项目中的问题,然后开始问基础 43 | 44 | * 属性的关键字 45 | * 浅拷贝和深拷贝的区别 46 | * Block的循环引用、如何解决、原理 47 | * 三种Block 48 | * Block和delegate的比较 49 | * kvo的实现原理 50 | * Autorelease pool的实现原理 51 | * 消息转发机制 52 | * 线程死锁的四个条件 53 | * 进程和线程的区别 54 | * 持久化 55 | * 事务的特征 56 | * 中途还讨论了Masonry的约束应该写在哪里,我说应该写在layoutSubViews,他说会调用多次,然后争论了一会儿 57 | * 写在layoutSubview 里在8.0以上是没问题,早期版本 58 | * 约束可以写在创建SubViews的方法里,前提是你不横竖屏或横竖屏使用同一套约束。约束不应该写在布局方法里,而是写在更新约束方法里 `updateConstraints` 59 | 60 | ### 阿里二面 61 | * 介绍项目 62 | * 性能优化 63 | * YYModel和AF源码 64 | * 如何自己设计json转model 65 | * 架构 66 | * ![迷之算法题](https://upload-images.jianshu.io/upload_images/1293297-65f43ea82958c5c5.jpeg?imageMogr2/auto-orient/strip%7CimageView2/2/w/700) 67 | 68 | ### 阿里三面 69 | * 一个安卓的面试官。。。。。 70 | * 主要问了项目的一些东西 和给一些场景问我如何实现 71 | * 自我介绍 介绍一些项目难点 72 | * 主线程是相对于什么而言的 73 | * 一张图片的内存占用大小是由什么决定的 74 | * 索引的作用 75 | * 索引的优缺点 76 | * 在数组中找最小的k个数 77 | * 淘宝下拉加载更多如何优化 78 | * 淘宝页面发送HTTP请求的过程 79 | * 介绍一下MVVM 80 | * 知道哪些设计模式 81 | 82 | ### 头条一面 83 | * MVC的一些缺点 84 | * 讲一讲其它架构 85 | * 你知道哪些编码方式 86 | * 算法字符串翻转 87 | * HTTPS 88 | * 多线程的方式和它们的区别 89 | * 队列和线程的关系 90 | * 一道线程安全的题 91 | * 有哪些锁 92 | * 属性的关键字 93 | * assign可以用于OC对象吗 94 | * copy和strong的区别 95 | * weak如何实现自动赋nil 96 | * 为什么不可变对象要用copy 97 | * assing可以使用在对象中吗 98 | 99 | ### 头条二面 100 | 101 | * Pod update和pod install的区别 102 | * layoutIfNeeded和setNeedsLayout的区别 103 | * 抓包工具抓取HTTPS的原理 104 | * isEquel和hash的关系 105 | * SD的源码 106 | * bitmap的结构 107 | * [可变数组的实现原理](http://blog.joyingx.me/2015/05/03/NSMutableArray%20%E5%8E%9F%E7%90%86%E6%8F%AD%E9%9C%B2/) 108 | * NSArray 或 NSMutableArray 和 CFArray 完全没有共同点 109 | * __NSArrayM 用了环形缓冲区 (circular buffer)。这个数据结构相当简单,只是比常规数组或缓冲区复杂点。环形缓冲区的内容能在到达任意一端时绕向另一端 110 | * 在 0 处插入对象用了环形缓冲区魔法来将新插入的对象放置在缓存区的末端 111 | * 这意味着 __NSArrayM 可以对任意一端进行处理。你可以使用 __NSArrayM 作为栈或队列而没有任何性能问题 112 | * 每当缓冲区满了,它会重新分配1.625倍大小的空间。我很惊讶它居然不等于 2 113 | * 在删除的时候不会清除指针 114 | 115 | * 如何hook一个对象的方法,而不影响其它对象 116 | * 如何避免if else 117 | * 自旋锁和互斥锁的区别 118 | 119 | ### 头条三面 120 | 121 | * 介绍项目,主要介绍自己强项一点的地方 122 | * 数组cop后里面的元素会复制一份新的吗 123 | * 数组的浅拷贝与深拷贝 124 | * TCP为什么是三次握手和四次挥手 125 | 126 | ### 腾讯一面 127 | * 介绍项目的网络层 128 | * 为什么要使用HTTP???为什么不直接用TCP 129 | * 如何保证HTTP传输到达 130 | * HTTP头部有哪些内容 131 | * 讲一讲拥塞控制 132 | * MVVM如何实现绑定 133 | * block和通知的区别,分别适用什么场景 134 | * 算法。连续问了好几个,都是数组,层层递进的,但是我忘了,只记得最后是找出数组中重复的数字 135 | * 进程和线程的区别 136 | * 程序在运行时操作系统除了分配内存空间还有什么 137 | * 进程间通信的方式 138 | * 如何检测应用是否卡顿 139 | * 好像没多少问题了,记不太清,然后他说完了,我感觉好快,以为要挂了,就强行讲了些runloop和性能优化的东西,然后他说好了,你和下一轮面试官再说吧 140 | 141 | ### 腾讯二面 142 | * OC中对象的结构 143 | * 多态 144 | * Ping是什么协议 145 | * 知道MTU吗 146 | * TCP头部多长,IP呢 147 | * 线程同步的方式 148 | * iOS中有哪些锁 149 | * MVC和MVVM的区别 150 | * 了解哪些设计模式 151 | * 存一个通讯录,包括增删改查,用什么数据结构 152 | * 看过哪些源码,讲讲思路 153 | * 两个链表找第一个相同结点 154 | * 字符串旋转 155 | * 找链表的倒数第k个结点 156 | * 把一个链表比某个值大的放在左边,比它小的放在右边 157 | * 二叉树的中序遍历,非递归 158 | 159 | 160 | ### 百度一面 161 | > 大概回忆一下 162 | 163 | * 进程和线程的区别 164 | * 一个进程有哪些区 165 | * 拥塞控制 166 | * 进程间通信的方式 167 | * 七层模型 168 | * TCP和UDP的区别 169 | * 传输层和网络层分别是做什么的 170 | * UDP可以实现一对多?? 171 | * 算法 求数组的最长子数组 172 | * Http2.0如1.x的区别 173 | 174 | ### 百度二面 175 | * 发送一个HTTP请求的过程 176 | * TCP是如何保证可靠的 177 | * 内核态和用户态的区别 178 | * 在一个10G的数据里面找出最大的100个数 179 | * 讲一下我最满意的一个项目 180 | * 然后讲了一下网络造成卡顿的原因 181 | 182 | 183 | ### 百度三面 184 | > 全是问得iOS方面的问题,问得真的很细,需要基础很扎实,对各个机制真的足够理解,不然确实有点难回答。我只列举一下大概方向,这些东西也是iOS开发必须掌握的基础吧 185 | 186 | * 属性的关键字方面的 187 | * 内存管理方面的 188 | * 多线程 189 | * 各种队列 190 | * 线程锁 191 | * MVVM 192 | 193 | 194 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 195 | 196 |

197 | 198 |

199 | 200 | ## 链接 201 | 202 | - [面试题系列目录](../README.md) 203 | - **上一份**: [2018秋招iOS面试总结](13秋招iOS面试总结2018年.md) 204 | - **下一份**: [腾讯社招iOS面试记录2018年7月](15腾讯社招iOS面试记录2018年7月.md) 205 | 206 | -------------------------------------------------------------------------------- /interview-iOS/18苏州蜗牛iOS开发面试题2018年春.md: -------------------------------------------------------------------------------- 1 | 2 | # 苏州蜗牛iOS开发面试题2018年春 3 | 4 | > 作者:RocketsChen&&jianshu.com/p/ffc9b1cec635 5 | 6 | > 面试通知邮件:邮件+电话约当天下午的面试 7 | 8 | > **笔试+面试 模式** 9 | 10 | > 虽然对笔试有心里准备但是当拿到5页面试题的时候心还是细微的颤抖了下,除了第一张是一道考宏交换的程序判断题和最后一页三条题<纠错,趣味>以外,中间三页题目密度在平均一页7条。总的来说题量还是很感人的!当然接待的人事特意跟我说笔试题是开卷。 11 | 12 | ## 笔试 13 | 14 | > 附上如下部分面试题目,总的来说蜗牛的面试题题量涉及的范围还是挺广的。 15 | 16 | > 我大概做了五十几分钟,然后接待的人事和我说不用写了,可以接下来准备下一轮面试。(笔试过程中有人来看过我,下一轮的面试官) 17 | 18 | ### 简述itms-services作用 19 | 20 |
21 | 参考内容 22 | 23 | > 备注:**iOS14开始,需要IPA包下载地址和plist地址均使用HTTPS** 24 | 25 | - 苹果安装app的另一种方式(通过itms-services协议,不通过AppStore,直接安装IOS应用程序) 26 | 27 | - 其实是利用苹果自家的浏览器safari和itms-services协议来实现的:只要在内网布置一个服务器,测试人员只需要通过测试设备的safari浏览器访问特定的url既可以实现安装 28 | 29 |
30 | 31 | ### POST和GET谁更安全?以及谈谈服务器交互的过程中更安全的保护措施? 32 |
33 | 参考内容 34 | 35 | > [POST和GET区别](./01一份"有点难"的iOS面试题MrPeak2016年.md) 36 | 37 | - GET传输方式将在URL中显示参数,更容易引发一些“不怀好意”人的兴趣,POST相对来说比get方法更加安全。当然是没有绝对的安全的 38 | - HTTP协议中提到GET是安全的方法(safe method),其意思是说GET方法不会改变服务器端数据,所以不会产生副作用。如果是该用POST的地方用了GET,又说GET不安全,那GET也太冤枉了。也就是说,只要我们正确选择使用GET和POST,那么GET是安全的。 39 | - 只要我们正确使用二者,因为GET方法中不对数据进行修改,不传送一些保密的信息,而这些需要由POST来传输,所以说GET不存在安全问题,而需要注意的是POST传输的安全问题。 40 | 41 | - 更安全的保护措施[客户端侧] 42 | - 跟服务器端确认是否需要添加特定的user-agent(添加user-agent的目的:确保服务器安全)。 43 | - 确认客户端和服务器端交互时是否需要对文件进行加密操作。 44 | - 跟开发确认请求时是否需要增加重试和具体的超时机制,有无下载的断点续传。 45 | - 对于异常情况,跟服务器和客户端的开发确定相应的容错处理。 46 | - 需要注意询问开发,与服务器之间的交互是用什么做的,标准的http协议还是自写的协议。 47 | 48 |
49 | 50 | 51 | ### 对于一个xxxx.a的静态库而言,如何使用命令行来查看其支持的CPU架构 ? 苹果在2015年2月之后要求我们必须支持哪一种CPU架构; 52 |
53 | 参考内容 54 | 55 | > [iOS_StaticLibrary](../iOSNote/iOS_StaticLibrary.md) 56 | 57 | - 使用命令: lipo -info .a文件名称, 即可查看静态库所支持的系统架构。 58 | 59 | - arm64 60 | 61 |
62 | 63 | 64 | ### duplicate symbol是什么?谈谈如何避免和产生后解决方案; 65 | 66 |
67 | 参考内容 68 | 69 | > 两个静态库冲突. 70 | > 文件中重复定义了一个函数、变量(比如全局变量) 71 | > 工程中包含同名的文件。 72 | 73 | - 在使用import 引入头文件时,由于疏忽,误引入.m 文件 74 | - 同名文件放在不同的文件夹下 75 | - 在 Targets 的 Build Phrases 设置里,查看下 Complie Sources这一项,看看出现问题的类是不是重复的.如果是重复的,删除掉重新添加也能解决这个问题 76 | - 1如果是两个静态库冲突的话,可以将两个.a静态库解压,删除其中一个里面重复的.o文件(编译时产生的临时文件),然后用lipo命令合并两个静态库;比如libx.a文件 77 | 78 |
79 | 80 | 81 | ### 时间和空间复杂度(剑指Offer-第五章) 82 | 83 |
84 | 参考内容 85 | 86 | > 算法(Algorithm)是指用来操作数据、解决程序问题的一组方法。对于同一个问题,使用不同的算法,也许最终得到的结果是一样的,但在过程中消耗的资源和时间却会有很大的区别。 87 | 88 | #### 那么我们应该如何去衡量不同算法之间的优劣呢? 89 | 90 | > 主要还是从算法所占用的「时间」和「空间」两个维度去考量。 91 | 92 | - 时间维度:是指执行当前算法所消耗的时间,我们通常用「时间复杂度」来描述。 93 | * 大O符号表示法,即 T(n) = O(f(n)) 【算法的渐进时间复杂度】 94 | * 常数阶O(1) 95 | * 对数阶O(logN) 96 | * 线性阶O(n) 97 | * 线性对数阶O(nlogN) 98 | * 平方阶O(n²) 99 | * 立方阶O(n³) 100 | * K次方阶O(n^k)【n的k次方 101 | * 指数阶(2^n) 102 | 103 | - 空间维度:是指执行当前算法需要占用多少内存空间,我们通常用「空间复杂度」来描述。 104 | - 如果算法执行所需要的临时空间不随着某个变量n的大小而变化,即此算法空间复杂度为一个常量,可表示为 O(1) 105 | 106 |
107 | 108 | 109 | ### 交叉编译?简述一下iOS中开发应用场景; 110 | 111 |
112 | 参考内容 113 | > 在iOS设备上进行音视频的处理,往往要使用市面上比较流行的音视频相关库,比如音频编码的Lame,处理视频的FFmpeg,处理图片的OpenCV等. 114 | 115 | - 编译型语言的源代码,比如C源代码,要能在PC上运行,需要经过编译,链接,成为PC可执行的二进制文件,然后才能在PC上运行.同理,如果要在其他机器上运行,就必须编译,链接成为可以在其他机器上运行的代码. 116 | - 源代码在机器A上的编译链接得到机器B上运行的代码. 117 | - 如果机器B==机器A,那么就是本机编译. 118 | - **如果机器B!=机器A,就是交叉编译.** 119 | 120 |
121 | 122 | 123 | ### 两个具体上架过程中苹果审核失败返回的信息请问如何解决:翻译过来第一条是:利用邀请奖励制度来诱惑玩家驳回 第二条是:抽奖类的比赛规则驳回; 124 | 125 | ### 备注:以下三题原文均无细节 126 | 127 | * 具体的报错Log分析题; 128 | * 程序输出结果题; 129 | * 趣味思考题。 130 | 131 | 132 | ## 面试: 133 | 134 | > 两位面试官:拿着我答题卷和简历开始进行面试:问题整理下大致有如下几个 135 | 136 | * 简单分享下你开源作品中的一个技术点 137 | * 对于热跟新技术的理解还有雷区 138 | * 对于项目中的动态性的处理和看法以及组件的运用 139 | * 对于图片加载的方式和图片展示方式的思考 140 | * 项目中使用的框架 141 | * 深入的问了几条我的面试卷上的题目,其中有一条我提出了疑问,面试官简单的给我讲解了下 142 | 分析一下趣味题的实现思路 143 | 144 | * 问了下职业规划 145 | * 对于技术探究和专研方面 146 | * 最后就是问我有没有什么想问的 147 | 148 | > 这样就算面试都结束了。然后过了大概一周人事给我电话说面试已经通过,可以给offer了。面试过程大概用了两个小时。 149 | 150 | ## 总结 151 | 152 | - 总的面试过程还算是比较顺利的,面试官也很友善。对我来说算是来面试的过程中有所学习。开始我在去蜗牛的路上本以为会问一些runtime、Block、MVC、MVP、MVVM、GCD、ARC等等,结果拿到题算是和我想的不太一样,是把技术点运用到实际问题中,比如最后一页的Crash纠错:在一堆报错日志分析下来:简单的来说就是持有的通知对象在生命周期销毁之前没有被释放而或重复使用。是使用KVO常遇到的一种报错。解决:当前持有的被观察对象,在-dealloc中移除观察者。 153 | 154 | - 在面试过程中肯定有会被面试官问道你不会的的题目,可以进一步题目来问清楚具体查考的方面。不要说一堆与题目无关或误关的的东西。 155 | 156 | 157 | ## 分享最近看的几本书: 158 | 159 | * 《Effective Objective-C 2.0》 160 | * 《剑指Offer》 161 | * 《程序员的自我修养》 162 | * 《Objective-C编程之道》 163 | 164 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 165 | 166 |

167 | 168 |

169 | 170 | ## 链接 171 | 172 | - [面试题系列目录](../README.md) 173 | - **上一份**: [阿里网易蘑菇街同花顺等面试题2018年7月](17阿里网易蘑菇街同花顺等面试题2018年7月.md) 174 | - **下一份**: [新浪公司iOS面试题2019年6月](19新浪公司iOS面试题2019年6月.md) 175 | 176 | 177 | -------------------------------------------------------------------------------- /iOSNote/Analyze/SDWebImage/网络网络状态不同加载图片.md: -------------------------------------------------------------------------------- 1 | ## 网络网络状态为WiFi时,显示图片高清图;网络状态为蜂窝移动网络时,显示 图片缩略图 2 | 3 | > [出处](https://www.jianshu.com/p/dabc0c6d083e) 4 | 5 | - 用户在WiFi环境下下载的高清图,下次在蜂窝网络状态下打开应用也应显示高清图,而不是去下载缩略图 6 | - 移动网络环境下仍然显示高清图 7 | - 用户处于离线状态时候,合理处理业务 8 | 9 | ### 存在 `bug` 版本 10 | 11 | ``` 12 | - setItem:(CustomItem *)item 13 | { 14 | _item = item; 15 | 16 | // 占位图片 17 | UIImage *placeholder = [UIImage imageNamed:@"placeholderImage"]; 18 | 19 | // 从内存\沙盒缓存中获得原图, 20 | UIImage *originalImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:item.originalImage]; 21 | if (originalImage) { // 如果内存\沙盒缓存有原图,那么就直接显示原图(不管现在是什么网络状态) 22 | self.imageView.image = originalImage; 23 | } else { // 内存\沙盒缓存没有原图 24 | AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager]; 25 | if (mgr.isReachableViaWiFi) { // 在使用Wifi, 下载原图 26 | [self.imageView sd_setImageWithURL:[NSURL URLWithString:item.originalImage] placeholderImage:placeholder]; 27 | } else if (mgr.isReachableViaWWAN) { // 在使用手机自带网络 28 | // 用户的配置项假设利用NSUserDefaults存储到了沙盒中 29 | // [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"alwaysDownloadOriginalImage"]; 30 | // [[NSUserDefaults standardUserDefaults] synchronize]; 31 | #warning 从沙盒中读取用户的配置项:在3G\4G环境是否仍然下载原图 32 | BOOL alwaysDownloadOriginalImage = [[NSUserDefaults standardUserDefaults] boolForKey:@"alwaysDownloadOriginalImage"]; 33 | if (alwaysDownloadOriginalImage) { // 下载原图 34 | [self.imageView sd_setImageWithURL:[NSURL URLWithString:item.originalImage] placeholderImage:placeholder]; 35 | } else { // 下载小图 36 | [self.imageView sd_setImageWithURL:[NSURL URLWithString:item.thumbnailImage] placeholderImage:placeholder]; 37 | } 38 | } else { // 没有网络 39 | UIImage *thumbnailImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:item.thumbnailImage]; 40 | if (thumbnailImage) { // 内存\沙盒缓存中有小图 41 | self.imageView.image = thumbnailImage; 42 | } else { // 处理离线状态,而且有没有缓存时的情况 43 | self.imageView.image = placeholder; 44 | } 45 | } 46 | } 47 | } 48 | 49 | 50 | ``` 51 | 52 | ### 详细分析 53 | 54 | - UITableViewCell的缓存机制,一个展示 list 55 | 56 | - 没有cell被推出屏幕,此时`缓存池为空` 57 | - 当有一个cell被推到屏幕之外时,系统会自动将这个cell放入自动缓存池,依旧存在对应的数据模型 58 | 59 | > `BUG 场景 `当用户所处环境WiFi网速不够快(不能立即将图片下载完毕),而在上述代码,在WiFi环境下又是下载高清大图。所以需要一定的时间来完成下载。而就在此时,用户不愿等,想看看上次打开App时显示的图片,此时用户会滑到处于下面的cell来查看。注意:此时,上面的cell下载图片操作并没有暂停,还在处于下载图片状态中。当用户在查看上次打开App的显示图片时(上次打开App下载完成的图片,SDWebImage会帮我们缓存,不用下载),而正好需要显示上次打开App时的图片的cell是利用tableView重用机制而从缓存池中拿出来的cell,等到处于上面的cell的高清大图已经下载好了的时候,SDWebImage默认做法是,立马把下载好的图片设置给ImageView,所以我们这时候会在底下的显示的cell显示上面的图片,造成数据错乱,这是非常严重的BUG 60 | 61 | ``` 62 | 63 | - setItem:(CustomItem *)item 64 | { 65 | _item = item; 66 | 67 | // 占位图片 68 | UIImage *placeholder = [UIImage imageNamed:@"placeholderImage"]; 69 | 70 | // 从内存\沙盒缓存中获得原图 71 | UIImage *originalImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:item.originalImage]; 72 | if (originalImage) { // 如果内存\沙盒缓存有原图,那么就直接显示原图(不管现在是什么网络状态) 73 | [self.imageView sd_setImageWithURL:[NSURL URLWithString:item.originalImage] placeholderImage:placeholder]; 74 | } else { // 内存\沙盒缓存没有原图 75 | AFNetworkReachabilityManager *mgr = [AFNetworkReachabilityManager sharedManager]; 76 | if (mgr.isReachableViaWiFi) { // 在使用Wifi, 下载原图 77 | [self.imageView sd_setImageWithURL:[NSURL URLWithString:item.originalImage] placeholderImage:placeholder]; 78 | } else if (mgr.isReachableViaWWAN) { // 在使用手机自带网络 79 | // 用户的配置项假设利用NSUserDefaults存储到了沙盒中 80 | // [[NSUserDefaults standardUserDefaults] setBool:NO forKey:@"alwaysDownloadOriginalImage"]; 81 | // [[NSUserDefaults standardUserDefaults] synchronize]; 82 | #warning 从沙盒中读取用户的配置项:在3G\4G环境是否仍然下载原图 83 | BOOL alwaysDownloadOriginalImage = [[NSUserDefaults standardUserDefaults] boolForKey:@"alwaysDownloadOriginalImage"]; 84 | if (alwaysDownloadOriginalImage) { // 下载原图 85 | [self.imageView sd_setImageWithURL:[NSURL URLWithString:item.originalImage] placeholderImage:placeholder]; 86 | } else { // 下载小图 87 | [self.imageView sd_setImageWithURL:[NSURL URLWithString:item.thumbnailImage] placeholderImage:placeholder]; 88 | } 89 | } else { // 没有网络 90 | UIImage *thumbnailImage = [[SDImageCache sharedImageCache] imageFromDiskCacheForKey:item.thumbnailImage]; 91 | if (thumbnailImage) { // 内存\沙盒缓存中有小图 92 | [self.imageView sd_setImageWithURL:[NSURL URLWithString:item.thumbnailImage] placeholderImage:placeholder]; 93 | } else { 94 | [self.imageView sd_setImageWithURL:nil placeholderImage:placeholder]; 95 | } 96 | } 97 | } 98 | } 99 | 100 | ``` 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | -------------------------------------------------------------------------------- /iOSNote/CocoaPods/cocoapods-PodFile&spec.md: -------------------------------------------------------------------------------- 1 | # PodFile&&Podspec 2 | 3 | ## base 4 | 5 | - **cocoapods**: **/Users/`LFL`/.cocoapods/repos** 6 | 7 | - **cache**: **/Users/`LFL`/Library/Caches/CocoaPods/** 包含如下 8 | - pods :缓存已经安装的第三方 9 | - search_index.json 10 | 11 | 12 | ## Podspec 13 | 14 | ```ruby 15 | s.name:名称,pod search 搜索的关键词 16 | s.version:版本 (tag) 17 | s.summary:pod search 搜索的关键词 18 | s.homepage:主页地址,例如Github地址 19 | s.license:许可证 20 | s.author:作者 21 | s.social_media_url:社交网址 22 | s.platform:平台 23 | s.source:Git仓库地址,例如在Github地址后边加上 .git 就是Git仓库地址. 24 | s.source_files :"ProjectKit/*" 25 | * `*` 表示匹配所有文件:"ProjectKit/*" 26 | * `*.{h,m}` 表示匹配所有以.h和.m结尾的文件:"ProjectKit/Classes/*.{h,m}" 27 | * `**` 表示匹配所有`子目录`:"ProjectKit/**/*.h" 28 | 29 | s.resources:需要包含的图片等资源文件 30 | s.dependency:依赖库,如有多个可以这样写,需要用到的frameworks,不需要加.frameworks后缀 31 | s.requires_arc:是否要求ARC 32 | 33 | ``` 34 | 35 | - **资源文件** 36 | - `Assets` 文件夹内图片资源最终会打包成一个 `bundle` 文件 37 | 38 | ``` 39 | 图片bundle 资源 40 | 41 | [[NSbundle bundleForClass :self] pathForResource:"" inDirectory:"当前pod库名.bundle"] 42 | 43 | 44 | cell : xib 45 | 46 | cell = [[[NSBundle bundleForClass:self] loadNibNamed:@"cell 对应 name " owner:nil options:nil] firstObject]; 47 | 48 | cell 使用图片:`当前pod库名.bundle/图片名`,不能再使用[UIImage imageName:@"名字"],使用 contenofURL 49 | 50 | 51 | ``` 52 | - **xib 处理** 53 | - 先编译为 `nib` 54 | - 读取涉及图片,需要处理对应的`@2`,`@3` 55 | 56 | 57 | - **子库分离 参考 "AFN"** 58 | 59 | 60 | `s.subspec 'LFLSegumentTool' do |b| 61 | b.source_files => 'LFLTest/LFLSegumentTool/*' 62 | 子库依赖单独处理 63 | b.dependecy = 'GitHubSegumentTool' 64 | end` 65 | 66 | 67 | ### PodFile 68 | 69 | - 指定多个子库 70 | 71 | ``` 72 | pod `LFLKit`,:subspec =>['base','LFLTool'] 73 | 74 | ``` 75 | 76 | - 如果您的Pods文件夹不包含在git中,则您可以添加keep_source_code_for_prebuilt_frameworks!Podfile的头部以加快Pod的安装速度,因为每次预建的Pod发生更改时,它都不会下载所有源代码。 77 | 78 | - enable_bitcode_for_prebuilt_frameworks! 79 | 80 | ```ruby 81 | 要使用仓库的另一个分支: 82 | 83 | pod 'Alamofire', :git => 'https://github.com/Alamofire/Alamofire.git', :branch => 'dev' 84 | 85 | 要使用master仓库的分支: 86 | 87 | pod 'Alamofire', :git => 'https://github.com/Alamofire/Alamofire.git' 88 | 89 | /// 指定固定源 90 | pod 'PonyDebugger', :source => 'https://github.com/CocoaPods/Specs.git' 91 | 92 | pod 'QueryKit', :subspecs => ['Attribute', 'QuerySet'] 93 | 94 | pod "test",:head 一直最新 95 | 96 | ``` 97 | 98 | - Build configurations 99 | 100 | ```ruby 101 | pod 'PonyDebugger', :configurations => ['Debug', 'Beta'] 102 | 103 | pod 'PonyDebugger', :configuration => 'Debug' 104 | 105 | ``` 106 | 107 | ### generate_multiple_pod_projects 108 | 109 | 110 | - `install! 'cocoapods', generate_multiple_pod_projects: true` 111 | 112 | - 多个兼容 113 | 114 | ```ruby 115 | install! 'cocoapods', 116 | disable_input_output_paths: true, 117 | generate_multiple_pod_projects: true 118 | 119 | ``` 120 | 121 | ```ruby 122 | 123 | post_install do |installer| 124 | 125 | swift_4_0_compatible = [ ... ] 126 | swift_4_2_compatible = [ ... ] 127 | 128 | installer.pod_target_subprojects.flat_map { |p| p.targets }.each do |t| 129 | t.build_configurations.each do |c| 130 | c.build_settings['SWIFT_VERSION'] = '4.0' if swift_4_0_compatible.include? t.name 131 | c.build_settings['SWIFT_VERSION'] = '4.2' if swift_4_2_compatible.include? t.name 132 | end 133 | end 134 | end 135 | 136 | ``` 137 | ## PodSpec 扩展 138 | 139 | > https://guides.cocoapods.org/syntax/podspec.html 140 | 141 | - s.static_framework = true 142 | - 是否是静态库 这个地方很重要 假如不写这句打出来的包 就是动态库 不能使用 一运行会报错 image not found 143 | 144 | - spec.swift_version = '3.0', '4.0' 145 | 146 | - spec.cocoapods_version = '>= 0.36' 147 | 148 | - spec.prepare_command = 'ruby build_files.rb' 149 | 150 | - spec.dependency 'AFNetworking', '~> 1.0', :configurations => ['Debug'] 151 | 152 | - spec.prefix_header_contents = '#import ', '#import ' 153 | 154 | 155 | ```ruby 156 | 157 | spec.prefix_header_file = 'iphone/include/prefix.pch' 158 | spec.prefix_header_file = false 159 | 160 | spec.module_name = 'Three20' 161 | 162 | # 配置 Xcode Build Setting 163 | s.xcconfig = { 164 | 'HEADER_SEARCH_PATHS' => '$(PODS_ROOT)/', # 配置 Header 搜索路径 165 | 'FRAMEWORK_SEARCH_PATHS' => '$(PODS_ROOT)/', # 配置 Framwork 搜索路径 166 | 'GCC_PREPROCESSOR_DEFINITIONS' => 'RELEASE COCOAPODS=1' # 配置预编译宏 167 | } 168 | 169 | ``` 170 | 171 | ```ruby 172 | spec.ios.vendored_frameworks = 'Frameworks/MyFramework.framework' 173 | spec.vendored_frameworks = 'MyFramework.framework', 'TheirFramework.framework' 174 | 175 | spec.ios.vendored_library = 'Libraries/libProj4.a' 176 | spec.vendored_libraries = 'libProj4.a', 'libJavaScriptCo 177 | 178 | spec.ios.resource_bundle = { 'MapBox' => 'MapView/Map/Resources/*.png' } 179 | spec.resource_bundles = { 180 | 'MapBox' => ['MapView/Map/Resources/*.png'], 181 | 'MapBoxOtherResources' => ['MapView/Map/OtherResources/*.png'] 182 | } 183 | 184 | spec.resource = 'Resources/HockeySDK.bundle' 185 | 186 | spec.resources = ['Images/*.png', 'Sounds/*'] 187 | 188 | spec.default_subspec = 'Core' 189 | spec.default_subspecs = 'Core', 'UI' 190 | spec.default_subspecs = :none 191 | 192 | ``` 193 | 194 | ```ruby 195 | Pod::Spec.new do |spec| 196 | spec.name = 'ShareKit' 197 | spec.source_files = 'Classes/ShareKit/{Configuration,Core,Customize UI,UI}/**/*.{h,m,c}' 198 | # ... 199 | 200 | spec.subspec 'Evernote' do |evernote| 201 | evernote.source_files = 'Classes/ShareKit/Sharers/Services/Evernote/**/*.{h,m}' 202 | end 203 | 204 | spec.subspec 'Facebook' do |facebook| 205 | facebook.source_files = 'Classes/ShareKit/Sharers/Services/Facebook/**/*.{h,m}' 206 | facebook.compiler_flags = '-Wno-incomplete-implementation -Wno-missing-prototypes' 207 | facebook.dependency 'Facebook-iOS-SDK' 208 | end 209 | # ... 210 | end 211 | 212 | ``` 213 | 214 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # iOS Interviews DevNotes 2 | 3 |

4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |

12 | 13 | > 聚焦于**iOS开发面试题和开发笔记** 14 | 15 | > 如果你觉得此仓库对你有价值,欢迎 star/fork,蟹蟹🤝。 16 | 17 | - **[iOSDevNote](#iOSDevNote)** 18 | - **[Git,MarkDown ,Shell等点此处跳转](https://github.com/DevDragonLi/DevelopBaseNote)** 19 | 20 | ## B站iOS开发相关视频 21 | 22 | > [作者B站首页视频点此可一览目录](https://space.bilibili.com/108575967/video) 视频相关文档资料等[请点这里](./Bilibili) 23 | 24 | - [iOS面试知识点备战规划2021版](https://www.bilibili.com/video/BV1YU4y157zn/) 25 | - [**iOS端组件化整套技术方案概述**](https://www.bilibili.com/video/BV1Kw411o7Za/) 26 | - [面试高频六大设计原则及常见设计模式解析](https://www.bilibili.com/video/BV1v44y1q75D/) 27 | - [iOS开发之设计一套暗黑模式组件【框架思维及iOS关联对象项目运用】](https://www.bilibili.com/video/BV1p64y1B7bb/) [**点此查阅 PDF文稿**](https://github.com/DevDragonLi/LFLDarkModeKit) 28 | 29 | ## iOS面试题目列表 30 | 31 | > **是迄今为止东半球收集并整理参考解答最为全的面试题集合** 32 | 33 | > **整理不易:本作品采用知识共享署名 4.0 国际许可协议进行许可,转载时请注明原文链接,并保留全部内容!!!** 34 | 35 | - 温馨提示1️⃣:可任意份点进文档均提供`上/下一份`超链方便查阅,并提供大纲超链😁。 36 | 37 | - 温馨提示1️⃣:已更新并整理`参考答案` 默认`折叠`展示(点击可查阅) 38 | 39 | 1. [一份"有点难"的iOS面试题MrPeak2016年:参考答案完整✅](./interview-iOS/01一份"有点难"的iOS面试题MrPeak2016年.md) 40 | 2. [interview-iOS-2:参考答案完整✅](./interview-iOS/02interview-iOS-2.md) 41 | 3. [interview-iOS-3:参考答案完整✅](./interview-iOS/03interview-iOS-3.md) 42 | 4. [interview-iOS-4:参考答案完整✅](./interview-iOS/04interview-iOS-4.md) 43 | 5. [宝库iOS研发岗面试2017年:参考答案完整✅](./interview-iOS/05iOS宝库iOS开发笔试题2017年.md) 44 | 6. [iOS基础问题系列2017年:参考答案完整✅](./interview-iOS/06iOS基础问题系列2017年.md) 45 | 7. [深圳iOS面试分享2018年4月:参考答案完整✅](./interview-iOS/07深圳iOS面试分享2018年4月.md) 46 | 8. [字节跳动面试题2018年4月:参考答案完整✅](./interview-iOS/08字节跳动面试题:2018年4月.md) 47 | 9. [头条网易微信阿里美团硕士春招面试题2018年3月(作者po了iOS的问题背后知识点)](./interview-iOS/09头条网易微信阿里美团硕士春招面试题2018年3月.md) 48 | 10. [美团饿了么面试题2018年4月:参考答案完整✅](./interview-iOS/10美团饿了么面试题2018年4月.md) 49 | 11. [天猫蚂蚁金服百度面试题2018年4月参考答案基本完整✅](./interview-iOS/11天猫蚂蚁金服百度面试题2018年4月.md) 50 | 12. [校招攻略43份优质面经汇总iOS开发2018年](./interview-iOS/12校招攻略43份优质面经汇总iOS开发2018年.md) 51 | 13. [秋招iOS面试总结2018年](./interview-iOS/13秋招iOS面试总结2018年.md) 52 | 14. [阿里腾讯百度头条美团iOS面试题2018年4月](./interview-iOS/14阿里腾讯百度头条美团iOS面试题2018年4月.md) 53 | 15. [腾讯社招iOS面试记录2018年7月:参考答案完整✅](./interview-iOS/15腾讯社招iOS面试记录2018年7月.md) 54 | 16. [**腾讯音乐iOS面试题2018年7月**:部分提示解答模式✅](./interview-iOS/16腾讯音乐iOS面试题2018年7月.md) 55 | 17. [阿里网易蘑菇街同花顺等面试题2018年7月](./interview-iOS/17阿里网易蘑菇街同花顺等面试题2018年7月.md) 56 | 18. [苏州蜗牛iOS开发面试题2018年春:一面题目解答完毕✅](./interview-iOS/18苏州蜗牛iOS开发面试题2018年春.md) 57 | 19. [**新浪公司iOS面试题2019年6月**:参考答案完整✅](./interview-iOS/19新浪公司iOS面试题2019年6月.md) 58 | 20. **推荐:**[**阿里字节一套高效的iOS面试题2020年2月**:参考答案基本完整✅](./interview-iOS/20阿里字节一套高效的iOS面试题2020年2月.md) 59 | 21. [**出一套iOS高级面试题:J_Knight_**:参考答案基本完整✅](./interview-iOS/21出一套iOS高级面试题2018年7月.md) 60 | 22. [快手X3岗面试题2020年3月](./interview-iOS/22快手X3岗面试题2020年3月.md) 61 | 23. [抖音面试题2020年3月:参考答案完整✅](./interview-iOS/23抖音面试题2020年3月.md) 62 | 24. [阿里iOS五轮面经2019年10月](./interview-iOS/24阿里iOS五轮面经2019年10月.md) 63 | 25. [小米百度bigo滴滴快手等iOS面试题2020年上:参考答案补充完善中🚀](./interview-iOS/25小米百度bigo滴滴快手等iOS面试题2020年上.md) 64 | 26. [腾讯iOS六轮面试分享2020年](./interview-iOS/26腾讯iOS六轮面试分享2020年.md) 65 | 27. [抖音快手等面试题2020年9月](./interview-iOS/27抖音快手等面试题2020年9月.md) 66 | 28. [字节iOS面试题](./interview-iOS/字节_面试.pdf) 67 | 68 | ## iOSDevNote 69 | 70 | | CATEGORY | FILENAME | 71 | |:----|:----| 72 | |iOS技能图谱/技术栈|[iOS技能图谱-byStuQ](./iOSNote/map-MobileDev-iOSDev.md)
[JSPatch作者博客中的技能栈-图](./images/iOS/iOSDev-bang.png)| 73 | |iOS开发相关shell脚本|[组件自动化更新&&组件校验脚本](https://github.com/DevDragonLi/DevelopBaseNote#shell)
[多项目批量更新检出脚本](https://github.com/DevDragonLi/DevelopBaseNote#shell)| 74 | |iOSDevNote|[**东半球效率最高的iOS组件通信中间件**](https://github.com/DevDragonLi/ProtocolServiceKit)
[**iOS UI界面热重载神器InjectionTool**:支持懒加载](https://github.com/Todaycoding/InjectionTool)
[**DarkMode适配组件**](https://github.com/DevDragonLi/LFLDarkModeKit)
[iOS项目完全解耦**Debug菜单中心组件**](https://github.com/DevDragonLi/iOSDebugKit)
[**iOS开发架构分享文稿**](./iOSNote/iOS_architecture.pdf)
[**掘金客户端体积瘦身**](./iOSNote/iOSAppThin.md)
[**iOSDevCodeRepo**](https://github.com/DevDragonLi/iOSDevDemo)
[Core Animation框架结构及性能调优11张大图详解](https://github.com/DevDragonLi/Core-AnimationPerformanceOptimization)
[iOS_StaticLibrary](./iOSNote/iOS_StaticLibrary.md)
[iOS经典Crash分析与总结- QQ`MelonTeam`](https://github.com/DevDragonLi/iOSDevDemo)
[iOS核心动画高级技巧阅读笔记(**性能调优**,**高效绘制**,**图像IO**,**图层性能**)](./iOSNote/iOSCoreAnimationNote.md)
[单元测试概述](./iOSNote/UnitTesting.md)| 75 | |CocoaPods |[**cocoapods Install [已适配M1]**](./iOSNote/CocoaPods/cocoapods.md)
[**cocoapods-plugins:插件汇总**](./iOSNote/CocoaPods/cocoapods-plugins.md)
[开源组件之开发流程](./iOSNote/CocoaPods/cocoapods-pod.md)
[管理库的使用技巧](./iOSNote/CocoaPods/cocoapods-pod.md)
[公司内部组件化开发参考基础文档](./iOSNote/CocoaPods/cocoapods-PodFile&spec.md)
[私有库参考Demo](https://github.com/DevDragonLi/iOSDevDemo/tree/master/1-DevDemo/PodPrivate_demo)
[Podspec语法说明及PodFile使用汇总](./iOSNote/CocoaPods/cocoapods-PodFile&spec.md)| 76 | |开源框架|**[WiFi显示图片高清图;蜂窝显示图片缩略图解析](./iOSNote/Analyze/SDWebImage/网络网络状态不同加载图片.md)**
**[MJRefresh源码解析](./iOSNote/Analyze/MJRefresh/MJRefresh.md)**| 77 | 78 | ## 赞赏一下旺仔(收集整理不易,且赞且珍惜) 79 | 80 |

81 | 82 |

83 | 84 | ## 欢迎提交 PR / issue 85 | 86 | > **Dragonli_52171@163.com** 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /interview-iOS/07深圳iOS面试分享2018年4月.md: -------------------------------------------------------------------------------- 1 | # 深圳iOS面试分享2018年4月 2 | 3 | > 作者:Xcode_boy&&juejin.im/post/5adaed6a518825673123c757 4 | 5 | - [请在1000万个整型数据中以最快的速度找出其中最大的1000个数?](#请在1000万个整型数据中以最快的速度找出其中最大的1000个数) 6 | - [循环链表题:一个有序循的整形环链表断开了,请插入一个整形数,使得链表仍然是有序的。](#循环链表题一个有序循的整形环链表断开了请插入一个整形数使得链表仍然是有序的) 7 | - [Block中可以修改全局变量,全局静态变量,局部静态变量吗?](#block中可以修改全局变量全局静态变量局部静态变量吗) 8 | - [NSString代码输出考察 ?](#nsstring代码输出考察) 9 | - [SDWebImage实现原理是什么? 10 | 它是如何解决tableView的复用时出现图片错乱问题的呢?](#sdwebimage实现原理是什么-它是如何解决tableview的复用时出现图片错乱问题的呢) 11 | - [Swift问题](#swift问题) 12 | - [struct 和 class 的区别?](#struct-和-class-的区别) 13 | - [class与staitc关键字的区别?](#class与staitc关键字的区别) 14 | 15 | ## 算法题 16 | 17 | ### 请在1000万个整型数据中以最快的速度找出其中最大的1000个数? 18 |
19 | 参考内容 20 | 21 | > 这是一个经常被问到的问题,百度网上解法也很多。这里仅提供基本思路,供参考: 22 | 23 | - 把1000万的整型平均分到合适n个文件中,分别对每一份文件找出前1000个最大的数,最后对每份文件前1000数据用常规算法合并即可。 24 | - 那么,如何从每一份文件中找出前1000个最大的数呢? 25 | - **先取文件中前1000个数放到数组中,并排好序(假设升序),之后从文件中读取下一个数与数组第一个数比较,如果比数组中第一个数大,则替换数组第一个数,并重新排序,之后再取下一个数进行下轮比较即可。** 26 | 27 |
28 | 29 | ### 循环链表题:一个有序循的整形环链表断开了,请插入一个整形数,使得链表仍然是有序的。 30 | 31 |
32 | C语言实现参考内容 33 | 34 | ``` 35 | #include 36 | #include 37 | typedef struct node{ 38 | int data; 39 | struct node *next; 40 | }linklist; 41 | 42 | linklist *createList(){ 43 | linklist *head,*p,*q; 44 | int x; 45 | scanf("%d",&x); 46 | p=(linklist *)malloc(sizeof(linklist)); 47 | p->data=x; 48 | head=p; 49 | scanf("%d",&x); 50 | while (x!=-1){ 51 | q=(linklist *)malloc(sizeof(linklist)); 52 | q->data=x; 53 | p->next=q; 54 | p=q; 55 | scanf("%d",&x); 56 | } 57 | p->next=NULL; 58 | return head; 59 | } 60 | 61 | linklist *insertList(int n,linklist *head){ 62 | linklist *p,*q,*s; 63 | s=(linklist *)malloc(sizeof(linklist)); 64 | s->data=n;s->next=NULL; 65 | if (head==NULL) return p; 66 | p=q=head; 67 | while (q!=NULL && q->data < n){ 68 | p=q;q=q->next; 69 | } 70 | if (p==head){ 71 | s->next=p;head=s;//在头部插入 72 | } 73 | else{ 74 | s->next=q;p->next=s; 75 | } 76 | return head; 77 | } 78 | void printList(linklist *head){ 79 | linklist *t; 80 | t=head; 81 | if (t==NULL) 82 | printf("这是一个空列表\n"); 83 | while (t!=NULL){ 84 | printf("%d ",t->data); 85 | t=t->next; 86 | } 87 | printf("\n"); 88 | } 89 | int main() 90 | { 91 | linklist *head; 92 | int n; 93 | printf("请输入一组递增数,以-1结束\n"); 94 | head=createList(); 95 | printList(head); 96 | printf("请输入要插入的数\n"); 97 | scanf("%d",&n); 98 | head=insertList(n,head); 99 | printList(head); 100 | 101 | system("pause"); 102 | return 0; 103 | } 104 | 105 | ``` 106 |
107 | 108 | ### Block中可以修改全局变量,全局静态变量,局部静态变量吗? 109 | 110 |
111 | 参考内容 112 | 113 | > 修饰符所有权一同捕获 114 | 115 | - 参考链接 [深入研究Block捕获外部变量和__block实现原理](https://www.jianshu.com/p/ee9756f3d5f6) 116 | - 全局变量和静态全局变量的值改变,以及它们被Block捕获进去,因为是全局的,作用域很广 117 | - 静态变量和自动变量,被Block从外面捕获进来,成为__main_block_impl_0这个结构体的成员变量 118 | - 自动变量是以值传递方式传递到Block的构造函数里面去的。Block只捕获Block中会用到的变量。由于只捕获了自动变量的值,并非内存地址,所以Block内部不能改变自动变量的值。 119 | - Block捕获的外部变量可以**改变值的是静态变量,静态全局变量,全局变量** 120 | 121 |
122 | 123 | ### NSString代码输出考察 会输出什么? 124 | 125 | ```objc 126 | 127 | @property (nonatomic, strong) NSString *strongString; 128 | @property (nonatomic, weak) NSString *weakString; 129 | 130 | strongString = [NSString stringWithFormat:@"%@",@"string1"]; 131 | weakString = strongString; 132 | strongString = nil; 133 | 134 | NSLog(@"%@", weakString); 135 | 136 | ``` 137 | 138 |
139 | 参考内容 140 | 141 | - NSString的问题,这个跟retainCount没什么太大的关系 142 | - **首先,stringWithFormat方法创建的字符串是autorelease的,本身就会延迟释放,直接跟log的话肯定不会输出null,如果你写个button做触发,放在方法外作log的话,才会打印出null** 143 | - 在64位环境下,苹果对NSString做了优化,细节不说,具体表现是,当非字面值常量的数字,英文字母字符串的长度小于等于 9 的时候会自动成为 NSTaggedPointerString 类型,如果有中文或其他特殊符号存在的话则会直接成为__NSCFString 类型。而NSTaggedPointerString是个常量释放不掉的. 144 | - 最后,如果是使用@""或者initWithString:@""的方式创建的字符串,会被转换成__NSCFConstantString,也是个常量,释放不掉不会输出null 145 | 146 |
147 | 148 | ### SDWebImage实现原理是什么? 它是如何解决tableView的复用时出现图片错乱问题的呢? 149 |
150 | 参考内容 151 | 152 | - 解决tableView复用错乱问题:每次都会调UIImageView+WebCache文件中的 [self sd_cancelCurrentImageLoad]; 153 | - [原理解释参考](https://www.jianshu.com/p/13c0cdc7987e) 154 | - SDWebImageDownloader 155 | - 图片的下载操作放在一个NSOperationQueue并发操作队列中,队列默认最大并发数是6 156 | - 每个图片对应一些回调(下载进度,完成回调等),回调信息会存在downloader的URLCallbacks(一个字典,key是url地址,value是图片下载回调数组)中,URLCallbacks可能被多个线程访问,所以downloader把下载任务放在一个barrierQueue中,并设置屏障保证同一时间只有一个线程访问URLCallbacks。,在创建回调URLCallbacks的block中创建了一个NSOperation并添加到NSOperationQueue中 157 | - 下载的核心是利用NSURLSession加载数据,每个图片的下载都有一个operation操作来完成,并将这些操作放到一个操作队列中,这样可以实现图片的并发下载。 158 | - 内存缓存的处理由NSCache对象实现,NSCache类似一个集合的容器,它存储key-value对,类似于nsdictionary类,我们通常使用缓存来临时存储短时间使用但创建昂贵的对象,重用这些对象可以优化新能,同时这些对象对于程序来说不是紧要的,如果内存紧张就会自动释放。 159 | - 先在内存中放置一份缓存,如果需要缓存到磁盘,将磁盘缓存操作作为一个task放到串行队列中处理,会先检查图片格式是jpeg还是png,将其转换为响应的图片数据,最后吧数据写入磁盘中(文件名是对key值做MD5后的串)。 160 | 161 |
162 | 163 | ## Swift问题 164 | 165 | ### struct 和 class 的区别? 166 | 167 |
168 | 参考内容 169 | 170 | - 类可以继承,结构体不可以 171 | 172 | - 可以让一个类的实例来反初始化,释放存储空间,结构体做不到 173 | 174 | - 类的对象是引用类型,而结构体是值类型。所以类的赋值是传递引用 ,结构体则是传值。 175 | 176 |
177 | 178 | 179 | ### class与staitc关键字的区别? 180 |
181 | 参考内容 182 | 183 | - static 可以在类、结构体、或者枚举中使用。而 class 只能在类中使用。 184 | - static 可以修饰存储属性,static 修饰的存储属性称为静态变量(常量)。而 class 不能修饰存储属性。 185 | - static 修饰的计算属性不能被重写。而 class 修饰的可以被重写。 186 | - static 修饰的静态方法不能被重写。而 class 修饰的类方法可以被重写。 187 | - class 修饰的计算属性被重写时,可以使用 static 让其变为静态属性。 188 | - class 修饰的类方法被重写时,可以使用 static 让方法变为静态方法。 189 | 190 |
191 | 192 | 193 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 194 | 195 |

196 | 197 |

198 | 199 | ## 链接 200 | 201 | - [面试题系列目录](../README.md) 202 | - **上一份**: [第六份:iOS基础问题系列2017年](06iOS基础问题系列2017年.md) 203 | - **下一份**: [第八份:字节跳动面试题2018年](08字节跳动面试题:2018年4月.md) 204 | -------------------------------------------------------------------------------- /iOSNote/Analyze/MJRefresh/MJRefresh.md: -------------------------------------------------------------------------------- 1 | 2 | ## MJRefresh 3 | 4 | - 下拉刷新原理 5 | - MJRefreshComponent 6 | - 关联下拉刷新控件到UIScrollView 7 | - 继承结构可以分为三层 8 | ![](http://images0.cnblogs.com/blog2015/497279/201506/132232456139177.png) 9 | 10 | ### 下拉刷新原理 11 | 12 | > 首先把刷新控件添加到scrollView的头部或者底部, 然后监控到scrollView的滚动进度(底部刷新控件还需要监控scrollView的内容的改变, 每次改变后再次将控件调整到scrollView的底部), 在scrollView的滚动过程中, 根据滚动的偏移量来计算出拖拽的进度, 然后计算出对应头部/底部的状态, 根据不同的状态 来相应的调整不同的UI或者动画 13 | 14 | - `contentInset` 15 | - 下拉的话,contentOffset就会越来越小,如果上滑,contentOffset就会增大 16 | - 而大部分的下拉刷新控件,都是将自己放在UIScrollView的上方,起始y设置成负数,所以平时不会显示出来,只有下拉的时候才会出现 17 | - 然后在loading的时候,临时把contentInset增大,相当于把UIScrollView往下挤,于是下拉刷新的控件就会显示出来,然后刷新完成之后,再把contentInset改回原来的值,实现回弹的效果 18 | 19 | 20 | ### MJRefreshComponent 21 | 22 | > MJRefreshComponent作为基类,定义了MJRefresh的整体流程,其它子类只是在此流程的基础上,通过覆写基类的方法,实现定制 23 | 24 | - 控件四种状态 25 | - 1, 正常状态, 即未开始和已经结束的状态. 26 | - 2, 拖拽状态, 这个时候拖拽的进度小于1, 如果继续拖拽直到拖拽进度等于(>)1的时候, 进入下一种状态. 27 | - 3, 松手即进入刷新的状态, 这个时候松开手才能进入下一个状态, 如果不松开手, 向反方向拖拽, 则拖拽进度会减小, 如果进度<1, 则会进入上一个状态 ... 28 | - 4, 加载动画状态, 这个时候进入加载状态, 知道收到 结束动画的指定, 才结束刷新动画进入正常状态等待 29 | 30 | - 处理事务 31 | * 声明控件的所有状态。 32 | * 声明控件的回调函数。 33 | * 添加监听。 34 | * 提供刷新,停止刷新接口。 35 | * 提供子类需要实现的方法。 36 | 37 | 38 | 39 | ### 关联下拉刷新控件到UIScrollView 40 | 41 | - 这是利用了UIScrollView+MJRefresh里的一个category,为UIScrollView增加了属性header和footer。这里用到了关联对象的技巧(AssociatedObject) 42 | 43 | - 把header添加到了UIScrollView的subviews里,并保留了一个引用。但是这个header的frame还没有确定,也没有任何行为 44 | 45 | ``` 46 | - (void)setHeader:(MJRefreshHeader *)header 47 | { 48 | if (header != self.header) { 49 | // 删除旧的,添加新的 50 | [self.header removeFromSuperview]; 51 | [self addSubview:header]; 52 | 53 | // 存储新的 54 | [self willChangeValueForKey:@"header"]; // KVO 55 | objc_setAssociatedObject(self, &MJRefreshHeaderKey, 56 | header, OBJC_ASSOCIATION_ASSIGN); 57 | [self didChangeValueForKey:@"header"]; // KVO 58 | } 59 | } 60 | 61 | ``` 62 | - 由于上面执行了addSubview,接下来就会进入header的生命周期方法willMoveToSuperview,这个方法是在公共的基类MJRefreshComponent里实现的。因为这是基础的行为,所以写在公共的基类里,所有的子类都能共享: 63 | 64 | ``` 65 | - (void)willMoveToSuperview:(UIView *)newSuperview 66 | { 67 | [super willMoveToSuperview:newSuperview]; 68 | 69 | // 如果不是UIScrollView,不做任何事情 70 | if (newSuperview && ![newSuperview isKindOfClass:[UIScrollView class]]) return; 71 | 72 | // 旧的父控件移除监听 73 | [self removeObservers]; 74 | 75 | if (newSuperview) { // 新的父控件 76 | // 设置宽度 77 | self.mj_w = newSuperview.mj_w; 78 | // 设置位置 79 | self.mj_x = 0; 80 | 81 | // 记录UIScrollView 82 | _scrollView = (UIScrollView *)newSuperview; 83 | // 设置永远支持垂直弹簧效果 84 | _scrollView.alwaysBounceVertical = YES; 85 | // 记录UIScrollView最开始的contentInset 86 | _scrollViewOriginalInset = self.scrollView.contentInset; 87 | 88 | // 添加监听 89 | [self addObservers]; 90 | } 91 | } 92 | 93 | ``` 94 | - 这里关键是设置了alwaysBounceVertical,这样才能确保UIScrollView可以下拉 95 | 置,以及其中每个subview的位置。并且侦听了UIScrollView的contentOffset和contentSize变化 96 | 97 | - 下拉会导致contentOffset变化,由于前面已经添加了KVO侦听,所以会执行scrollViewContentOffsetDidChange方法: 98 | 99 | ``` 100 | - (void)scrollViewContentOffsetDidChange:(NSDictionary *)change 101 | { 102 | [super scrollViewContentOffsetDidChange:change]; 103 | 104 | // 在刷新的refreshing状态 105 | if (self.state == MJRefreshStateRefreshing) { 106 | // sectionheader停留解决 107 | return; 108 | } 109 | 110 | // 跳转到下一个控制器时,contentInset可能会变 111 | _scrollViewOriginalInset = self.scrollView.contentInset; 112 | 113 | // 当前的contentOffset 114 | CGFloat offsetY = self.scrollView.mj_offsetY; 115 | // 头部控件刚好出现的offsetY 116 | CGFloat happenOffsetY = - self.scrollViewOriginalInset.top; 117 | 118 | // 如果是向上滚动到看不见头部控件,直接返回 119 | if (offsetY >= happenOffsetY) return; 120 | 121 | // 普通 和 即将刷新 的临界点 122 | CGFloat normal2pullingOffsetY = happenOffsetY - self.mj_h; 123 | CGFloat pullingPercent = (happenOffsetY - offsetY) / self.mj_h; 124 | if (self.scrollView.isDragging) { // 如果正在拖拽 125 | self.pullingPercent = pullingPercent; 126 | if (self.state == MJRefreshStateIdle && offsetY < normal2pullingOffsetY) { 127 | // 转为即将刷新状态 128 | self.state = MJRefreshStatePulling; 129 | } else if (self.state == MJRefreshStatePulling && offsetY >= normal2pullingOffsetY) { 130 | // 转为普通状态 131 | self.state = MJRefreshStateIdle; 132 | } 133 | } else if (self.state == MJRefreshStatePulling) {// 即将刷新 && 手松开 134 | // 开始刷新 135 | [self beginRefreshing]; 136 | } else if (pullingPercent < 1) { 137 | self.pullingPercent = pullingPercent; 138 | } 139 | } 140 | 141 | ``` 142 | 143 | - 这段代码比较长,主要是判断offset变化是否达到了临界值,以及当前的手势,切换header的state状态,然后根据state状态变化,驱动不同的行为: 144 | 145 | ``` 146 | - (void)setState:(MJRefreshState)state 147 | { 148 | MJRefreshCheckState 149 | // setState方法是第四个扩展点,这里的MJRefreshCheckState是个宏,也调用了父类的setState的方法。下拉的时候临时增大contentInset,令header保留在屏幕上,然后调用callback block;结束之后还原contentInset 150 | 151 | // 根据状态做事情 152 | if (state == MJRefreshStateIdle) { 153 | if (oldState != MJRefreshStateRefreshing) return; 154 | 155 | // 保存刷新时间 156 | [[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:self.lastUpdatedTimeKey]; 157 | [[NSUserDefaults standardUserDefaults] synchronize]; 158 | 159 | // 恢复inset和offset 160 | [UIView animateWithDuration:MJRefreshSlowAnimationDuration animations:^{ 161 | self.scrollView.mj_insetT -= self.mj_h; 162 | 163 | // 自动调整透明度 164 | if (self.isAutoChangeAlpha) self.alpha = 0.0; 165 | } completion:^(BOOL finished) { 166 | self.pullingPercent = 0.0; 167 | }]; 168 | } else if (state == MJRefreshStateRefreshing) { 169 | [UIView animateWithDuration:MJRefreshFastAnimationDuration animations:^{ 170 | // 增加滚动区域 171 | CGFloat top = self.scrollViewOriginalInset.top + self.mj_h; 172 | self.scrollView.mj_insetT = top; 173 | 174 | // 设置滚动位置 175 | self.scrollView.mj_offsetY = - top; 176 | } completion:^(BOOL finished) { 177 | [self executeRefreshingCallback]; 178 | }]; 179 | } 180 | } 181 | 182 | ``` -------------------------------------------------------------------------------- /interview-iOS/23抖音面试题2020年3月.md: -------------------------------------------------------------------------------- 1 | ## 2020抖音iOS面试经历(附参考答案) 2 | 3 | > 源地址 : https://www.jianshu.com/p/25ede6308676 4 | 5 | > 2020年3月6日 6 | 7 | ### 一面 8 | 9 | 1. UIButton不响应事件的原因 10 | 1. 按钮添加到了一个没有开启用户交互的父View上 11 | 2. 按钮自身被遮挡,点击的时候根本就没有点击到button 12 | 3. 按钮的frame超出了父视图的frame 13 | 1. error 为什么是** 14 | - 如果将指向对象的指针传递给函数,则函数只能修改指针所指向的内容。 15 | - 如果将指针传递给对象指针,则该函数可以修改指针以指向另一个对象。 16 | - 对于NSError,该函数可能希望创建一个新的NSError对象,并向您传递一个指向该NSError对象的指针。因此,您需要双间接,以便指针可以修改。 17 | - 总结:**想改变什么值就传入什么值得指针,很明显我们想改变的是NSError *error的值** 18 | 19 | - isEqualTo和hashValue的原理 20 |
21 | 参考内容 22 | - 判等流程 23 | 24 | - 实现一个新的 isEqualTo__ClassName__ 方法,进行实际意义上的值的比较。 25 | - 重载 isEqual: 方法进行类和对象的本体性检查,如果失败则回退到上面提到的值比较方法。 26 | - 重载 hash 方法,在下一个部分会详细介绍 27 | 28 | - 对于面向对象编程来说,对象相等性检查的主要用例,就是确定一个对象是不是一个集合的成员。为了加快这个过程,子类当中需要实现 hash 方法: 29 | 30 | - 对象相等具有 交换性 ([a isEqual:b] ⇒ [b isEqual:a]) 31 | - 如果两个对象相等,它们的 hash 值也一定是相等的 ([a isEqual:b] ⇒ [a hash] == [b hash]) 32 | - 反过来则不然,两个对象的散列值相等不一定意味着它们就是相等的 ([a hash] == [b hash] ¬⇒ [a isEqual:b]) 33 | 34 | ``` 35 | //NSObject 使用 isEqual: 这个方法来测试和其他对象的相等性。在它的基类实现中,相等性检查本质上就是对本体性的检查。 36 | //两个 NSObject 如果指向了同一个内存地址,那它们就被认为是相同的。 37 | @implementation NSObject (Approximate) 38 | - (BOOL)isEqual:(id)object { 39 | return self == object; 40 | } 41 | @end 42 | // 一个完整例子 43 | @interface Person 44 | @property NSString *name; 45 | @property NSDate *birthday; 46 | 47 | - (BOOL)isEqualToPerson:(Person *)person; 48 | @end 49 | 50 | @implementation Person 51 | 52 | - (BOOL)isEqualToPerson:(Person *)person { 53 | if (!person) { 54 | return NO; 55 | } 56 | 57 | BOOL haveEqualNames = (!self.name && !person.name) || [self.name isEqualToString:person.name]; 58 | BOOL haveEqualBirthdays = (!self.birthday && !person.birthday) || [self.birthday isEqualToDate:person.birthday]; 59 | 60 | return haveEqualNames && haveEqualBirthdays; 61 | } 62 | 63 | 64 | - (BOOL)isEqual:(id)object { 65 | if (self == object) { 66 | return YES; 67 | } 68 | 69 | if (![object isKindOfClass:[Person class]]) { 70 | return NO; 71 | } 72 | 73 | return [self isEqualToPerson:(Person *)object]; 74 | } 75 | 76 | //对于好奇心旺盛和不畏钻研的同学来说,Mike Ash 的这篇博文解释了如何通过移位操作和旋转可能重复的部分值来进一步优化 hash 函数的实现。 77 | - (NSUInteger)hash { 78 | return [self.name hash] ^ [self.birthday hash]; 79 | } 80 | 81 | ``` 82 |
83 | 84 | - 业务上的问题,为什么用highcharts这个库 85 | - 这个面试问题是根据你的项目经验提出的,所以具体问题具体分析。 86 | 87 | - webview的优化,webview为什么会加载白屏 88 |
89 | 参考内容 90 | 91 | - webview加载H5页面过程 92 | - 初始化 webview -> 请求页面 -> 下载数据 -> 解析HTML -> 请求 js/css 资源 -> dom 渲染 -> 解析 JS 执行 -> JS 请求数据 -> 解析渲染 -> 下载渲染图片 93 | - 优化 94 | - 前端优化 95 | - 合并资源,减少http请求数 96 | - 加快请求速度:预解析DNS,减少域名数,并行加载,CDN 分发 97 | - 客户端优化 98 | - 离线包方案:把一个个功能模块的所有相关页面和资源打包下发 99 | - 提前初始化 webview,提供一个全局的webview。添加webview 池重用池,可以用两个或多个 webview 重复使用 100 | - 预加载数据 101 | - 总结:缓存/预加载/并行,缓存一切网络请求,尽量在用户打开之前就加载好所有内容,能并行做的事不串行做。 102 | 103 |
104 | 105 | - 项目遇到哪些比较困难的问题 106 | - 曲线卡顿问题 107 | - 全局切换工厂问题 108 | 109 | - app 启动优化 110 |
111 | 参考内容 112 | 113 | - App总启动时间 = pre-main耗时 + main耗时,可以通过添加环境变量:DYLD_PRINT_STATISTICS 114 | 115 | - 启动流程 116 | - pre-main:系统dylib(动态链接库)和自身App可执行文件的加载 117 | - main: main方法执行之后到AppDelegate类中的didFinishLaunchingWithOptions方法执行结束前这段时间,主要是构建第一个界面,并完成渲染展示 118 | - pre-main优化 119 | - 减少类的数量,删除无用代码(未被调用的静态变量、类和方法,抽象重复代码 120 | +load方法中做的事情延迟到+initialize中,或者在+load中做的事情不宜花费过多时间 121 | - 减少不必要的framework,或者优化已有的framework 122 | - main阶段优化 123 | - didFinishLaunchingWithOptions,日志、统计,某个功能的预加载,第三方SDK初始化,可以采用懒加载,或者分阶段启动 124 | - 首页启动渲染的页面优化,对于viewDidLoad以及viewWillAppear方法中尽量去尝试少做,晚做,不做,或者采用异步的方式去做。不使用xib或者storyboard,直接使用代码 125 | 126 |
127 | 128 | - TableView卡顿 129 | - 要说明ios卡顿&掉帧的原理 130 | - 然后针对CPU和GPU渲染超时的解决方案 131 | 132 | - 查找两个view的共同父视图 133 |
134 | 参考内容 135 | 136 | > 注意这是要手敲代码的!!! 137 | 138 | > 思考:如果是只需要查找最近的公共父视图呢? 139 | 140 | ```objc 141 | 142 | - (void)findCommonSuperViews:(UIView *)view1 view2:(UIView *)view2 143 | { 144 | NSArray * superViews1 = [self findSuperViews:view1]; 145 | 146 | NSArray * superViews2 = [self findSuperViews:view2]; 147 | 148 | NSMutableArray * resultArray = [NSMutableArray array]; 149 | 150 | int i = 0; 151 | 152 | while (i < MIN(superViews1.count, superViews2.count)) { 153 | 154 | UIView *super1 = superViews1[superViews1.count - i - 1]; 155 | 156 | UIView *super2 = superViews2[superViews2.count - i - 1]; 157 | 158 | if (super1 == super2) { 159 | 160 | [resultArray addObject:super1]; 161 | 162 | i++; 163 | 164 | }else{ 165 | 166 | break; 167 | } 168 | } 169 | 170 | NSLog(@"resultArray:%@",resultArray); 171 | 172 | } 173 | - (NSArray *)findSuperViews:(UIView *)view 174 | { 175 | UIView * temp = view.superview; 176 | 177 | NSMutableArray * result = [NSMutableArray array]; 178 | 179 | while (temp) { 180 | 181 | [result addObject:temp]; 182 | 183 | temp = temp.superview; 184 | } 185 | 186 | return result; 187 | } 188 | 189 | ``` 190 |
191 | 192 | - 用过设计模式介绍下 193 |
194 | 参考内容 195 | 196 | > 六大原则:单一职责/开闭/接口隔离/依赖倒置/里氏替换/迪米特原则 197 | 198 | - 单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。 199 | - 优点: 1. 在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。2. 避免对资源的多重占用(比如写文件操作)。 200 | - 缺点: 没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。 201 | 202 | - 工厂模式:定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。 203 | - 优点: 1、一个调用者想创建一个对象,只要知道其名称就可以了。 2、扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以。 3、屏蔽产品的具体实现,调用者只关心产品的接口。 204 | - 缺点:每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。 205 | - 观察者模式:系统的KVO 206 | - 桥接模式:业务解耦 207 | - 适配器:一个类需要适应变化的需求,对象适配器和类适配器 208 | - 命令模式:YTKNetwork 采用此模式 209 |
210 | 211 | ## 链接 212 | 213 | - [面试题系列目录](../README.md) 214 | - **上一份**: [第22份:2020年3月份快手X3岗面试题](22快手X3岗面试题2020年3月.md) 215 | - **下一份**: [第24份:阿里iOS五轮面经2019年10月](24阿里iOS五轮面经2019年10月.md) 216 | 217 | 218 | 219 | ## 赞赏一下旺仔(收集整理不易,且赞且珍惜) 220 | 221 |

222 | 223 | 224 | 225 | 226 |

-------------------------------------------------------------------------------- /interview-iOS/25小米百度bigo滴滴快手等iOS面试题2020年上.md: -------------------------------------------------------------------------------- 1 | # 小米百度bigo 滴滴 快手等iOS 面试题2020年上 2 | 3 | > xiaozhuanlan.com/topic/7628534019 4 | > 第25份面试题 5 | 6 | #### 面试过程 7 | 8 | - 在疫情期间都是远程面试,下边先介绍一下疫情期间面试的一些公司的面试情况。同时拿到了其中几家的 offer。下边介绍的面试题只还原了其中印象比较深的部分,会存在不足的情况,并不代表面试的全部。 9 | 10 | ## 小米 11 | 12 | ### 一面 (已更新参考答案) 13 | 14 | * 介绍有哪些设计原则,并让比较详细的说了其中开闭原则在项目中的应用。 15 | * [六大设计原则](./23抖音面试题2020年3月.md) 16 | * 开闭原则在项目中的应用:一个软件实体应当对扩展开放,对修改关闭。即软件实体应尽量在不修改原有代码的情况下进行扩展。(分类) 17 | * 介绍设计模式,然后其中主要问了我抽象工厂和适配器两种模式。 18 | * [常见设计模式](./23抖音面试题2020年3月.md) 19 | * 介绍 runloop 相关的知识和在实际开发中的使用情况 20 | * [Runloop相关问题解答参考面试题第六份](./06iOS基础问题系列2017年.md) 21 | * [应用示例:卡顿监控](19新浪公司iOS面试题2019年6月.md),亦可以优化列表大图加载等场景。 22 | 23 | #### 要求详细的描述事件响应链 24 | 25 |
26 | 参考内容 27 | 28 | ``` 29 | //判断点击的位置是不是在视图内 30 | - (BOOL)pointInside:(CGPoint)point withEvent:(nullable UIEvent *)event; 31 | //返回点击的视图 32 | - (nullable UIView *)hitTest:(CGPoint)point withEvent:(nullable UIEvent *)event; 33 | 34 | ``` 35 | ##### 事件的传递 36 | 37 | - 加入到一个由UIApplication管理的事件队列中(队列的特点是FIFO,即先进先出,先产生的事件先处理才符合常理,所以把事件添加到队列中) 38 | 39 | - UIApplication会发送事件给应用程序的主窗口UIWindow。 40 | 41 | - 主窗口UIWindow会调用hitTest:withEvent:方法在视图(UIView)层次结构中找到一个最合适的UIView来处理触摸事件(也就是把事件传递给那个最适合的UIView) 42 | 43 | ##### 工作流程 44 | 45 | * 首先调用当前视图的pointInside:withEvent:方法判断触摸点是否在当前视图内 46 | 47 | * 若pointInside:withEvent:方法返回NO,说明触摸点不在当前视图内,则当前视图的hitTest:withEvent:返回nil 48 | 49 | * 若pointInside:withEvent:方法返回YES,说明触摸点在当前视图内,则遍历当前视图的所有子视图(subviews),调用子视图的hitTest:withEvent:方法重复前面的步骤,子视图的遍历顺序是从top到bottom,即从subviews数组的末尾向前遍历,直到有子视图的hitTest:withEvent:方法返回非空对象或者全部子视图遍历完毕。 50 | 51 | * 若第一次有子视图的hitTest:withEvent:方法返回非空对象,则当前视图的hitTest:withEvent:方法就返回此对象,处理结束 52 | 53 | * 若所有子视图的hitTest:withEvent:方法都返回nil,则当前视图的hitTest:withEvent:方法返回当前视图自身(self) 54 | 55 |
56 | 57 | ### 二面(已更新参考答案) 58 | 59 | > 介绍过往的项目经验,因为曾经的项目和所面试的部门岗位需求匹配度较高,所以这块的时间占比较多。 60 | 61 | * 【回文算法】判断一个字符串是不是对称的字符串,比如 abba 或者 aba 这样的就是对称的。 62 | 63 |
64 | 参考内容 65 | 66 | ``` 67 | bool check_string(char *s){ 68 | int len = strlen(s); 69 | int i = 0; 70 | int j = len-1; 71 | while(i < j){ 72 | if(s[i] != s[j])return false; 73 | } 74 | retrun true; 75 | } 76 | 77 | ``` 78 |
79 | 80 | * block 的实现原理 81 | 82 |
83 | 参考内容 84 | 85 | * block本质一个对象,主要分为 Imp 结构体 和 Desc 结构体 86 | * [block全部,静态,局部变量相关](./07深圳iOS面试分享2018年4月.md) 87 | 88 | ``` 89 | struct __main_block_impl_0 { 90 | struct __block_impl impl; 91 | struct __main_block_desc_0* Desc; 92 | __main_block_impl_0(void *fp, struct __main_block_desc_0 *desc, int flags=0) { 93 | impl.isa = &_NSConcreteStackBlock; 94 | impl.Flags = flags; 95 | impl.FuncPtr = fp; 96 | Desc = desc; 97 | } 98 | }; 99 | 100 | ``` 101 |
102 | * 比较详细的介绍 https 的过程。 103 | * 过往开发中做过哪些优化向的工作,问的也比较详细。 104 | * 如何检测项目中的卡顿问题(比如假死) 105 | * [应用示例:卡顿监控](19新浪公司iOS面试题2019年6月.md) 106 | * 比较详细的介绍消息转发流程和事件响应链 107 | * [消息转发流程](./08字节跳动面试题:2018年4月.md) 108 | * 事件响应链参考一面链接 109 | * GCD 的底层线程调度原理 110 | * 介绍 hash 算法的原理 111 | 112 | ### 三面 113 | 114 | * 一个二叉树逐层打印的算法题 115 | * [😁leetcode](https://leetcode-cn.com/problems/cong-shang-dao-xia-da-yin-er-cha-shu-lcof/) 116 | * 介绍自己的过往的项目经验,会结合项目问一些架构向的思考 117 | * 如果现在做一个新的网络层框架,有哪些需要考量的点 118 | * 参考知名网络框架,或者绘制UML图。 119 | 120 | ## 百度 121 | 122 | > 百度只有一面,因为面得是百度的商业化部门,对于细节的要求非常严格。个人感觉自己的表现确实不是很好。 123 | 124 | * 判断一个字符串是不是 ipv6 地址(要求尽全力的考虑所有异常的情况) 125 | * [同是百度面试题,类似参考](./11天猫蚂蚁金服百度面试题2018年4月.md) 126 | * PS:当时面试官明确告诉我,这个面试题做不好,面试是直接结束的。 127 | 128 | * 介绍界面卡顿的优化有哪些可以优化的点。 129 |
130 | 参考内容 131 | * 复用cell,缓存 Cell 高度,减少一些复杂的 layout,文字计算等,可进行缓存处理; 132 | * 异步渲染内容到图片&&图片解码放到子线程处理 133 |
134 | * 介绍 UIResponder 的继承链。然后说事件响应链。 135 | * 参考上文小米面试题解答。 136 | 137 | ## Bigo 138 | 139 | > 感觉面试的这些公司,Bigo 对于基础的考察最全面。 140 | 141 | ### 一面 142 | 143 | * (算法)找出一个页面中漏出部分面积最大的试图,重合的部分按照最上层的面积算漏出,会有时间复杂度的要求。 144 | * 简单地介绍的过往的项目经验 145 | * 控件的点击事件和添加在上边的手势谁先响应,并说明原因 146 | * 谈 CoreAnimation 和 CoreGraphic 的区别 147 | * 说 @synchronized 锁的实现原理,并说明其中可能存在的问题。同时介绍了 iOS 开发中常见的锁。 148 | * 介绍编译的过程和原理 149 | * 谈对于 bitcode 的理解和作用。 150 | * 详细的介绍了 Https 的过程。 151 | 152 | ### 二面 153 | 154 | * 介绍属性常用修饰符,介绍 assign 和 weak 之间的区别。这块会延伸到内存管理相关,比如引用计数的方式。 155 | * 聊对于 GCD 的理解,和 GCD 底层是如何进行线程调度的。聊 GCD 中常见方法的使用 (group ,信号量 156 | * ,barrier 等) 157 | * 详细的介绍了 KVC 和 KVO 的原理。 158 | * 介绍消息转发过程 159 | * 介绍对于 Runloop 并介绍知道的应用场景。再具体场景中会有追问。 160 | * 介绍项目优化的经验,这一块会聊的比较细。 161 | * 介绍对于静态库和动态库的理解。 162 | * 在 webview 使用过程中存在的问题和解决方案。 163 | 164 | ### 三面 165 | 166 | * 介绍了过往 RN 的使用经验和对于 Flutter 的理解。 167 | * 谈对于组件化的理解和市面上常见的组件化方案 168 | * 问了一些 APM 向上的问题。 169 | * 谈个人对于项目架构选择的理解。自己如何进行架构的选择(主要对于 MVVM,MVC等,后文有个人对于这一块的理解) 170 | * 谈个人规划 171 | 172 | ## 滴滴 173 | 174 | ### 一面 175 | 176 | > 滴滴的一面分为两部分。 177 | 178 | * 第一部分:过往项目经验,会对自己的过往项目经验,结合自己的描述,面试官问你介绍到的项目中涉及到问题,然后会据此引申出一些问题,这一部分占比比较大。 179 | * 第二部分是基础知识面 180 | * 谈属性修饰符,如果 assign 修饰对象可能存在的问题和原因。 181 | * 比较的深入的聊了内存管理的内容,包含引用计数和 weak 修饰的对象的内存管理的过程。问的会比较深入。 182 | * 讲 runloop 的过往使用经验。 183 | * 介绍自己比较熟悉的三方库的实现原理 184 | 185 | ## 二面 186 | 187 | * 对于锁的理解(自旋锁和互斥锁),以及 iOS 开发中常见的锁。同时要求介绍个人在开发过程中在哪些场景下用到过锁。 188 | * 在实际开发中遇到过哪些多线程问题以及如何进行解决的。 189 | * 为什么不能在异步线程中更新页面,介绍原因。 190 | * 对于内存泄漏的了解,以及介绍知道的解决方案。 191 | * 一些优化向上的问题,主要是根据自己介绍的优化进行较为深入的追问。 192 | * 一个坦克从一个空间的起点到终点,中间在某些位置上有阻隔的情况下,判断从起点到终点是否有可行路径的算法题。 193 | 194 | ### 三面 195 | 196 | * 比较详细的介绍之前的项目经验和主要负责的内容 197 | * 介绍过往项目中最有挑战的事情,并会据此深入的聊。 198 | * 介绍了一些架构向的理解 199 | * 谈个人规划 200 | 201 | ## 快手 202 | > 快手的一面是跨部门面试,二面是本部门面,所以一二面面试题会有一些重复,只写了一次。 203 | 204 | ### 一面 205 | 206 | * 介绍过往的项目经验 207 | * 两个不算难的算法题(具体的忘记了...) 208 | * 聊了 assign 修饰对象可能存在的问题 209 | * 聊过往项目中的优化经验 210 | * 介绍消息转发流程 211 | 212 | ### 二面 213 | 214 | * 比较详细的聊到的 block,深入的讲了其中的实现原理,并介绍不同变量的引用方式。 215 | * 介绍开发中常见的循环引用,并说明其中的原因和解决的方案和原理。 216 | * 介绍 Runloop 并讲应用场景。 217 | * 二叉树翻转 218 | 219 | ### 三面 220 | 221 | * 一道多线程实际场景下的问题,要求远程写出实现方案的代码 222 | * 聊对于 MVVM,MVC 和 MVP 的理解。 223 | * 介绍过往项目中 RN 的使用经验和遇到的问题。 224 | * 讲如何将一张内存极大的图片可以像地图一样的加载出来(只说实现思路) 225 | * 聊对于组件化的理解,对于市面上的组件化方案的理解,优劣分析等。 226 | 227 | 228 | ## 其他 229 | * 除了上边介绍的公司外,还面了平安,51 talk,58 同城,好未来,美篇。 230 | * 因为绝大部分面试内容和上边的基本上只是重复,只对差异性的面试题进行了总结。 231 | * 对图像编解码的了解 232 | * 在子线程中是如何进行内存管理的JSBridge 是如何实现的,以及和原生的调用关系。 233 | * 问到了一些 AFNetworking 和 SDWebImage 相关的实际开发中的问题。 234 | 235 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 236 | 237 |

238 | 239 |

240 | 241 | ## 链接 242 | 243 | - [面试题系列目录](../README.md) 244 | - **上一份**: [第24份:阿里iOS五轮面经2019年10月](./24阿里iOS五轮面经2019年10月.md) 245 | - **下一份**: [第26份:腾讯iOS六轮面试分享2020年](./26腾讯iOS六轮面试分享2020年.md) 246 | -------------------------------------------------------------------------------- /interview-iOS/06iOS基础问题系列2017年.md: -------------------------------------------------------------------------------- 1 | # 基础问题系列2017年 2 | 3 | > jianshu.com/p/1904f5ee7470 4 | 5 | - [什么是KVO和KVC?](#什么是kvo和kvc) 6 | - [KVO/KVC的优缺点?](#kvokvc的优缺点) 7 | - [Swfit和Objective-C的联系及Swift对比Objective-C有什么优势?](#swfit和objective-c的联系及swift对比objective-c有什么优势) 8 | - [举例说明Swfit里面有哪些是Objective-C中没有的?](#举例说明swfit里面有哪些是objective-c中没有的) 9 | - [如何对iOS设备进行性能测试?](#如何对ios设备进行性能测试) 10 | - [集成三方框架有哪些方法?](#集成三方框架有哪些方法) 11 | - [如何解决TableView卡的问题?](#如何解决tableview卡的问题) 12 | - [一个动画怎么实现?](#一个动画怎么实现) 13 | - [iOS中常用的数据存储方式有哪些?](#ios中常用的数据存储方式有哪些) 14 | - [runloop和线程有什么关系?](#runloop和线程有什么关系) 15 | - [runloop的mode作用是什么?](#runloop的mode作用是什么) 16 | - [你一般是如何调试Bug的?](#你一般是如何调试bug的) 17 | - [描述一个ViewController的生命周期](#描述一个viewcontroller的生命周期) 18 | 19 | ### 什么是KVO和KVC? 20 |
21 | 参考内容 22 | 23 | - KVC : 键值编码,是Key Value Coding 的简称,cocoa的标准组成部分,是一种可以直接通过字符串的名字(Key)来访问类属性的机制,而不是通过调用Setter方法、Getter方法进行访问 24 | - KVO:(Key Value Observer)键值观察者,是观察者设计模式的一种具体实现 25 | 26 |
27 | 28 | ### KVO/KVC的优缺点? 29 | 30 |
31 | 参考内容 32 | 33 | #### KVC: 34 | 35 | - 优点:没有property的变量(私有)也能通过KVC进行设置,或者简化代码(多级属性) 36 | - 缺点:如果key只写错,编写的时候不会报错,但是运行的时候会报错 37 | 38 | #### KVO优点: 39 | 40 | * 能够提供一种简单的方法实现两个对象的同步; 41 | * 能够对内部对象的状态改变作出响应,而且不需要改变内部对象的实现; 42 | * 能够提供被观察者属性的最新值和之前的值; 43 | * 使用key Path来观察属性,因此可以观察嵌套对象; 44 | * 完成了对观察对象的抽象,因为不需要额外的代码来允许观察者被观察。 45 | 46 | #### KVO缺点: 47 | 48 | * KVO只能检测类中的属性,并且属性名都是通过NSString来查找,编译器不会补全(编译时不会出现警告),容易写错; 49 | * 对属性重构,将导致观察代码不可用; 50 | * 复杂的 “if” 语句要求对象正在观察多个值,是因为所有的观察代码通过一个方法来指向; 51 | 52 |
53 | 54 | ### Swfit和Objective-C的联系及Swift对比Objective-C有什么优势? 55 |
56 | 参考内容 57 | 58 | > 联系: 59 | 60 | - Swift与Objective-C共用同一套运行时环境 61 | - 同一个工程,可以同时使用Swift和Objective-C 62 | - Objective-C出现过的绝大多数概念,比如引用记数、ARC、属性、协议、接口、初始化、扩展类、命名参数、匿名函数等,在Swift中继续有效(可能只是换了个术语) 63 | 64 | >优势 65 | 66 | - Swift容易阅读,语法和文件结构简易化。 67 | - Swift更易于维护,文件分离后结构更清晰。 68 | - Swift更加安全,它是类型安全的语言。 69 | - Swift代码更少,简洁的语法,可以省去大量冗余代码 70 | - Swift速度更快,运算性能更高。 71 | 72 |
73 | 74 | ### 举例说明Swfit里面有哪些是Objective-C中没有的? 75 | 76 |
77 | 参考内容 78 | 79 | 1).swift独有的范围运算符:a…b 表示 [a,b] 如3…5 就是范围取3,4,5 80 | 81 | 2).swift独有的元组类型 82 | 83 | var point = (x:15,y:20.2) 84 | 就是元组名是 point ,里面有两个元素x和y。 有点类似于结构体. 85 | 86 | 3).函数的默认参数值 87 | 88 | func addStudent (name:string,age:Int = 20) –>string{} 89 | 设置了默认的年龄为20 所以再调用时只需要写个名字 90 | addStudent("DragonLi") 91 | 要注意的是,使用了默认参数值, 系统会自动生成一个外部参数名。 92 | 想改名字也就要写外部参数名了 即 addStudent(“zss”,age:18) 93 | 94 | 4).swift中使用let定义常量,var定义变量 95 | 96 | 使用常量,更加安全,不能够被修改,在需要对对象进行修改的时候 只能用var修饰. 97 | 98 | 5).if let 、 guard let 的用法 99 | 100 | 缩减代码量,安全处理数据逻辑。 101 | 102 |
103 | 104 | ### 如何对iOS设备进行性能测试? 105 | 106 | - Instruments 是应用程序用来动态跟踪和分析 Mac OS X 和 iOS 代码的实用工具。这是一个灵活而强大的工具,它让你可以跟踪一个或多个进程,并检查收集的数据 107 | 108 | - Profile-> Instruments ->Time Profiler 109 | 110 | ### 集成三方框架有哪些方法? 111 | - 手动集成(不推荐) 112 | - cocoapods集成 113 | - carthage (iOS8+) 114 | - other(参考pb) 115 | 116 | ### 如何解决TableView卡的问题? 117 |
118 | 参考内容 119 | 120 | * 缓存行高 121 | * 尽量用轻量级的对象,比如用不到事件处理的地方,可以考虑使用 CALayer 取代 UIView 122 | * 不要频繁地调用 UIView 的相关属性,比如 frame、bounds、transform 等属性,尽量减少不必要的修改 123 | * 尽量提前计算好布局,在有需要时一次性调整对应的属性,不要多次修改属性 124 | * Autolayout 会比直接设置 frame 消耗更多的 CPU 资源 125 | * 图片的 size 最好刚好跟 UIImageView 的 size 保持一致 126 | * 控制一下线程的最大并发数量 127 | * 尽量把耗时的操作放到子线程 128 | * 文本处理(尺寸计算、绘制) 129 | * 图片处理(解码、绘制) 130 | 131 | * 尽量避免短时间内大量图片的显示,尽可能将多张图片合成一张进行显示 132 | * 尽量减少视图数量和层次 133 | * 减少透明的视图(alpha<1),不透明的就设置 opaque 为 YES 134 | * 尽量避免出现离屏渲染 135 | 136 |
137 | 138 | ### 一个动画怎么实现? 139 | > [CoreAnimation(核心动画)](https://github.com/DevDragonLi/Core-AnimationPerformanceOptimization) 140 | 141 | ### iOS中常用的数据存储方式有哪些? 142 | 143 | - [相似问题链接](./01一份"有点难"的iOS面试题MrPeak2016年.md#链接) 144 | 145 |
146 | 参考内容 147 | 148 | - 综合 149 | - 所有的本地持久化数据存储的本质都是写文件,而且只能存到沙盒中。 150 | - 沙盒机制是苹果的一项安全机制,本质就是系统给每个应用分配了一个文件夹来存储数据,而且每个应用只能访问分配给自己的那个文件夹,其他应用的文件夹是不能访问的。 151 | - 数据存储的核心都是写文件。主要有四种持久化方式:属性列表,对象序列化,SQLite 数据库, CoreData 152 | 153 | - 属性列表:应用于少量数据存储,比如登陆的用户信息,应用程序配置信息等。只有NSString ,NSArray,NSDictory,NSData,可以WriteToFile;存储的依旧是plist文件,plist文件可以存储的7种数据类型:array,dictory,string,bool,data,date,number。 154 | 155 | - 详细 156 | - 对象序列化:最终也是存为属性列表文件,如果程序中,需要存储的时候,直接存储对象比较方便,例如有一个设置类,我们可以把设置类的对象直接存储,就没必要再把里面的每一个属性单独存到文件中。对象序列化是将一个实现了NSCoding协议的对象,通过序列化(NSKeydArchiver)的形式,将对象中的属性抽取出来,转化成二进制流,也就是NSData,NSData可以选择write to file 或者存储到NSUserdefault中。 必须实现的两个方法 encodeWithCoder,initWithCoder。对象序列化的本质就是 对象NSData。 157 | 158 | - SQLite: 适合大量,重复,有规律的数据存储。而且频繁的读取,删除,过滤数据,这种适合使用数据库 (iOS 使用第三方FMDB) 159 | 160 | - CoreData: Sqlite叫做关系型数据库,CoreData 是一中OR-Mapping的思想 ,O代表对象Object,R代表relationship,Mapping代表映射,直译过来就是对象关系映射,其实就是把对象的属性和表中的字段自动映射,简化程序员的负担,以面向对象的方式操作数据库。ORMapping是一种思想,CoreData实现了这种思想,在Java中,hibernate 也是对ORMapping的一种实现,只是利用java实现的。 161 | - CoreData 本质还是数据库,只不过使用起来更加面向对象,不关注二维的表结构,而是只需要关注对象,纯面向对象的数据操作方式。我们直接使用数据库的时候,如果向数据库中插入数据,一般是把一个对象的属性和数据库中某个表的字段一一对应,然后把对象的属性存储到具体的表字段中.取一条数据的时候,把表中的一行数据取出,同样需要再封装到对象的属性中,这样的方式有点繁琐,不面向对象。CoreData解决的问题就是不需要这个中间的转换过程,看起来是直接把对象存储进去,并且取出来,不关心表的存在,实际内部帮你做好了映射关系。 162 | 163 |
164 | 165 | ### runloop和线程有什么关系? 166 |
167 | 参考内容 168 | 169 | - runloop和线程是一一对应关系 170 | - key:thread ,value :loop 171 | - 一般来讲,一个线程一次只能执行一个任务,执行完成后线程就会退出。 172 | - 保持程序的持续运行(ios程序为什么能一直活着不会死) 173 | - 处理app中的各种事件(比如触摸事件、定时器事件【NSTimer】、selector事件【选择器·performSelector···】) 174 | - 节省CPU资源,提高程序性能,有事情就做事情,没事情就休息 175 | 176 | - 重要性 177 | - 如果没有Runloop,那么程序一启动就会退出,什么事情都做不了。 178 | - 如果有了Runloop,那么相当于在内部有一个事件循环,能够保证程序的持续运行 179 | - main函数中的Runloop a 在UIApplication函数内部就启动了一个Runloop 该函数返回一个int类型的值 b 这个默认启动的Runloop是跟主线程相关联的 180 | 181 |
182 | 183 | ### runloop的mode作用是什么? 184 |
185 | 参考内容 186 | 187 | - 实际编码可用为3种(系统占用2种独有) 188 | - example ,定时器,等处理需要采取不同的 mode 189 | 190 |
191 | 192 | ### 你一般是如何调试Bug的? 193 |
194 | 参考内容 195 | 196 | - 在运行过程中,如果出现EXC_BAD_ACCESS 异常,往往提示的信息很少或者没有提示,启用NSZombieEnabled后在控制台能打印出更多的提示信息,便于debug,请注意,僵尸模式下的调试工作只能在模拟器中实现,我们无法在物理设备上完成这一诊断流程. 197 | - 异常断点,一般程序crash时Xcode一般会定位到main函数中,得不到详细的crash信息,打上异常断点后就极大可能定位到程序的crash处,利于debug。 198 | - 一般来说,在创建工程的时候,应该在Build Settings启用Analyze During 'Build',这样每次编译时都会自动静态分析。这样的话,写完一小段代码之后,就马上知道是否存在内存泄露或其他bug问题,并且可以修bugs。 199 | - 如果你想在运行的时候查看APP是否存在内存泄露,你可以使用Xcode上instruments工具上的Leaks模块进行内存分析。但是有些内存泄露是很难检查出来,有时只有通过手动覆盖dealloc方法,看它最终有没有调用。 200 |
201 | 202 | ### 描述一个ViewController的生命周期 203 |
204 | 参考内容 205 | 206 | * 当我们调用UIViewControlller的view时, 207 | * 系统首先判断当前的 UIViewControlller是否存在view,如果存在直接返回view, 208 | * 如果不存在的话,会调用loadview方法, 209 | * 然后判断loadview方法是否是自定义方法, 210 | * 如果是自定义方法,就执行自定义方法, 211 | * 如果不是自定义方法,判断当时视图控制器是否有xib、stroyboard。 212 | * 如果有xib、stroyboard 就加载xib、stroyboard。 213 | * 如果没有创建一个空白的view。 214 | * 调用viewDidLoad方法。 215 | * 最后返回view 216 | 217 |
218 | 219 | 220 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 221 | 222 |

223 | 224 |

225 | 226 | ## 链接 227 | 228 | - [面试题系列目录](../README.md) 229 | - **上一份**: [第五份:宝库iOS研发岗面试2017年:参考答案已更新完毕](05iOS宝库iOS开发笔试题2017年.md) 230 | - **下一份**: [第七份:深圳iOS面试分享2018年4月](07深圳iOS面试分享2018年4月.md) -------------------------------------------------------------------------------- /interview-iOS/04interview-iOS-4.md: -------------------------------------------------------------------------------- 1 | # interview-iOS - 4 2 | 3 | - [用户需要上传和下载一个重要的资料文件,应该如何判断用户本次是否上传成功和下载成功了?](#用户需要上传和下载一个重要的资料文件应该如何判断用户本次是否上传成功和下载成功了) 4 | - [ReactiveCocoa(RAC)如何防止UIButton短时间内多次重复点击,大概思路?](#reactivecocoarac如何防止uibutton短时间内多次重复点击大概思路) 5 | - [倒计时如何实现 ?](#倒计时如何实现) 6 | - [熟悉CocoaPods么?能大概讲一下工作原理么?](#熟悉cocoapods么能大概讲一下工作原理么) 7 | - [使用SDWebImage内存爆涨的问题](#使用sdwebimage内存爆涨的问题) 8 | - [isa指针的作用](#isa指针的作用) 9 | - [测试都有哪些方式?优缺点呢](#测试都有哪些方式优缺点呢) 10 | - [Xcode8开始后自动配置开发证书过程?](#xcode8开始后自动配置开发证书过程) 11 | - [项目中的图片上传功能如何实现,为什么使用队列上传,为什么不用异步上传](#项目中的图片上传功能如何实现为什么使用队列上传为什么不用异步上传) 12 | - [项目中你是怎么处理网络速度慢、中断抖动等网络请求中的问题?](#项目中你是怎么处理网络速度慢中断抖动等网络请求中的问题) 13 | 14 | ## 用户需要上传和下载一个重要的资料文件,应该如何判断用户本次是否上传成功和下载成功了? 15 |
16 | 参考内容 17 | 18 | - 用MD5验证文件的完整性!(仅仅通过代码来判断当前次的请求发送结束或者收到数据结束不可以的) 19 | - 当客户端上传一个文件的时候,在请求body里面添加该文件的MD5值来告诉服务器,服务器接受文件完毕以后通过校验收到的文件的MD5值与请求body里面的MD5值来最终确定本次上传是否成功 20 | - 当客户端下载一个文件的时候,在响应头里面收到了服务器附带的该文件的MD5值,文件下载结束以后,通过获取下载后文件的MD5值与本次请求服务器返回的响应头中的MD5值做一个比较,来最终判断本次下载是否成功 21 | - MD5,是一个将任意长度的数据字符串转化成短的固定长度的值的单向操作。任意两个字符串不应有相同的散列值 22 | - MD5校验可以应用在多个领域,比如说机密资料的检验,下载文件的检验,明文密码的加密等。MD5校验原理举例:如客户往我们数据中心同步一个文件,该文件使用MD5校验,那么客户在发送文件的同时会再发一个存有校验码的文件,我们拿到该文件后做MD5运算,得到的计算结果与客户发送的校验码相比较,如果一致则认为客户发送的文件没有出错,否则认为文件出错需要重新发送。 23 | 24 | 25 |
26 | 27 | ## ReactiveCocoa(RAC)如何防止UIButton短时间内多次重复点击,大概思路? 28 | 29 | > 需要有RAC使用经验才可问此题 30 | 31 |
32 | 参考内容 33 | 34 | - 建立一个`flag`或者使用 `filter` 35 | 36 | - 事件完成 flag重置,否则一直skip或者filter (某个RAC群友抛砖引玉) 37 | 38 |
39 | 40 | ## 倒计时如何实现 ? 41 |
42 | 参考内容 43 | 44 | - NSTimer ,精度不一定准确 45 | - GCD 46 | - DisplayLink 47 | - RAC 48 | 49 | 50 | ```objc 51 | -(void)startTime{ 52 | __block int timeout=30; //倒计时时间 53 | dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); 54 | dispatch_source_t _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0,queue); 55 | dispatch_source_set_timer(_timer,dispatch_walltime(NULL, 0),1.0*NSEC_PER_SEC, 0); //每秒执行 56 | dispatch_source_set_event_handler(_timer, ^{ 57 | if(timeout<=0){ //倒计时结束,关闭 58 | dispatch_source_cancel(_timer); 59 | dispatch_async(dispatch_get_main_queue(), ^{ 60 | //设置界面的按钮显示 根据自己需求设置 61 | [l_timeButton setTitle:@"发送验证码" forState:UIControlStateNormal]; 62 | l_timeButton.userInteractionEnabled = YES; 63 | }); 64 | }else{ 65 | // int minutes = timeout / 60; 66 | int seconds = timeout % 60; 67 | NSString *strTime = [NSString stringWithFormat:@"%.2d", seconds]; 68 | dispatch_async(dispatch_get_main_queue(), ^{ 69 | //设置界面的按钮显示 根据自己需求设置 70 | NSLog(@"____%@",strTime); 71 | [l_timeButton setTitle:[NSString stringWithFormat:@"%@秒后重新发送",strTime] forState:UIControlStateNormal]; 72 | l_timeButton.userInteractionEnabled = NO; 73 | 74 | }); 75 | timeout--; 76 | 77 | } 78 | }); 79 | dispatch_resume(_timer); 80 | 81 | } 82 | 83 | [[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]]subscribeNext:^(NSDate * date) { 84 | static NSInter = 60; 85 | 60 --; 86 | // 处理显示逻辑 87 | }]; 88 | 89 | ``` 90 | 91 |
92 | 93 | ## 熟悉CocoaPods么?能大概讲一下工作原理么? 94 | 95 |
96 | 参考内容 97 | 98 | > **Podfile.lock**:在pod install以后会生成一个Podfile.lock的文件,这个文件在多人协作开发的时候就不建议加入在.gitignore中,因为这个文件会锁定当前各依赖库的版本,就算之后再pod install也不会更改版本,不提交上去的话就可以防止第三方库升级后造成大家各自的第三方库版本不同 99 | 100 | ### **CocoaPods原理** 101 | 102 | > CocoaPods的原理是将所有的依赖库都放到另一个名为Pods的项目中,然后让主项目依赖Pods项目,这样,源码管理工作都从主项目移到了Pods项目中。Pods项目最终会编译成一个名为libPods.a的文件,主项目只需要依赖这个.a文件即可。 103 | 104 | * 运行pre-install hook 105 | 106 | * 生成Pod Project 107 | 108 | * 将该pod文件添加到工程中 109 | 110 | * 添加对应的framework、.a库、bundle等 111 | 112 | * 链接头文件,生成Target 113 | 114 | * 运行post-install hook 115 | 116 | * 生成podfile.lock ,之后生成文件副本mainfest.lock并将其放在Pod文件夹内。(如果出现 The sandbox is not sync with the podfile.lock这种错误,则表示manifest.lock和podfile.lock文件不一致),此时一般需要重新运行pod install命令。 117 | 118 | * 配置原有的project文件(add build phase) 119 | 120 | * 添加了 Embed Pods Frameworks 121 | 122 | * 添加了 Copy Pod Resources 其中,pre-install hook和post-install hook可以理解成回调函数,是在podfile里对于install之前或者之后(生成工程但是还没写入磁盘)可以执行的逻辑,逻辑为: 123 | 124 | * pre_install do |installer| # 做一些安装之前的hook end 125 | * post_install do |installer| # 做一些安装之后的hook end 126 | 127 |
128 | 129 | 130 | ## 使用SDWebImage内存爆涨的问题 131 | 132 |
133 | 参考内容 134 | 135 | - 产生的源码部分如下 136 | 137 | ```objc 138 | 139 | - (UIImage *)diskImageForKey:(NSString *)key { 140 | NSData *data = [self diskImageDataBySearchingAllPathsForKey:key]; 141 | if (data) { 142 | UIImage *image = [UIImage sd_imageWithData:data]; 143 | image = [self scaledImageForKey:key image:image]; 144 | if (self.shouldDecompressImages) { 145 | image = [UIImage decodedImageWithImage:image]; 146 | } 147 | return image; 148 | } 149 | else { 150 | return nil; 151 | } 152 | } 153 | 154 | ``` 155 | 156 | - 在某个VC出栈的时候清除比较合适,因为有可能用户不会再去显示那些图片,但是这些图片依旧占着内存 157 | 158 | - `[[SDImageCache sharedImageCache] setValue:nil forKey:@"memCache"];` 159 | 160 |
161 | 162 | 163 | ## isa指针的作用 164 |
165 | 参考内容 166 | 167 | - 对象的isa指向类,类的isa指向元类(meta class),元类isa指向元类的根类。isa帮助一个对象找到它的方法 168 | 169 | - 是一个Class 类型的指针. 每个实例对象有个isa的指针,他指向对象的类,而Class里也有个isa的指针, 指向meteClass(元类)。元类保存了类方法的列表。当类方法被调用时,先会从本身查找类方法的实现,如果没有,元类会向他父类查找该方法。同时注意的是:元类(meteClass)也是类,它也是对象。元类也有isa指针,它的isa指针最终指向的是一个根元类(root meteClass).根元类的isa指针指向本身,这样形成了一个封闭的内循环。 170 | 171 | 172 |
173 | 174 | ## 测试都有哪些方式?优缺点呢 175 | 176 |
177 | 参考内容 178 | 179 | - 联机调试 (一般而言适用于开发人员) 180 | - 之前需要插线 181 | - 后期版本可以无线调试! 182 | 183 | - 蒲公英等分发平台(就是需要提供参与app测试人员的设备UDID) 缺点:开发者需要将这些设备的UDID添加到开发者中心,每次有新的测试人员加入,需要重新生成profiles 184 | 185 | - TestFlight进行App Beta版测试 (apple 官方,iOS8及以上版本的iOS设备才能运行): 186 | - 优点: 无需UUID,**外部测试人员的上限是10000人**(2018年后又扩大了测试上限),只需要参与app测试人员提供一个邮箱 187 | - 188 | 189 |
190 | 191 | ## Xcode8开始后自动配置开发证书过程? 192 | 193 |
194 | 参考内容 195 | 196 | - Xcode会在本机钥匙串寻找team对应的开发证书,如果本地钥匙串存在该证书则加载使用 197 | - 不存在:则从开发者中心寻找本机对应的开发证书,如果开发者中心没有则自动生成一个并下载到钥匙串使用 198 | 199 |
200 | 201 | 202 | ## 项目中的图片上传功能如何实现,为什么使用队列上传,为什么不用异步上传 203 | 204 |
205 | 参考内容 206 | 207 | - image -> data 208 | - 如果是所有图片一起传,可以使用异步,但是如果是有按照顺序的需求,则需要按照用户的已知顺序传 209 | 210 |
211 | 212 | ## 项目中你是怎么处理网络速度慢、中断抖动等网络请求中的问题? 213 | 214 |
215 | 参考内容 216 | 217 | > dns 和 ping 探测当前网络情况 218 | 219 | - UI -> loading/Tips 220 | - netWorking ->cdn ,IP 直链 221 | 222 |
223 | 224 | 225 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 226 | 227 |

228 | 229 |

230 | 231 | ## 链接 232 | 233 | - [面试题系列目录](../README.md) 234 | - **上一份**: [interview-iOS-3](03interview-iOS-3.md) 235 | - **下一份**: [第五份:宝库iOS开发笔试题2017年:参考答案已更新完毕](05iOS宝库iOS开发笔试题2017年.md) 236 | -------------------------------------------------------------------------------- /interview-iOS/01一份"有点难"的iOS面试题MrPeak2016年.md: -------------------------------------------------------------------------------- 1 | 2 | # 一份"有点难"的iOS面试题:MrPeak 3 | 4 | > MrPeak : Facebook Software engineer 5 | 6 | > 题目出处: zhuanlan.zhihu.com/p/22834934 7 | 8 | - [谈下iOS开发中知道的哪些锁?](#谈下ios开发中知道的哪些锁) 9 | - [iOS下如何实现指定线程数目的线程池?](#ios下如何实现指定线程数目的线程池) 10 | - [如何用HTTP实现长连接?](#如何用http实现长连接) 11 | - [HTTP的post和get啥区别](#http的post和get啥区别) 12 | - [使用atomic一定是线程安全的吗?](#使用atomic一定是线程安全的吗) 13 | - [数据库建表的时候索引有什么用?](#数据库建表的时候索引有什么用) 14 | - [介绍下iOS设备获取唯一设备号的历史变迁](#介绍下ios设备获取唯一设备号的历史变迁) 15 | - [如何使用runtime 16 | hook一个class的某个方法,又如何hook某个instance的方法?](#如何使用runtime-hook一个class的某个方法又如何hook某个instance的方法) 17 | - [聊下HTTP的POST的body体使用form-urlencoded和multipart/form-data的区别。](#聊下http的post的body体使用form-urlencoded和multipartform-data的区别) 18 | - [通过\[UIImage 19 | imageNamed:\]生成的对象什么时候被释放?](#通过uiimage-imagenamed生成的对象什么时候被释放) 20 | - [applicationWillEnterForeground和applicationDidBecomeActive都会在哪些场景下被调用?举例越多越好。](#applicationwillenterforeground和applicationdidbecomeactive都会在哪些场景下被调用举例越多越好) 21 | - [如何终止正在运行的工作线程?](#如何终止正在运行的工作线程) 22 | - [iOS下所有的本地持久化方案?](#ios下所有的本地持久化方案) 23 | 24 | 25 | ## 谈下iOS开发中知道的哪些锁? 26 | 27 | > 一般开发中你最常用哪个? 28 | 29 | > 哪个性能最差?了解SD和AFN使用哪些吗? 30 | 31 |
32 | 参考内容 33 | 34 | > 我们在使用多线程的时候多个线程可能会访问同一块资源,这样就很容易引发数据错乱和数据安全等问题,这时候就需要我们保证每次只有一个线程访问这一块资源,锁 应运而生 35 | 36 | - `@synchronized` 性能最差,SD和AFN等框架内部有使用这个. 37 | 38 | - NSRecursiveLock 和 NSLock :建议使用前者,避免循环调用出现**死锁** 39 | 40 | - OSSpinLock 自旋锁,存在的问题是:优先级反转问题,破坏了spinlock 41 | 42 | - dispatch_semaphore 信号量 : 保持线程同步为线程加锁 43 | 44 | ```objc 45 | dispatch_semaphore_t signal = dispatch_semaphore_create(1); 46 | 47 | dispatch_time_t overTime = dispatch_time(DISPATCH_TIME_NOW, 1.0f * NSEC_PER_SEC); 48 | //Thread1 49 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 50 | NSLog(@"Thread1 waiting"); 51 | dispatch_semaphore_wait(signal, overTime); //signal 值 -1 52 | NSLog(@"Thread1"); 53 | dispatch_semaphore_signal(signal); //signal 值 +1 54 | NSLog(@"Thread1 send signal"); 55 | }); 56 | 57 | //Thread2 58 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 59 | NSLog(@"Thread2 waiting"); 60 | dispatch_semaphore_wait(signal, overTime); 61 | NSLog(@"Thread2"); 62 | dispatch_semaphore_signal(signal); 63 | NSLog(@"Thread2 send signal"); 64 | }); 65 | dispatch_semaphore_create(1): 若传入为0(over time 失效) 则阻塞线程并等待timeout,时间到后会执行其后的语句, 66 | 67 | dispatch_semaphore_wait(signal, overTime):可以理解为 lock,会使得 signal 值 -1 68 | 69 | dispatch_semaphore_signal(signal):可以理解为 unlock,会使得 signal 值 +1 70 | 71 | ``` 72 | 73 |
74 | 75 | 76 | ## iOS下如何实现指定线程数目的线程池? 77 | 78 |
79 | 参考内容 80 | 81 | ### 回答思路 82 | 83 | - 循环通过pthread_create创建线程,创建s_tf thread对象做为线程句,加入线程数组,s_tftask_content->methord初始化为空函数 84 | 85 | - 创建任务执行函数,执行完通过task初始化函数后,在执行函数中通过pthread_cond_wait信号将当前创建的线程挂起 86 | 87 | - 创建完之后,程序中将会有n个挂起状态的线程,当需要执行新的task的时候查找,我们就可以根据不同的task标志在k_threads中查询出空闲线程,并创建新的s_tftask_content加入s_tfthread的任务列表,通过pthread_cond_signal重新唤醒该线程继续执行任务 88 | 89 |
90 | 91 | 92 | ### 参考样例实现代码(基于dispatch_semaphore) 93 | 94 |
95 | 参考内容 96 | 97 | ``` 98 | dispatch_queue_t workConcurrentQueue = dispatch_queue_create("example.code", DISPATCH_QUEUE_CONCURRENT); 99 | dispatch_queue_t serialQueue = dispatch_queue_create("example.code.task",DISPATCH_QUEUE_SERIAL); 100 | dispatch_semaphore_t semaphore = dispatch_semaphore_create(3); 101 | for (NSInteger i = 0; i < 10; i++) { 102 | dispatch_async(serialQueue, ^{ 103 | dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 104 | dispatch_async(workConcurrentQueue, ^{ 105 | NSLog(@"thread-info:%@开始执行任务%d",[NSThread currentThread],(int)i); 106 | sleep(1); 107 | NSLog(@"thread-info:%@结束执行任务%d",[NSThread currentThread],(int)i); 108 | dispatch_semaphore_signal(semaphore);}); 109 | }); 110 | } 111 | NSLog(@"主线程...!"); 112 | 113 | ``` 114 | 115 |
116 | 117 | 118 | ## 如何用HTTP实现长连接? 119 |
120 | 参考内容 121 | 122 | - HTTP是无状态的,要维持一个长连接可以用**心跳包**方式 123 | - 丢包,沾包 ,实际上http连接进行轮询.(滴滴打车较早期版本采用的方式,耗费流量) 124 | - 定时轮询会存在延迟 用户体验就不好 125 | 126 |
127 | 128 | ## HTTP的post和get啥区别 129 |
130 | 参考内容 131 | 132 | - 从语义角度分析 133 | 134 | - 安全性:不会引发 server 端的改变 135 | - 幂等:同一个方法请求多次结果相同 136 | - 可缓存(Get) 137 | 138 |
139 | 140 | 141 | ## 使用atomic一定是线程安全的吗? 142 |
143 | 参考内容 144 | 145 | - 只是针对取值和赋值线程安全 146 | - 数组的初始化,赋值,取值安全 147 | - 数组的添加数据元素并非线程安全 148 | - BOOL 类型 修饰符不受到atomic或者noatomic影响 149 | 150 |
151 | 152 | 153 | ## 数据库建表的时候索引有什么用? 154 |
155 | 参考内容 156 | 157 | - 创建索引可以大大提高系统的性能,加快数据的检索速度,加速表和表之间的连接,保证数据库表中每一行数据的唯一性 158 | - 但是有些列不应该创建索引,需要综合考虑. 159 | 160 |
161 | 162 | ## 介绍下iOS设备获取唯一设备号的历史变迁 163 | 164 |
165 | 参考内容 166 | 167 | #### iOS中获取设备唯一标示符的方法一直随版本的更新而变化 168 | - iOS 2.0版本以后UIDevice提供一个获取设备唯一标识符的方法uniqueIdentifier 169 | - iOS6是用WiFi的mac地址 170 | - iOS7-iOS10.2通过KeyChain来保存获取到的UDID,因为APP删了再装回来,也可以从KeyChain中读取回来 (广告收益计算等) 171 | - [10.3后用户删掉一个 App,之后再重装就只能手动登录一次](http://mt.sohu.com/20170310/n482880968.shtml) 172 | 173 |
174 | 175 | 176 | ## 如何使用runtime hook一个class的某个方法,又如何hook某个instance的方法? 177 | 178 |
179 | 参考内容 180 | 181 | > 这个问题,首先要考虑怎么回答才能不被套路 182 | 183 | - 考虑 hook是否有公开头文件的类,有的话写一个Utility函数,再使用category, 184 | - 没有的话就建一个类作为新函数载体,然后先为被hook的类增加函数,再替换。 185 | - 如何hook某个instance的方法,应该可以定义一个函数指针变量(IMP),hook时将要调用的地址赋给这个变量,调用时把这个变量当作函数来用 (参考:RAC框架hook) 186 | 187 |
188 | 189 | 190 | ## 聊下HTTP的POST的body体使用form-urlencoded和multipart/form-data的区别。 191 | 192 |
193 | 参考内容 194 | 195 | - multipart/form-data是当上传文件或者二进制数据和非ASCII数据使用 ,AFN请求如何设置? 196 | 197 | ```objc 198 | [requestSerializer setValue:@"multipart/form-data" forHTTPHeaderField:@"content-type"]; 199 | ``` 200 | - form-urlencoded是默认的mime内容编码类型,是通用的,但是它在传输比较大的二进制或者文本数据时效率极低 201 | - 交互:GET,POST,PUT,PATCH,DELETE等 202 | - AFN的PATCH貌似数组存在问题. 203 | 204 |
205 | 206 | 207 | 208 | ## 通过[UIImage imageNamed:]生成的对象什么时候被释放? 209 | 210 |
211 | 参考内容 212 | 213 | - 建议针对小图标/场景出现较多图片(此类方式加载,会缓存到内存) 214 | - `@autoreleasepool` 如果没有使用局部释放池,**并且在主线程,则是当前主线程Runloop一次循环结束前释放**。 215 | - imageWithContentsOfFile : 加载适用于大图片,不常用的图片,一般无引用时候,会释放 216 | 217 |
218 | 219 | 220 | ## applicationWillEnterForeground和applicationDidBecomeActive都会在哪些场景下被调用?举例越多越好。 221 | 222 |
223 | 参考内容 224 | 225 | - applicationDidBecomeActive 226 | - APP首次启动用户授权后,会调用此函数 227 | - APP处于激活态 228 | - applicationWillEnterForeground:从后台进入前台 229 | 230 | - 场景 231 | - 推送、做支付 232 | - 跳转app 233 | - 后台杀进程的时候、IM、第三方授权分享登录回调情况下等 234 | 235 |
236 | 237 | 238 | 239 | ## 如何终止正在运行的工作线程? 240 |
241 | 参考内容 242 | 243 | - 线程中调用exit、pthread_exit、pthread_kill、pthread_cancel 244 | - NSOperation ,接口设计的cancle **实际上只能取消还未运行的,已经运行的无法取消**. 245 | 246 |
247 | 248 | ## iOS下所有的本地持久化方案? 249 | > [本系列面试题相似问题:iOS中常用的数据存储方式有哪些](./06iOS基础问题系列2017年.md) 250 | 251 |
252 | 参考内容 253 | 254 | - 沙盒 255 | - plist文件(属性列表) 256 | - preference(偏好设置) 257 | 258 | - NSKeyedArchiver(归档) 259 | 260 | - SQLite 3 261 | 262 | - CoreData 263 | - Realm 264 | 265 |
266 | 267 | 268 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 269 | 270 |

271 | 272 |

273 | 274 | ## 链接 275 | 276 | - [面试题系列目录](../README.md) 277 | - **下一份**: [interview-iOS-2](02interview-iOS-2.md) 278 | 279 | 280 | -------------------------------------------------------------------------------- /interview-iOS/02interview-iOS-2.md: -------------------------------------------------------------------------------- 1 | ## interview-iOS -2 2 | 3 | - [weak修饰的释放则自动被置为nil的实现原理](#weak修饰的释放则自动被置为nil的实现原理) 4 | - [HTTPS的加密原理](#https的加密原理) 5 | - [网络通讯中加密方式有哪些,各自的原理?](#网络通讯中加密方式有哪些各自的原理) 6 | - [开发中iOS缓存的理解](#开发中ios缓存的理解) 7 | - [你认为开发中那些导致crash?](#你认为开发中那些导致crash) 8 | - [应用逻辑的Bug](#应用逻辑的bug) 9 | - [违反iOS系统规则产生crash的三种类型](#违反ios系统规则产生crash的三种类型) 10 | - [SDWebImage](#sdwebimage) 11 | - [加载图片的流程](#加载图片的流程) 12 | - [SDImageCache是怎么做数据管理的?](#sdimagecache是怎么做数据管理的) 13 | - [内部做Decoder的原因 14 | (典型的空间换时间)](#内部做decoder的原因-典型的空间换时间) 15 | - [Crash的收集和定位bug的方式](#crash的收集和定位bug的方式) 16 | 17 | ## weak修饰的释放则自动被置为nil的实现原理 18 | 19 |
20 | 参考内容 21 | 22 | - Runtime维护着一个Weak表,用于存储指向某个对象的所有Weak指针 23 | - Weak表是Hash表,Key是所指对象的地址,Value是Weak指针地址的数组 24 | - 在对象被回收的时候,经过层层调用,会最终触发下面的方法将所有Weak指针的值设为nil。 25 | - runtime源码,objc-weak.m 的 arr_clear_deallocating 函数 26 | - weak指针的使用涉及到Hash表的增删改查,**有一定的性能开销**. 27 | 28 |
29 | 30 | ## HTTPS的加密原理 31 | 32 |
33 | 参考内容 34 | 35 | - 服务器端用非对称加密(RSA)生成公钥和私钥 36 | - 然后把公钥发给客户端, 服务器则保存私钥 37 | - 客户端拿到公钥后, 会生成一个密钥, 这个密钥就是将来客户端和服务器用来通信的钥匙 38 | - 然后客户端用公钥对密钥进行加密, 再发给服务器 39 | - 服务器拿到客户端发来的加密后的密钥后, 再使用私钥解密密钥, 到此双方都获得通信的钥匙 40 | 41 |
42 | 43 | ## 网络通讯中加密方式有哪些,各自的原理? 44 |
45 | 参考内容 46 | 47 | - md5(哈希算法):把任意长度的字符串加密成一个128bit的大整数,并且是不可逆的 (已不再安全) 48 | - RSA(非对称算法加密):产生一对非对称的公钥和私钥,公钥加密,私钥解密。私钥加密,公钥解密 49 | - AES(对称加密):加密和解密的密钥是同一个 50 | - base64(现代密码学的基础):原本8 bit一组的数据改为6bit一组,不足的地方补0,每两个0用一个 = 表示 51 | 52 |
53 | 54 | ## 开发中iOS缓存的理解 55 | 56 |
57 | 参考内容 58 | 59 | > 一般`缓存` 针对展示类的UI层数据比较多.比如可举例个人资料界面. 60 | 61 | - 网络优先:开始总是从网络获取,如果获取失败,从本地获取(旧数据)。 62 | - 本地优先:在一段时间内从本地获取,当超过这个时间,然后重新请求网络数据(展示同时覆盖旧数据)。 63 | - 混合(智能):打开程序先从本地获取展示,然后请求数据,请求完成后刷新界面(一般而言)。 64 | 65 |
66 | 67 | ## 你认为开发中那些导致crash? 68 | 69 |
70 | 参考内容 71 | 72 | > 当iOS设备上的App应用闪退时,操作系统会生成一个crash日志,保存在设备上。crash日志上有很多有用的信息,比如每个正在执行线程的完整堆栈跟踪信息和内存映像,这样就能够通过解析这些信息进而定位crash发生时的代码逻辑,从而找到App闪退的原因。 73 | 74 | > 通常来说,crash产生来源于两种问题:违反iOS系统规则导致的crash和App代码逻辑BUG导致的crash 75 | 76 | ### 应用逻辑的Bug 77 | 78 | - SEGV:(Segmentation Violation,段违例),无效内存地址,比如空指针,未初始化指针,栈溢出等; 79 | - SIGABRT:收到Abort信号,可能自身调用abort()或者收到外部发送过来的信号; 80 | - SIGBUS:总线错误。与SIGSEGV不同的是,SIGSEGV访问的是无效地址(比如虚存映射不到物理内存),而SIGBUS访问的是有效地址,但总线访问异常(比如地址对齐问题); 81 | - SIGILL:尝试执行非法的指令,可能不被识别或者没有权限; 82 | - SIGFPE:Floating Point Error,数学计算相关问题(可能不限于浮点计算),比如除零操作; 83 | - SIGPIPE:管道另一端没有进程接手数据; 84 | 常见的崩溃原因基本都是代码逻辑问题或资源问题,比如数组越界,访问野指针或者资源不存在,或资源大小写错误等 85 | 86 | ### 违反iOS系统规则产生crash的三种类型 87 | - 内存报警闪退 88 | - 当iOS检测到内存过低时,它的VM系统会发出低内存警告通知,尝试回收一些内存;如果情况没有得到足够的改善,iOS会终止后台应用以回收更多内存;最后,如果内存还是不足,那么正在运行的应用可能会被终止掉。在Debug模式下,可以主动将客户端执行的动作逻辑写入一个log文件中,这样程序童鞋可以将内存预警的逻辑写入该log文件,当发生如下截图中的内存报警时,就是提醒当前客户端性能内存吃紧,可以通过Instruments工具中的Allocations 和 Leaks模块库来发现内存分配问题和内存泄漏问题。 89 | 90 | - 响应超时 91 | - 当应用程序对一些特定的事件(比如启动、挂起、恢复、结束)响应不及时,苹果的Watchdog机制会把应用程序干掉,并生成一份相应的crash日志。 92 | 93 | - 用户强制退出 94 | - 一看到“用户强制退出”,首先可能想到的双击Home键,然后关闭应用程序。不过这种场景一般是不会产生crash日志的,因为双击Home键后,所有的应用程序都处于后台状态,而iOS随时都有可能关闭后台进程,当应用阻塞界面并停止响应时这种场景才会产生crash日志。这里指的“用户强制退出”场景,是稍微比较复杂点的操作:先按住电源键,直到出现“滑动关机”的界面时,再按住Home键,这时候当前应用程序会被终止掉,并且产生一份相应事件的crash日志。 95 | 96 | 97 |
98 | 99 | ## SDWebImage 100 | 101 | > [第四份面试题相关点:使用SDWebImage内存爆涨的问题](04interview-iOS-4.md) 102 | 103 | > 加载图片的流程 104 | 105 | > Cache是怎么做数据管理的? 106 | 107 | > 内部做Decoder的原因 108 | 109 |
110 | 参考内容 111 | 112 | ### 加载图片的流程 113 | 114 | 1.入口 setImageWithURL:placeholderImage:options: 会先把 placeholderImage 显示,然后 SDWebImageManager 根据 URL 开始处理图片。 115 | 116 | 2.进入 SDWebImageManager-downloadWithURL:delegate:options:userInfo:,交给 SDImageCache 从缓存查找图片是否已经下载 queryDiskCacheForKey:delegate:userInfo:. 117 | 118 | 3.先从内存图片缓存查找是否有图片,如果内存中已经有图片缓存,SDImageCacheDelegate 回调 imageCache:didFindImage:forKey:userInfo: 到 SDWebImageManager。 119 | 120 | 4.SDWebImageManagerDelegate 回调 webImageManager:didFinishWithImage: 到 UIImageView+WebCache 等前端展示图片。 121 | 122 | 5.如果内存缓存中没有,生成 NSInvocationOperation 添加到队列开始从硬盘查找图片是否已经缓存。 123 | 124 | 6.根据 URLKey 在硬盘缓存目录下尝试读取图片文件。这一步是在 NSOperation 进行的操作,所以回主线程进行结果回调 notifyDelegate:。 125 | 126 | 7.如果上一操作从硬盘读取到了图片,将图片添加到内存缓存中(如果空闲内存过小,会先清空内存缓存)。SDImageCacheDelegate 回调 imageCache:didFindImage:forKey:userInfo:。进而回调展示图片。 127 | 128 | 8.如果从硬盘缓存目录读取不到图片,说明所有缓存都不存在该图片,需要下载图片,回调 imageCache:didNotFindImageForKey:userInfo:。 129 | 130 | 9.共享或重新生成一个下载器 SDWebImageDownloader 开始下载图片。 131 | 132 | 10.图片下载由 NSURLConnection 来做,实现相关 delegate 来判断图片下载中、下载完成和下载失败。 133 | 134 | 11.connection:didReceiveData: 中利用 ImageIO 做了按图片下载进度加载效果。 135 | 136 | 12.connectionDidFinishLoading: 数据下载完成后交给 SDWebImageDecoder 做图片解码处理。 137 | 138 | 13.图片解码处理在一个 NSOperationQueue 完成,不会拖慢主线程 UI。如果有需要对下载的图片进行二次处理,最好也在这里完成,效率会好很多。 139 | 140 | 14.在主线程 notifyDelegateOnMainThreadWithInfo: 宣告解码完成,imageDecoder:didFinishDecodingImage:userInfo: 回调给 SDWebImageDownloader。 141 | 142 | 15.imageDownloader:didFinishWithImage: 回调给 SDWebImageManager 告知图片下载完成。 143 | 144 | 16.通知所有的 downloadDelegates 下载完成,回调给需要的地方展示图片。 145 | 146 | 17.将图片保存到 SDImageCache 中,内存缓存和硬盘缓存同时保存。写文件到硬盘也在以单独 NSInvocationOperation 完成,避免拖慢主线程。 147 | 148 | 18.SDImageCache 在初始化的时候会注册一些消息通知,在内存警告或退到后台的时候清理内存图片缓存,应用结束的时候清理过期图片。 149 | 150 | 19.SDWI 也提供了 UIButton+WebCache 和 MKAnnotationView+WebCache,方便使用。 151 | 152 | 20.SDWebImagePrefetcher 可以预先下载图片,方便后续使用。 153 | 154 | 155 | ### SDImageCache是怎么做数据管理的? 156 | 157 | SDImageCache分两个部分,一个是内存层面的,一个是硬盘层面的。内存层面的相当是个缓存器,以Key-Value的形式存储图片。当内存不够的时候会清除所有缓存图片。用搜索文件系统的方式做管理,文件替换方式是以时间为单位,剔除时间大于一周的图片文件。当SDWebImageManager向SDImageCache要资源时,先搜索内存层面的数据,如果有直接返回,没有的话去访问磁盘,将图片从磁盘读取出来,然后做Decoder,将图片对象放到内存层面做备份,再返回调用层。 158 | 159 | 160 | ### 内部做Decoder的原因 (典型的空间换时间) 161 | - 由于UIImage的imageWithData函数是每次画图的时候才将Data解压成ARGB的图像,所以在每次绘图的时候,**会有一个解压操作,这样效率很低,但是只有瞬时的内存需求**。为了提高效率通过SDWebImageDecoder将包装在Data下的资源解压,然后画在另外一张图片上,这样这张新图片就不再需要重复解压了 162 | 163 |
164 | 165 | ## crash的收集和定位bug的方式 166 |
167 | 参考内容 168 | 169 | - iTunes Connect(Manage Your Applications - View Details - Crash Reports),但是前提用户设置->隐私->诊断与用量->诊断与用量数据开启.一般不推荐 170 | 171 | - 自己实现应用内崩溃收集,并上传服务器.(收集异常,存储到本地,下次用户打开程序时上传给我们) 172 | - 在程序启动时加上一个异常捕获监听,用来处理程序崩溃时的回调动作UncaughtExceptionHandler是一个函数指针,该函数需要我们实现,可以取自己想要的名字。当程序发生异常崩溃时,该函数会得到调用,这跟C,C++中的回调函数的概念是一样的 173 | 174 | ``` 175 | NSSetUncaughtExceptionHandler (&UncaughtExceptionHandler)。 程序启动代理方法 176 | //:collection crash info by DragonLi 177 | void UncaughtExceptionHandler(NSException *exception) { 178 | NSArray *callStack = [exception callStackSymbols]; 179 | NSString *reason = [exception reason]; 180 | NSString *name = [exception name]; 181 | 182 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 183 | [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"]; 184 | NSString * dateStr = [formatter stringFromDate:[NSDate date]]; 185 | 186 | NSString * iOS_Version = [[UIDevice currentDevice] systemVersion]; 187 | NSString * PhoneSize = NSStringFromCGSize([[UIScreen mainScreen] bounds].size); 188 | NSString * App_Version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleShortVersionString"]; 189 | NSString * iPhoneType = @"当前设备名字"; 190 | NSString *uploadString = @"所有拼接信息"; 191 | // 存储到本地沙盒.下次启动找寻 192 | } 193 | 194 | ``` 195 | 196 | - 第三方收集crash (比如说集成Bugly/友盟,使用dSYM符号化并定位代码) 197 | 198 | - 上报的方式,时机,策略(优缺点)等 199 | 200 | 201 |
202 | 203 | 204 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 205 | 206 |

207 | 208 |

209 | 210 | 211 | ## 链接 212 | 213 | - [面试题系列目录](../README.md) 214 | - **上一份**: [第一份:一份"有点难"的iOS面试题MrPeak2016年](01一份"有点难"的iOS面试题MrPeak2016年.md) 215 | - **下一份**: [第三份:interview-iOS-3](03interview-iOS-3.md) -------------------------------------------------------------------------------- /interview-iOS/08字节跳动面试题:2018年4月.md: -------------------------------------------------------------------------------- 1 | 2 | ## 字节跳动面试题:2018年4月 3 | 4 | > 原链接早已失效(来源备注:https://xcqromance.top) 5 | 6 | > 针对原作者最后版本,此页补充部分答案和涉及点。 7 | 8 | - [内存管理方面(ARC、MRC、autorelease、autoreleasepool)](#内存管理方面arcmrcautoreleaseautoreleasepool) 9 | - [Runtime方面](#runtime方面消息发送nshipster-对象关联nshipster-方法交换等等) 10 | - 消息发送, 11 | - 对象关联, 12 | - 方法交换等 13 | 14 | - [KVO内部实现原理](#kvo内部实现原理) 15 | - [Runloop方面](#runloop方面) 16 | - [UITableView的优化手段方法](#uitableview的优化手段方法) 17 | - [多线程方面(GCD、NSOperation居多)](#多线程方面gcdnsoperation居多) 18 | - [SDWebImage源码分析](#sdwebimage源码分析) 19 | - [事件传递以及响应链](#事件传递以及响应链) 20 | - [HTTPS通信过程](#https通信过程) 21 | - [需要了解的知识点](#需要了解的知识点) 22 | 23 | ### 内存管理方面(ARC、MRC、autorelease、autoreleasepool) 24 | * 解答:[第三份面试题:Autorelease的原理及ARC的工作原理](./03interview-iOS-3.md) 25 | * 扩展:[第二十一份面试题:Autoreleasepool所使用的数据结构是什么?AutoreleasePoolPage结构体了解么?](./21出一套iOS高级面试题2018年7月.md#iOS基础题) 26 | 27 | ### Runtime方面 28 | 29 | > 消息发送 对象关联 方法交换等等 30 | 31 |
32 | 参考内容 33 | 34 | #### 消息发送 35 | 36 | > 一个对象的方法像这样[obj foo],编译器转成消息发送objc_msgSend(obj, foo),Runtime时执行的流程是这样的: 37 | 38 | - 首先,通过obj的isa指针找到它的 class ; 39 | - 在 class 的 method list 找 foo ; 40 | - 如果 class 中没到 foo,继续往它的 superclass 中找 ; 41 | - 一旦找到 foo 这个函数,就去执行它的实现IMP 。 42 | 43 | 44 | ##### 三级转发 45 | 46 | ``` 47 | + (BOOL)resolveInstanceMethod:(SEL)sel { 48 | return YES;//返回YES,进入下一步转发 49 | } 50 | 51 | - (id)forwardingTargetForSelector:(SEL)aSelector { 52 | return nil;//返回nil,进入下一步转发 53 | } 54 | 55 | - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { 56 | if ([NSStringFromSelector(aSelector) isEqualToString:@"foo"]) { 57 | return [NSMethodSignature signatureWithObjCTypes:"v@:"];//,进入forwardInvocation 58 | } 59 | 60 | return [super methodSignatureForSelector:aSelector]; 61 | } 62 | 63 | - (void)forwardInvocation:(NSInvocation *)anInvocation { 64 | SEL sel = anInvocation.selector; 65 | 66 | Person *p = [Person new]; 67 | if([p respondsToSelector:sel]) { 68 | [anInvocation invokeWithTarget:p]; 69 | } 70 | else { 71 | [self doesNotRecognizeSelector:sel]; 72 | } 73 | 74 | } 75 | 76 | ``` 77 | 78 |
79 | 80 | #### 对象关联 81 | 82 |
83 | 参考内容 84 | 85 | > 关联对象(Objective-C Associated Objects)给分类增加属性 86 | 87 | ``` 88 | //关联对象 89 | void objc_setAssociatedObject(id object, const void *key, id value, objc_AssociationPolicy policy) 90 | //获取关联的对象 91 | id objc_getAssociatedObject(id object, const void *key) 92 | //移除关联的对象 93 | void objc_removeAssociatedObjects(id object) 94 | 95 | id object:被关联的对象 96 | const void *key:关联的key,要求唯一 97 | id value:关联的对象 98 | objc_AssociationPolicy policy:内存管理的策略 99 | 100 | ``` 101 |
102 | 103 | #### 方法交换 104 | 105 |
106 | 参考内容 107 | 108 | - swizzling应该只在+load中完成。 在 Objective-C 的运行时中,每个类有两个方法都会自动调用。+load 是在一个类被初始装载时调用,+initialize 是在应用第一次调用该类的类方法或实例方法前调用的。两个方法都是可选的,并且只有在方法被实现的情况下才会被调用。 109 | 110 | - swizzling应该只在dispatch_once 中完成,由于swizzling 改变了全局的状态,所以我们需要确保每个预防措施在运行时都是可用的。原子操作就是这样一个用于确保代码只会被执行一次的预防措施,就算是在不同的线程中也能确保代码只执行一次。Grand Central Dispatch 的 dispatch_once满足了所需要的需求,并且应该被当做使用swizzling 的初始化单例方法的标准。 111 | 112 | ```objc 113 | 114 | + (void)load { 115 | static dispatch_once_t onceToken; 116 | dispatch_once(&onceToken, ^{ 117 | Class class = [self class]; 118 | SEL originalSelector = @selector(viewDidLoad); 119 | SEL swizzledSelector = @selector(devViewDidLoad); 120 | 121 | Method originalMethod = class_getInstanceMethod(class,originalSelector); 122 | Method swizzledMethod = class_getInstanceMethod(class,swizzledSelector); 123 | 124 | //judge the method named swizzledMethod is already existed. 125 | BOOL didAddMethod = class_addMethod(class, originalSelector, method_getImplementation(swizzledMethod), method_getTypeEncoding(swizzledMethod)); 126 | // if swizzledMethod is already existed. 127 | if (didAddMethod) { 128 | class_replaceMethod(class, swizzledSelector, method_getImplementation(originalMethod), method_getTypeEncoding(originalMethod)); 129 | } 130 | else { 131 | method_exchangeImplementations(originalMethod, swizzledMethod); 132 | } 133 | }); 134 | } 135 | ``` 136 | 137 |
138 | 139 | ### KVO内部实现原理 140 | 141 |
142 | 参考内容 143 | 144 | > KVO是基于runtime机制实现的 145 | 146 | - 当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter 方法。派生类在被重写的setter方法内实现真正的通知机制 147 | - 如果原类为ClassName,那么生成的派生类名为NSKVONotifying_ClassName 148 | - 每个类对象中都有一个isa指针指向当前类,当一个类对象的第一次被观察,那么系统会偷偷将isa指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的setter方法 149 | - 键值观察通知依赖于NSObject 的两个方法: willChangeValueForKey: 和 didChangevlueForKey:;在一个被观察属性发生改变之前, willChangeValueForKey:一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey:会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。 150 | - 补充:KVO的这套实现机制中苹果还偷偷重写了class方法,让我们误认为还是使用的当前类,从而达到隐藏生成的派生类 151 | 152 |
153 | 154 | ### Runloop方面 155 | 156 | * [Runloop相关问题解答参考面试题第六份](./06iOS基础问题系列2017年.md) 157 | 158 | * [runloop相关](./20阿里字节一套高效的iOS面试题2020年2月.md) 159 | - [app如何接收到触摸事件的](./20阿里字节一套高效的iOS面试题2020年2月.md#runloop) 160 | - [为什么只有主线程的runloop是开启的](./20阿里字节一套高效的iOS面试题2020年2月.md#runloop) 161 | - [为什么只在主线程刷新UI](./20阿里字节一套高效的iOS面试题2020年2月.md#runloop) 162 | - [PerformSelector和runloop的关系](./20阿里字节一套高效的iOS面试题2020年2月.md#runloop) 163 | - [如何使线程保活](./20阿里字节一套高效的iOS面试题2020年2月.md#runloop) 164 | 165 | ### UITableView的优化手段方法 166 | 167 | * [参考此份第7题](./06iOS基础问题系列2017年.md) 168 | 169 | ### 多线程方面(GCD、NSOperation居多) 170 | 171 | * [阿里字节面试题之多线程](./20阿里字节一套高效的iOS面试题2020年2月.md#多线程) 172 | 173 | ### SDWebImage源码分析 174 | * [参考此处](./02interview-iOS-2.md) 175 | 176 | ### 事件传递以及响应链 177 | 178 | * 传递的函数调用(pointinside,hittest) 179 | 180 | * 响应者链条 181 | 182 | * [要求详细的描述事件响应链参考答案](./25小米百度bigo滴滴快手等iOS面试题2020年上.md#要求详细的描述事件响应链) 183 | 184 | #### 图片的解压缩 185 | 186 |
187 | 参考内容 188 | 189 | > 在主线程的下一个 run loop 到来时,Core Animation 提交了这个隐式的 transaction ,这个过程可能会对图片进行 copy 操作,而受图片是否字节对齐等因素的影响,这个 copy 操作可能会涉及以下部分或全部步骤: 190 | 191 | > 在将磁盘中的图片渲染到屏幕之前,必须先要得到图片的原始像素数据,才能执行后续的绘制操作,这就是为什么需要对图片解压缩的原因 192 | 193 | * 分配内存缓冲区用于管理文件 IO 和解压缩操作; 194 | * 将文件数据从磁盘读到内存中; 195 | * 将压缩的图片数据解码成未压缩的位图形式,这是一个非常耗时的 CPU 操作; 196 | * 解压缩后的图片大小与原始文件大小之间没有任何关系,而只与图片的像素有关 197 | * 最后 Core Animation 使用未压缩的位图数据渲染 UIImageView 的图层。 198 | 199 |
200 | 201 | 202 | ### HTTPS通信过程 203 | 204 | - [本系列相似扩展问题:HTTPS的加密原理](./02interview-iOS-2.md) 205 | 206 |
207 | 参考内容 208 | 209 | * 客户端发起SSL通信,报文中包含客户端支持的SSL的指定版本,加密组件列表(加密算法及密码长度) 210 | * 服务端通过SSL通信,将SSL版本及加密算法版本中的一组发送至客户端. 211 | * 服务端发送客户端Certificate报文,报文中包含公开密钥证书. 212 | * 客户端验证证书的合法性(颁发证书的机构是否合法,证书中包含的网站地址是否与正在访问的地址一致等),如果证书受信任,则浏览器栏里面会显示一个小锁头,否则会给出证书不受信的提示;如果证书受信任,或者用户接受了不受信的证书,客户端会生成一个Pre-master secret的随机密码串,并且通过接受到公钥加密. 213 | * 服务端会通过私钥解密出Pre-master sercret随机密码串,通过Pre-master sercret解密密发来的握手信息,并验证Hash是否与浏览器发来的一致.之后通过密码加密一段握手信息,发给客户端. 214 | * 客户端解密并计算握手信息的Hash,如果与Server发来的Hash一致,此时握手过程结束,利用对称加密算法进行加密. 215 | 216 |
217 | 218 | ### 需要了解的知识点 219 | 220 | * APM方面(内存泄漏检测、crash监控,卡顿监控以及底层的实现原理等等) 221 | * [卡顿监控](19新浪公司iOS面试题2019年6月.md) 222 | * [阿里字节面试题之性能优化](./20阿里字节一套高效的iOS面试题2020年2月.md#性能优化) 223 | 224 | * 组件化方(蘑菇街 App 的组件化之路、iOS应用架构谈 组件化方案、在现有工程中实施基于CTMediator的组件化方案、iOS 组件化方案探索、iOS 组件化–路由设计思路分析) 225 | * [业界常用的组件通信方案优缺点概述](https://github.com/DevDragonLi/ProtocolServiceKit#业界常用的组件通信方案) 226 | 227 | * 持续化集成(我们公司使用的是:Jenkins+fastlane) 228 | * [Jenkins官网](https://www.jenkins.io) 229 | * [fastlane](https://docs.fastlane.tools) 230 | * 按照官网相关doc操作,或者网上找下教程即可,实践即可。 231 | 232 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 233 | 234 |

235 | 236 |

237 | 238 | 239 | ## 链接 240 | 241 | - [面试题系列目录](../README.md) 242 | - **上一份**: [第七份:深圳iOS面试分享2018年4月](07深圳iOS面试分享2018年4月.md) 243 | - **下一份**: [第九份:头条网易微信阿里美团硕士春招面试题2018年3月](09头条网易微信阿里美团硕士春招面试题2018年3月.md) -------------------------------------------------------------------------------- /interview-iOS/15腾讯社招iOS面试记录2018年7月.md: -------------------------------------------------------------------------------- 1 | # 腾讯社招iOS面试记录2018年7月 2 | 3 | > 作者:AceDong&&juejin.im/post/5b3c40f4e51d45191a0d0aae 4 | 5 | - [对mrc和arc的理解](#对mrc和arc的理解) 6 | - [谈谈对自动释放池的理解](#谈谈对自动释放池的理解) 7 | - [自动释放池在mrc和arc区别](#自动释放池在mrc和arc区别) 8 | - [多层自动释放池嵌套的对象在哪一层释放](#多层自动释放池嵌套的对象在哪一层释放) 9 | - [对于block,理解,mrc和arc下有什么区别,使用注意事项](#对于block理解mrc和arc下有什么区别使用注意事项) 10 | - [对于深拷贝和浅拷贝的理解](#对于深拷贝和浅拷贝的理解) 11 | - [对于strong 12 | weak,atomic等等理解](#对于strong-weakatomic等等理解) 13 | - [weak原理](#weak原理) 14 | - [如果属性完全不加修饰词入weak,atomic,系统会怎么处理](#如果属性完全不加修饰词入weakatomic系统会怎么处理) 15 | - [简述下block的实现](#简述下block的实现) 16 | - [描述下IM系统如何保证消息不丢](#描述下im系统如何保证消息不丢) 17 | - [IM数据库如何设计表](#im数据库如何设计表) 18 | - [C++引用和指针有什么区别](#c引用和指针有什么区别) 19 | - [Http协议30x的错误是什么](#http协议30x的错误是什么) 20 | - [谈谈你懂runloop得理解:由浅入深](#谈谈你懂runloop得理解由浅入深) 21 | - [谈谈对多线程理解:由浅入深](#谈谈对多线程理解由浅入深) 22 | - [谈谈category和extension区别,系统如何底层实现category](#谈谈category和extension区别系统如何底层实现category) 23 | - [谈谈消息转发机制实现](#谈谈消息转发机制实现) 24 | - [谈谈事件响应链,如何响应view之外的事件](#谈谈事件响应链如何响应view之外的事件) 25 | - [界面性能优化](#界面性能优化) 26 | 27 | ## 一面电话面试 28 | 29 | * 先简单自我介绍一下自己 30 | * 从我脸上看到什么:**帅** 31 | 32 | ### 对mrc和arc的理解 33 | 34 |
35 | 参考内容 36 | 37 | - MRC的优势及劣势 38 | - [ARC的工作原理参考](./03interview-iOS-3.md) 39 | 40 |
41 | 42 | ### 谈谈对自动释放池的理解 43 |
44 | 参考内容 45 | 46 | - [参考Autorelease的原理](./03interview-iOS-3.md) 47 | 48 | - autorelease方法会把对象存储到AutoreleasePoolPage的链表里。等到auto release pool被释放的时候,把链表内存储的对象删除。所以,AutoreleasePoolPage就是自动释放池的内部实现。 49 | 50 | ``` 51 | public: static inline id autorelease(id obj) 52 | { 53 | assert(obj); 54 | assert(!obj->isTaggedPointer()); 55 | id *dest __unused = autoreleaseFast(obj); 56 | assert(!dest || dest == EMPTY_POOL_PLACEHOLDER || *dest == obj); 57 | return obj; 58 | } 59 | static inline id *autoreleaseFast(id obj) 60 | { 61 | AutoreleasePoolPage *page = hotPage(); 62 | if (page && !page->full()) { 63 | return page->add(obj); 64 | } else if (page) { 65 | return autoreleaseFullPage(obj, page); 66 | } else { 67 | return autoreleaseNoPage(obj); 68 | } 69 | } 70 | id *add(id obj) 71 | { 72 | assert(!full()); 73 | unprotect(); 74 | id *ret = next; // faster than `return next-1` because of aliasing 75 | *next++ = obj; 76 | protect(); 77 | return ret; 78 | } 79 | 80 | ``` 81 |
82 | 83 | ### 自动释放池在mrc和arc区别 84 |
85 | 参考内容 86 | 87 | > 自动释放池是oc提供的一种自动回收的机制,具有延迟释放的特性,即当我们创建了一个对象,并把他加入到了自动释放池中时,他不会立即被释放,会等到一次runloop结束或者作用域超出{}或者超出[pool release]之后再被释放 88 | - MRC: 通过手动创建的方式来创建自动释放池,这种方式创建的自动释放池需要手动调用release(引用计数环境下,调用release和drain的效果相同,但是在CG下,drain会触发GC,release不会) 89 | - ARC下除了NSAutoreleasePool不可用以外,其他的同MRC 90 | 91 |
92 | 93 | ### 多层自动释放池嵌套的对象在哪一层释放 94 |
95 | 参考内容 96 | 97 | > 嵌套的autoreleasepool 98 | 99 | ``` 100 | @autoreleasepool {//DragonLi被放在该自动释放池里面 101 | XXClass *DragonLi = [[XXClass alloc]init]; 102 | @autoreleasepool {//p2被放在该自动释放池里面 103 | XXClass * DragonLi = [[XXClass alloc]init]; 104 | } 105 | } 106 | autorelease对象被添加进离他最近的自动释放池,多层的pool会有多个哨兵对象。 107 | 108 | ``` 109 | 110 |
111 | 112 | ### 对于block,理解,mrc和arc下有什么区别,使用注意事项 113 | 114 | ### 对于深拷贝和浅拷贝的理解 115 |
116 | 参考内容 117 | 118 | - 浅拷贝:只创建一个新的指针,指向原指针指向的内存 119 | - 深拷贝:创建一个新的指针,并开辟新的内存空间,内容拷贝自原指针指向的内存,并指向它 120 | 121 | ##### NSString一般使用Copy。 122 | - 如果用strong修饰,当我们给它传一个NSMutableString类型的数据时,它的指针指向了该数据,之后会随NSMutableString的特性去改变 123 | 124 |
125 | 126 | 127 | ### weak原理 128 | 129 | - [weak弱引用的代码逻辑实现](./03interview-iOS-3.md) 130 | 131 | ### 如果属性完全不加修饰词入weak,atomic,系统会怎么处理 132 |
133 | 参考内容 134 | 135 | - 默认为atomic,Strong,ReadWrite 136 | 137 |
138 | 139 | ### 简述下block的实现 140 | 141 | - [block](./20阿里字节一套高效的iOS面试题2020年2月.md#block) 142 | 143 | ### 描述下IM系统如何保证消息不丢 144 | 145 | ### IM数据库如何设计表 146 | 147 | ### C++引用和指针有什么区别 148 |
149 | 参考内容 150 | 151 | > 本质:引用是别名,指针是地址,具体的: 152 | 153 | 154 |
155 | 156 | ### Http协议30x的错误是什么 157 |
158 | 参考内容 159 | 160 | - 1xx - 信息提示 161 | - 这些状态代码表示临时的响应。客户端在收到常规响应之前,应准备接收一个或多个 1xx 响应。 • 100 - 继续。 162 | - 2xx - 成功 163 | - 这类状态代码表明服务器成功地接受了客户端请求。 164 | - **• 200 - 确定。客户端请求已成功。** 165 | - • 201 - 已创建。 166 | - • 202 - 已接受。 167 | - • 203 - 非权威性信息。 168 | - • 204 - 无内容。 169 | - • 205 - 重置内容。 170 | - • 206 - 部分内容。 171 | 172 | - 3xx - 重定向 173 | - 客户端浏览器必须采取更多操作来实现请求。例如,浏览器可能不得不请求服务器上的不同的页面,或通过代理服务器重复该请求。 174 | - • 302 - 对象已移动。 175 | - • 304 - 未修改。 176 | - **• 307 - 临时重定向。** 177 | 178 | - 4xx - 客户端错误 179 | - • 401 - 访问被拒绝。IIS 定义了许多不同的 401 错误,它们指明更为具体的错误原因。这些具体的错误代码在浏览器中显示,但不在 IIS 日志中显示: 180 | - • 401.1 - 登录失败。 181 | - • **403.1 - 执行访问被禁止。** 182 | - • 403.2 - 读访问被禁止。 183 | - • 403.3 - 写访问被禁止。 184 | - 5xx - 服务器错误 185 | - 服务器由于遇到错误而不能完成该请求。 186 | - • 500 - 内部服务器错误。 187 | - • 500.12 - 应用程序正忙于在 Web 服务器上重新启动。 188 | - • 503 - 服务不可用。这个错误代码为 IIS 6.0 所专用。 189 | 190 |
191 | 192 | ### 谈谈你懂runloop得理解:由浅入深 193 |
194 | 参考内容 195 | 196 | - [runloop](./20阿里字节一套高效的iOS面试题2020年2月.md#runloop) 197 | 198 |
199 | 200 | ### 谈谈对多线程理解:由浅入深 201 | 202 | - [多线程](./20阿里字节一套高效的iOS面试题2020年2月.md#多线程) 203 | 204 | ### 谈谈category和extension区别,系统如何底层实现category 205 |
206 | 参考内容 207 | 208 | - [分类和扩展有什么区别](./21出一套iOS高级面试题2018年7月.md) 209 | 210 | #### 系统如何底层实现category 211 | 212 | > 从objc-os.mm文件的_objc_init函数开始-->map_images-->map_images_nolock-->_read_images-->remethodizeClass-->attachCategories-->attachLists-->realloc、memmove、 memcpy。 213 | - 合并后分类的方法在前面(最后参与编译的那个分类的方法列表在最前面),本类的方法列表在最后面。所以当分类中有和本类同名的方法时,调用这个方法执行的就是分类中的方法。从这个现象来看,就好像本类的方法被分类中同名的方法给覆盖了,实际上并没有覆盖,只是调用方法时最先查找到了分类的方法所以就执行分类的方法 214 | 215 | ``` 216 | // 定义在objc-runtime-new.h文件中 217 | struct category_t { 218 | const char *name; // 比如给Student添加分类,name就是Student的类名 219 | classref_t cls; 220 | struct method_list_t *instanceMethods; // 分类的实例方法列表 221 | struct method_list_t *classMethods; // 分类的类方法列表 222 | struct protocol_list_t *protocols; // 分类的协议列表 223 | struct property_list_t *instanceProperties; // 分类的实例属性列表 224 | struct property_list_t *_classProperties; // 分类的类属性列表 225 | }; 226 | 227 | ``` 228 | 229 |
230 | 231 | ### 谈谈消息转发机制实现 232 | 233 | - [消息转发参考](08字节跳动面试题:2018年4月.md) 234 | 235 | ### 谈谈事件响应链,如何响应view之外的事件 236 |
237 | 参考内容 238 | 239 | 240 | * 函数调用(pointinside,hittest)入手 241 | 242 | * [要求详细的描述事件响应链参考答案](./25小米百度bigo滴滴快手等iOS面试题2020年上.md#要求详细的描述事件响应链) 243 | 244 |
245 | 246 | ### 界面性能优化 247 | 248 | ## 二面视频面试 249 | 250 | ### 聊一聊过往项目中你觉得收获最大的一个模块 251 | - 就说了上个项目做类似朋友圈的优化思路,谈到了空间换时间,缓存,渲染相关的技术点 252 | - 需求痛点:界面卡顿,体验不好 解决方案:探索的思路-》解决方案 253 | - 该模块引申到的新话题还涉及到了增量更新,内存缓存,本地缓存 254 | - 细节上还谈到了富文本绘制,Coretext框架的使用 255 | - 上个项目中存在视频裁剪,录制等功能。 256 | 257 | 面试官对这块有些兴趣,就聊到了视频裁剪的实现,因为我们项目中使用了ffmpeg做的裁剪功能。包括视频下载,数据裁剪封装,引申聊到了边预览边裁剪,因为我之前的项目并没有做到预览裁剪这块。也就没有深入聊下去了。期间简单谈到了**rstp协议,和HLS,rtmp等协议的对比**,信令协议。虽然之前都有看过协议的大致实现和预览,但是实际使用的是SDK,没有实践加持。这部分知识是很容易忘记的。大致聊了下总体差别 258 | - 项目中有用到过DLNA投屏协议 259 | 说来又是惭愧,自己完整做过的项目,过去了两年,居然连流程,协议都只是零零散散的记起来了,很勉强的说出了大概实现流程。知道最后才记起来是**soap协议**。当初为了做这个可是研究了整整两周的。面试官应该也实现过这个需求,提到了**视频盒子断线如何检测做处理**,什么原因导致的。由于之前我们的产品需求比较简单,没有特别完善。这里我也只能说了大概 260 | - 项目做过视频播放需求,使用的AVPlayer框架(重点聊) 261 | 面试官问到,**AVPlayer怎么监听视频缓冲状态的,有哪几种状态**。说来又是惭愧,我只记得是KVO监听的。具体的API已经记不清了。 262 | 接着面试官问到这个需求遇到过哪些坑,怎么解决的。 263 | 这个还真的有,首先是回调播放进度在拖动时候错乱,加载某些小视频的适配,首帧出图很慢。KVO的模式不灵活。**缓冲进度不受我们控制**。短视频可能直接迅速缓冲到底。还是之前的思路,需求痛点有了.解决方案:探索的思路-》解决方案。 264 | 不得不说之前做的产品,都是需求驱动,解决了需求,很多时候就没有极客精神,在深入的去探讨。这块真的是差! 265 | - 如果网络不好,首帧出图之后,如何优化后续播放不卡顿 当时已经一脸懵逼了:就提到了可以适当加大缓冲区,等到足够的I帧数据再开始播放 266 | 267 | - 项目聊完了之后,又追问了iOS的一些基础问题,属性和成员变量区别,strong,atomic关键字,怎么理解runloop,runloop有几种状态等等 268 | 269 | - 非常有意思的算法题 270 | - 有15个瓶子,其中最多有一瓶有毒,现在有四只老鼠,喝了有毒的水之后,第二天就会死。如何在第二天就可以判断出哪个瓶子有毒 271 | 答:开始我想到的是常规思路二分法,717,和面试官说了,发现四只老鼠根本不够,面试官友好的提示从老鼠面去想,这时候很快想到了一个老鼠有死和不死,也就0和1两个状态,四只老鼠有16个组合,正好是足够的。但是怎么分配瓶子,还没想好,演算了一会儿,因为面试官这边时间有限,就说思路是正确的。下面有兴趣在看怎么分哈。面试就到此结束了。 272 | 273 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 274 | 275 |

276 | 277 |

278 | 279 | 280 | ## 链接 281 | 282 | - [面试题系列目录](../README.md) 283 | - **上一份**: [阿里腾讯百度头条美团iOS面试题2018年4月](14阿里腾讯百度头条美团iOS面试题2018年4月.md) 284 | - **下一份**: [腾讯音乐iOS面试题2018年7月](16腾讯音乐iOS面试题2018年7月.md) 285 | 286 | -------------------------------------------------------------------------------- /interview-iOS/10美团饿了么面试题2018年4月.md: -------------------------------------------------------------------------------- 1 | ## 美团饿了么面试题2018年4月 2 | 3 | > 备注:原作者分享几个 4 | 5 | 6 | #### 自实现pow(double, double) 7 | 8 |
9 | 参考内容 10 | 11 | ``` 12 | func _pow_3(_ base: Double, _ exponent: Int) -> Double { 13 | 14 | var isNegative = false 15 | var exp = exponent 16 | if exp < 0 { 17 | isNegative = true 18 | exp = -exp 19 | } 20 | let result = _pow_2(base, exp) 21 | return isNegative ? 1 / result : result 22 | } 23 | 24 | ``` 25 |
26 | 27 | #### findMedianSortedArrays (找到两个排序数组的中位数) 28 | 29 |
30 | 参考内容 31 | 32 | ``` 33 | 34 | func findMedianSortedArrays_3(_ array1: [Int], _ array2: [Int]) -> Double { 35 | 36 | let total = array1.count + array2.count 37 | let index = total / 2 38 | let count = array1.count < array2.count ? array2.count : array1.count 39 | var array = [Int]() 40 | 41 | var i = 0, j = 0; 42 | for _ in 0...count { 43 | if array.count >= index + 1 { 44 | break 45 | } 46 | if array1[i] < array2[j] { 47 | array.append(array1[i]) 48 | i += 1 49 | } else { 50 | array.append(array2[j]) 51 | j += 1 52 | } 53 | } 54 | return total % 2 == 1 ? Double(array[index]) : Double(array[index] + array[index - 1]) * 0.5 55 | } 56 | 57 | ``` 58 |
59 | 60 | #### UIContorl -> UIButton 61 |
62 | 参考内容 63 | 64 | - UIButton setTitle的时候才会创建UILabel, setImage的时候才会创建UIImageView, 你为什么吧frame给写死... 不知道UIView有sizeToFit么, 你怎么不实现sizeThatFits, 你是完全不会用吧... 你知道UIButton用AutoLayout布局的时候只要设置origin坐标, 宽高就可以自适应了, 你自定义的时候怎么不实现呢? setBackgroundImage和setImageEdgeInsets 65 | 66 | ``` 67 | 68 | import UIKit protocol ButtonInterface { func setTitle(_ title: String); func setTitleColor(_ titleColor: UIColor); func setTitleEdgeInsets(_ edgeInsets: UIEdgeInsets); func setImage(_ image: UIImage); func setBackgroundImage(_ image: UIImage); func setImageEdgeInsets(_ edgeInsets: UIEdgeInsets); 69 | } class Button: UIControl, ButtonInterface { lazy var titleLabel: UILabel = UILabel() lazy var imageView: UIImageView = UIImageView() lazy var backgroundImageView: UIImageView = UIImageView() var titleLabelIsCreated = false var imageViewIsCreated = false var backgroundImageViewCreated = false internal func setTitle(_ text: String) { if !titleLabelIsCreated { 70 | addSubview(titleLabel) 71 | titleLabelIsCreated = true } 72 | titleLabel.text = text 73 | } internal func setTitleColor(_ textColor: UIColor) { if !titleLabelIsCreated { return } 74 | titleLabel.textColor = textColor 75 | } internal func setTitleEdgeInsets(_ edgeInsets: UIEdgeInsets) { if !titleLabelIsCreated { return } 76 | } internal func setImage(_ image: UIImage) { if !imageViewIsCreated { 77 | addSubview(imageView) 78 | imageViewIsCreated = true } 79 | imageView.image = image 80 | } internal func setBackgroundImage(_ image: UIImage) { if !backgroundImageViewCreated { 81 | addSubview(backgroundImageView) 82 | insertSubview(backgroundImageView, at: 0) 83 | backgroundImageViewCreated = true } 84 | backgroundImageView.image = image 85 | } internal func setImageEdgeInsets(_ edgeInsets: UIEdgeInsets) { if !imageViewIsCreated { return } 86 | } override func sizeThatFits(_ size: CGSize) -> CGSize { if titleLabelIsCreated && !imageViewIsCreated && !backgroundImageViewCreated { let text: NSString? = titleLabel.text as NSString? let titleLabelW: CGFloat = text?.boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: bounds.height), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : titleLabel.font], context: nil).size.width ?? 0.0 let titleLabelH: CGFloat = text?.boundingRect(with: CGSize(width: titleLabelW, height: CGFloat(MAXFLOAT)), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : titleLabel.font], context: nil).size.height ?? 0.0 return CGSize(width: titleLabelW, height: titleLabelH + 10) 87 | } else if !titleLabelIsCreated && imageViewIsCreated { return imageView.image?.size ?? CGSize.zero 88 | } else if titleLabelIsCreated && imageViewIsCreated { let text: NSString? = titleLabel.text as NSString? let titleLabelW: CGFloat = text?.boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: bounds.height), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : titleLabel.font], context: nil).size.width ?? 0.0 let titleLabelH: CGFloat = text?.boundingRect(with: CGSize(width: titleLabelW, height: CGFloat(MAXFLOAT)), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : titleLabel.font], context: nil).size.height ?? 0.0 let imageViewW: CGFloat = imageView.image?.size.width ?? 0.0 let imageViewH: CGFloat = imageView.image?.size.height ?? 0.0 return CGSize(width: titleLabelW + imageViewW, height: imageViewH > titleLabelH ? imageViewH : titleLabelH) 89 | } else { return backgroundImageView.image?.size ?? CGSize.zero 90 | } 91 | } override func layoutSubviews() { super.layoutSubviews() if titleLabelIsCreated && !imageViewIsCreated { 92 | titleLabel.frame = bounds 93 | titleLabel.textAlignment = .center 94 | } else if !titleLabelIsCreated && imageViewIsCreated { let y: CGFloat = 0; let width: CGFloat = imageView.image?.size.width ?? 0; let x: CGFloat = (bounds.width - width) * 0.5; let height: CGFloat = bounds.height; 95 | imageView.frame = CGRect(x: x, y: y, width: width, height: height) 96 | } else if titleLabelIsCreated && imageViewIsCreated { let imageViewY: CGFloat = 0; let imageViewW: CGFloat = imageView.image?.size.width ?? 0; let imageViewH: CGFloat = bounds.height; let text: NSString? = titleLabel.text as NSString? let titleLabelW: CGFloat = text?.boundingRect(with: CGSize(width: CGFloat(MAXFLOAT), height: bounds.height), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : titleLabel.font], context: nil).size.width ?? 0.0 let titleLabelH: CGFloat = text?.boundingRect(with: CGSize(width: titleLabelW, height: CGFloat(MAXFLOAT)), options: NSStringDrawingOptions.usesLineFragmentOrigin, attributes: [NSAttributedStringKey.font : titleLabel.font], context: nil).size.height ?? 0.0 let imageViewX: CGFloat = (bounds.width - imageViewW - titleLabelW) * 0.5; let titleLabelX: CGFloat = imageViewX + imageViewW let titleLabelY = (bounds.height - titleLabelH) * 0.5 titleLabel.frame = CGRect(x: titleLabelX, y: titleLabelY, width: titleLabelW, height: titleLabelH) 97 | imageView.frame = CGRect(x: imageViewX, y: imageViewY, width: imageViewW, height: imageViewH) 98 | } if backgroundImageViewCreated { 99 | backgroundImageView.frame = bounds 100 | } 101 | } 102 | } 103 | 104 | ``` 105 |
106 | 107 | ### 网络框架 108 | 109 |
110 | 参考内容 111 | 112 | > 可以参考`YTKNetworking` 或者`AFN` 113 | 114 | - 设计一个网络框架, 如何进行不同数据解析的设计(header, body), 并能够进行自定义 115 | 116 | - 重连机制如何处理, 状态码错误转发机制的处理 117 | 118 | - 如何避免回调地狱, 实现Promise的自实现. 119 | 120 | #### 网络接口规范 121 | 122 | - 两层三部分数据结构 123 | 124 | #### 多服务器多环境设置 125 | 126 | - 标准的APP是有4个环境的,开发、测试、预发、正式, 127 | 128 | #### 网络层数据传递(请求和返回) 129 | 130 | - Client做两个操作,一个是生成NSURLRequest,一个是生成NSURLSessionDataTask并发起,另外还要暴露取消操作给Engine, 131 | 132 | 133 | #### 业务层对接方式 134 | 135 | - casa:集约型API调用其实就是所有API的调用只有一个类,然后这个类接收API名字,API参数,以及回调着陆点(可以是target-action,或者block,或者delegate等各种模式的着陆点)作为参数。然后执行类似startRequest这样的方法,它就会去根据这些参数起飞去调用API了,然后获得API数据之后再根据指定的着陆点去着陆。 136 | 137 | #### 网络请求怎么自动取消 138 | 139 | - casa思路:在**BaseDataEngine的dealloc里面做取消网络请求操作**,把BaseDataEngine绑定给ViewController,当ViewController销毁时BaseDataEngine也就跟着销毁了 140 | - 每个接口生成一个BaseEngine实例,持有Client返回的requestID,所以就可以做取消操作,简单的使用场景 141 | 142 | #### 网络层错误处理 143 | 144 | > 我们将错误处理分为两个步骤,一个是错误解析,一个是错误的UI展示 145 | 146 | - 设计的接口返回数据是标准的id data, NSError *error,是Client就把error处理好,不管你是网络超时错误也好,或者是数据格式不正确也好,都error解析完整,把code错误码定义好,上层根据需要通过code来做具体的UI展示,因为有的界面的错误需要用户的点击确认,有的页面的错误只是一闪而过的提示框,把error交给BaseEngine或者DataEngine来处理errorUI, 147 | 148 | - 定义了一套errorUI的枚举,当BaseEngine拿到error的时候就去做错误的展示 149 | 150 |
151 | 152 | 153 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 154 | 155 |

156 | 157 |

158 | 159 | ## 链接 160 | 161 | - [面试题系列目录](../README.md) 162 | - **上一份**: [头条网易微信阿里美团硕士春招面试题2018年3月](09头条网易微信阿里美团硕士春招面试题2018年3月.md) 163 | - **下一份**: [天猫蚂蚁金服百度面试题2018年4月](11天猫蚂蚁金服百度面试题2018年4月.md) 164 | -------------------------------------------------------------------------------- /interview-iOS/05iOS宝库iOS开发笔试题2017年.md: -------------------------------------------------------------------------------- 1 | # 宝库iOS开发笔试题2017年 2 | 3 | > 较为简单,可快速略过 4 | 5 | - [对数组中的元素去重复](#对数组中的元素去重复) 6 | - [请简单写出增、删、改、查的SQL语句](#请简单写出增删改查的sql语句) 7 | - [与 NSURLConnection 相比,NSURLsession 8 | 改进哪些?](#与-nsurlconnection-相比nsurlsession-改进哪些) 9 | - [使用drawRect有什么影响?](#使用drawrect有什么影响) 10 | - [什么时候会报unrecognized 11 | selector的异常?如何避免?](#什么时候会报unrecognized-selector的异常如何避免) 12 | - [界面多个网络请求,如何处理刷新的?](#界面多个网络请求如何处理刷新的) 13 | - [如果tableView界面网络请求有缓存数据逻辑?](#如果tableview界面网络请求有缓存数据逻辑) 14 | - [init方法私有化](#init方法私有化) 15 | - [线程中栈与堆是公有的还是私有的?](#线程中栈与堆是公有的还是私有的) 16 | 17 | ## 对数组中的元素去重复 18 |
19 | 参考内容 20 | 21 | - 参考如下代码 22 | 23 | ```objc 24 | NSArray *array = @[@"12-11", @"12-11", @"12-11", @"12-12", @"12-13", @"12-14"]; 25 | 26 | 1.开辟新的内存空间,然后判断是否存在,若不存在则添加到数组中,得到最终结果的顺序不发生变化。效率分析:时间复杂度为O ( n2 ): 27 | 28 | NSMutableArray *resultArray = [[NSMutableArray alloc] initWithCapacity:array.count]; 29 | // 外层一个循环 30 | for (NSString *item in array) { 31 | // 调用-containsObject:本质也是要循环去判断,因此本质上是双层遍历 32 | // 时间复杂度为O ( n^2 )而不是O (n) 33 | if (![resultArray containsObject:item]) { 34 | [resultArray addObject:item]; 35 | } 36 | } 37 | NSLog(@"resultArray: %@", resultArray); 38 | 39 | 2.利用NSDictionary去重,字典在设置key-value时,若已存在则更新值,若不存在则插入值,然后获取allValues。若不要求有序,则可以采用此种方法。若要求有序,还得进行排序。效率分析:只需要一个循环就可以完成放入字典,若不要求有序,时间复杂度为O(n)。若要求排序,则效率与排序算法有关: 40 | NSMutableDictionary *resultDict = [[NSMutableDictionary alloc] initWithCapacity:array.count]; 41 | for (NSString *item in array) { 42 | [resultDict setObject:item forKey:item]; 43 | } 44 | NSArray *resultArray = resultDict.allValues; 45 | NSLog(@"%@", resultArray); 46 | 47 | 如果需要按照原来的升序排序,可以这样: 48 | resultArray = [resultArray sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { 49 | NSString *item1 = obj1; 50 | NSString *item2 = obj2; 51 | return [item1 compare:item2 options:NSLiteralSearch]; 52 | }]; 53 | NSLog(@"%@", resultArray); 54 | 55 | 3.利用集合NSSet的特性(确定性、无序性、互异性),放入集合就自动去重了。但是它与字典拥有同样的无序性,所得结果顺序不再与原来一样。如果不要求有序,使用此方法与字典的效率应该是差不多的。效率分析:时间复杂度为O (n): 56 | NSSet *set = [NSSet setWithArray:array]; 57 | NSArray *resultArray = [set allObjects]; 58 | NSLog(@"%@", resultArray); 59 | 如果要求有序,那就得排序,比如这里要升序排序: 60 | 61 | resultArray = [resultArray sortedArrayUsingComparator:^NSComparisonResult(id _Nonnull obj1, id _Nonnull obj2) { 62 | NSString *item1 = obj1; 63 | NSString *item2 = obj2; 64 | return [item1 compare:item2 options:NSLiteralSearch]; 65 | }]; 66 | NSLog(@"%@", resultArray); 67 | 4. 有序集合--->直接使用有序集合 68 | NSOrderedSet *set = [NSOrderedSet orderedSetWithArray:array]; 69 | NSLog(@"%@", set.array); 70 | 71 | ``` 72 |
73 | 74 | ## 请简单写出增、删、改、查的SQL语句 75 |
76 | 参考内容 77 | 78 | - 增:`insert into tb_blogs(name, url) values('DragonLi','https://github.com/DevDragonLi');` 79 | 80 | - 删: `delete from tb_blogs where blogid = 1;` 81 | 82 | - 改:`update tb_blogs set url = 'www.textURL.com' where blogid = 1;` 83 | 84 | - 查:`select name, url from tb_blogs where blogid = 1;` 85 | 86 |
87 | 88 | ## 与 NSURLConnection 相比,NSURLsession 改进哪些? 89 |
90 | 参考内容 91 | 92 | - 可以配置每个 session 的缓存,协议,cookie,以及**证书策略(credential policy)**,甚至跨程序共享这些信息 93 | - session task。它负责处理数据的加载以及文件和数据在客户端与服务端之间的上传和下载。NSURLSessionTask 与 NSURLConnection 最大的相似之处在于它也负责数据的加载,最大的不同之处在于**所有的 task 共享其创造者 NSURLSession** 这一公共委托者(common delegate) 94 | 95 |
96 | 97 | ## 使用drawRect有什么影响? 98 |
99 | 参考内容 100 | 101 | > drawRect方法依赖Core Graphics框架来进行自定义的绘制 102 | 103 | - 缺点:它处理touch事件时每次按钮被点击后,都会用setNeddsDisplay进行强制重绘;而且不止一次,每次单点事件触发两次执行。这样的话从性能的角度来说,对CPU和内存来说都是欠佳的。特别是如果在我们的界面上有多个这样的UIButton实例,那就会很糟糕了 104 | - 这个方法的调用机制也是非常特别. 当你调用 setNeedsDisplay 方法时, UIKit 将会把当前图层标记为dirty,但还是会显示原来的内容,直到下一次的视图渲染周期,才会将标记为 dirty 的图层重新建立Core Graphics上下文,然后将内存中的数据恢复出来, 再使用 CGContextRef 进行绘制 105 | 106 |
107 | 108 | 109 | ## 什么时候会报unrecognized selector的异常?如何避免? 110 |
111 | 参考内容 112 | 113 | - 当调用该对象上某个方法,而该对象上没有实现这个方法的时候, 可以通过“消息转发”进行解决,如果还是不行就会报unrecognized selector异常 114 | - objc是动态语言,每个方法在运行时会被动态转为消息发送,即:objc_msgSend(receiver, selector),整个过程介绍如下: 115 | - objc在向一个对象发送消息时,runtime库会根据对象的isa指针找到该对象实际所属的类然后在该类中的方法列表以及其父类方法列表中寻找方法运行 116 | 如果,在最顶层的父类中依然找不到相应的方法时,程序在运行时会挂掉并抛出异常unrecognized selector sent to XXX 。但是在这之前,objc的运行时会给出三次拯救程序崩溃的机会 117 | 118 | ### 三次拯救程序崩溃的机会 119 | 120 | - Method resolution:objc运行时会调用**+resolveInstanceMethod:或者 +resolveClassMethod**:,让你有机会提供一个函数实现。如果你添加了函数并返回 YES,那运行时系统就会重新启动一次消息发送的过程,如果 resolve 方法返回 NO ,运行时就会移到下一步,消息转发 121 | - Fast forwarding:如果目标对象实现了**-forwardingTargetForSelector:**,Runtime 这时就会调用这个方法,给你把这个消息转发给其他对象的机会,只要这个方法返回的不是nil和self,整个消息发送的过程就会被重启,当然发送的对象会变成你返回的那个对象。否则,就会继续Normal Fowarding。这里叫Fast,只是为了区别下一步的转发机制。因为这一步不会创建任何新的对象,但Normal forwarding转发会创建一个NSInvocation对象,相对Normal forwarding转发更快点,所以这里叫Fast forwarding 122 | 123 | - Normal forwarding这一步是Runtime最后一次给你挽救的机会。 124 | 首先它会发送**-methodSignatureForSelector:**消息获得函数的参数和返回值类型。 125 | **如果-methodSignatureForSelector:返回nil,Runtime则会发出-doesNotRecognizeSelector:消息,程序这时也就挂掉了**。如果返回了一个函数签名,Runtime就会创建一个NSInvocation对象并发送-forwardInvocation:消息给目标对象 126 | 127 | #### 可以项目引入类似防Crash的组件(或者自研),平时加强数据逻辑校验等。 128 | 129 |
130 | 131 | ## 界面多个网络请求,如何处理刷新的? 132 | 133 |
134 | 参考内容 135 | 136 | > 使用调度组:**问题 : 为多个请求均加载完成,但界面已在未得到数据前提前刷新导致界面空白** 137 | 138 | - dispatch_semaphore信号量为基于计数器的一种多线程同步机制。用于解决在多个线程访问共有资源时候,会因为多线程的特性而引发数据出错的问题。 139 | 140 | - semaphore计数大于等于1,计数-1,返回,程序继续运行。如果计数为0,则等待。 141 | 142 | - dispatch_semaphore_signal(semaphore)为计数+1操作。 143 | 144 | - dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)为设置等待时间,这里设置的等待时间是一直等待 145 | 146 | 147 | ```objc 148 | 1. 调度组 149 | dispatch_group_t group = dispatch_group_create(); 150 | 151 | dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 152 | NSLog(@"netWorking_Frist"); 153 | 154 | }); 155 | 156 | dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 157 | NSLog(@"netWorking_Second"); 158 | }); 159 | dispatch_group_async(group,dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 160 | NSLog(@"netWorking_Three"); 161 | }); 162 | 163 | dispatch_group_notify(group, dispatch_get_main_queue(), ^{ 164 | NSLog(@"complete"); 165 | }); 166 | 167 | 168 | 2. 信号量:dispatch_semaphore 169 | 170 | - (void)netWorkingimplementation{ // 基于自身项目的网络请求 171 | // 1. 发起请求 172 | dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 173 | // 2. 成功/失败回调标记 174 | dispatch_semaphore_signal(semaphore); 175 | // 3. 计数为0 ,则一直等待 176 | dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 177 | } 178 | 179 | ``` 180 |
181 | 182 | 183 | ## 如果tableView界面网络请求有缓存数据逻辑? 184 | 185 |
186 | 参考内容 187 | 188 | - 首次进入一个界面tableview的数据应该先读取缓存,主要防止没有网络或者网络不好的情况下用户等待数据时间过长或者没有数据用户体验不好,主要用于某些tableview请求的数据量很大,或者数据短时间内变化不是很快的地方。 189 | - 用户下拉刷新表示重新请求数据,应该强制更新数据,不论本地是否有缓存,但是这部分数据应该存入数据库,保证退出后下次进入界面的时候能够读取最后更新的缓存。 190 | - 上拉加载更多的时候不读缓存,因为如果客户端自己在处理这部分逻辑比较复杂,不是说实现起来复杂,因为对于本地存储来说调用的是统一的一个方法,主要是因为如果用户下拉刷新需要强制更新数据,不论本地有无缓存,都要从服务器请求最新数据。那么问题来了,如果我把用户上拉加载更多时候的数据也存入本地,假设用户上拉加载了5页数据,然后又强制下拉刷新了一下,这个时候tableview显示的是最新的第一页数据,如果接着上拉加载更多我应该是读取缓存还是直接发起网络请求呢。毫无疑问应该直接发起请求,因为下拉强制刷新已经导致了第一页为最新数据,如果第2-5页数据缓存没有过期并且服务器数据确实变化了的话,客户端将得不到新的数据,**所以干脆仅仅第一次进入界面tableview请求第一页数据的时候要读缓存**。 191 | - 根本不用缓存的地方主要是某些数据变化非常快,或者发起的网络请求是一次性的操作,比如收藏某个题目等等。 192 | 193 |
194 | 195 | ## init方法私有化 196 | 197 | > SDK或者组件设计API相关 198 | 199 |
200 | 参考内容 201 | 202 | ```objc 203 | 204 | - (instancetype)init __attribute__((unavailable("Disabled. Use +sharedInstance instead"))); 205 | - (instancetype)init NS_UNAVAILABLE; 206 | 207 | 2.m 208 | //3. 内部不响应 不建议! 209 | - (instancetype)init { 210 | // 抛出不识别,没有说明真的原因 211 | [super doesNotRecognizeSelector:_cmd]; 212 | return nil; 213 | } 214 | 215 | // 通过断言 216 | - (instancetype)init{ 217 | NSAssert(false,@"unavailable, use sharedInstance instead"); 218 | return nil; 219 | } 220 | 221 | // 通过异常 222 | - (instancetype)init{ 223 | [NSException raise:NSGenericException format:@"Disabled. Use +[%@ %@] instead", 224 | NSStringFromClass([self class]), 225 | NSStringFromSelector(@selector(sharedInstance))]; 226 | return nil; 227 | } 228 | 229 | ``` 230 |
231 | 232 | ## 线程中栈与堆是公有的还是私有的 ? 233 | 234 | - 栈私有, 堆公有 235 | 236 | 237 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 238 | 239 |

240 | 241 |

242 | 243 | 244 | ## 链接 245 | 246 | - [面试题系列目录](../README.md) 247 | - **上一份**: [第四份:interview-iOS-4](04interview-iOS-4.md) 248 | - **下一份**: [第六份:iOS基础问题系列2017年:参考答案已更新完毕](06iOS基础问题系列2017年.md) 249 | 250 | -------------------------------------------------------------------------------- /interview-iOS/19新浪公司iOS面试题2019年6月.md: -------------------------------------------------------------------------------- 1 | ## 新浪公司iOS面试题2019年6月 2 | 3 | > 作者:路飞_Luck&&jianshu.com/p/f9ec208b00b6 4 | 5 | - [对象引用计数放哪里?](#对象引用计数放哪里) 6 | - [MVVM和MVC的区别](#mvvm和mvc的区别) 7 | - [UIButton防止多次点击](#uibutton防止多次点击) 8 | - [弱网相关](#弱网相关) 9 | - [卡顿检测](#卡顿检测) 10 | - [NSCache,NSDictionary,NSArray的区别](#nscachensdictionarynsarray的区别) 11 | - [SDWebImage里面用了哪种缓存策略?](#sdwebimage里面用了哪种缓存策略) 12 | - [self + weakSelf + strongSelf ?](#self-weakself-strongself) 13 | 14 | ### 对象引用计数放哪里? 15 | 16 |
17 | 参考内容 18 | 19 | * 可查阅objc相关源码:**struct** objc_class -> isa 20 | * isa 结构如下 21 | 22 | ``` 23 | /** isa_t 结构体 */ 24 | union isa_t { 25 | Class cls; 26 | uintptr_t bits; 27 | struct { 28 | uintptr_t nonpointer : 1; 29 | uintptr_t has_assoc : 1; 30 | uintptr_t has_cxx_dtor : 1; 31 | uintptr_t shiftcls : 33; 32 | uintptr_t magic : 6; 33 | uintptr_t weakly_referenced : 1; 34 | uintptr_t deallocating : 1; 35 | uintptr_t has_sidetable_rc : 1; 36 | uintptr_t extra_rc : 19; 37 | }; 38 | }; 39 | ``` 40 | * extra_rc:表示该对象的引用计数值,实际上是引用计数值减 1,例如,如果对象的引用计数为 10,那么 extra_rc 为 9。如果引用计数大于 10,则需要使用到下面的 has_sidetable_rc。 41 | * has_sidetable_rc:当对象引用计数大于 10 时,则has_sidetable_rc 的值为 1,那么引用计数会存储在一个叫 SideTable 的类的属性中,这是一个散列表。 42 | * 对象引用计数就存放在extra_rc中 43 |
44 | 45 | ### MVVM和MVC的区别 46 | 47 | > 参考内容较长,可直接看总结 48 | 49 |
50 | 参考内容 51 | 52 | - MVC:V()C (Update> && 一种可以很好地解决Massive View Controller问题的办法就是将 Controller 中的展示逻辑抽取出来,放置到一个专门的地方,而这个地方就是 viewModel 。MVVM衍生于MVC,是对 MVC 的一种演进,它促进了 UI 代码与业务逻辑的分离。它正式规范了视图和控制器紧耦合的性质,并引入新的组件。他们之间的结构关系如下: 68 | 69 | > ![](https://upload-images.jianshu.io/upload_images/1653926-7ed45d1af126df79.png?) 70 | 71 | - MVVM 基本概念 72 | - 在MVVM 中,view 和 view controller正式联系在一起,我们把它们视为一个组件 73 | view 和 view controller 都不能直接引用model,而是引用视图模型(viewModel) 74 | viewModel 是一个放置用户输入验证逻辑,视图显示逻辑,发起网络请求和其他代码的地方 75 | 使用MVVM会轻微的增加代码量,但总体上减少了代码的复杂性 76 | 77 | - MVVM 的注意事项 78 | * view 引用viewModel ,但反过来不行(即不要在viewModel中引入#import UIKit.h,任何视图本身的引用都不应该放在viewModel中)(PS:基本要求,必须满足) 79 | * viewModel 引用model,但反过来不行* MVVM 的使用建议 80 | * MVVM 可以兼容你当下使用的MVC架构。 81 | * MVVM 增加你的应用的可测试性。 82 | * MVVM 配合一个绑定机制效果最好(PS:ReactiveCocoa你值得拥有)。 83 | * viewController 尽量不涉及业务逻辑,让 viewModel 去做这些事情。 84 | * viewController 只是一个中间人,接收 view 的事件、调用 viewModel 的方法、响应 viewModel 的变化。 85 | * viewModel 绝对不能包含视图 view(UIKit.h),不然就跟 view 产生了耦合,不方便复用和测试。 86 | * viewModel之间可以有依赖。 87 | * viewModel避免过于臃肿,否则重蹈Controller的覆辙,变得难以维护。 88 | - MVVM 的优势 89 | * 低耦合:View 可以独立于Model变化和修改,一个 viewModel 可以绑定到不同的 View 上 90 | * 可重用性:可以把一些视图逻辑放在一个 viewModel里面,让很多 view 重用这段视图逻辑 91 | * 独立开发:开发人员可以专注于业务逻辑和数据的开发 viewModel,设计人员可以专注于页面设计 92 | * 可测试:通常界面是比较难于测试的,而 MVVM 模式可以针对 viewModel来进行测试 93 | - MVVM 的弊端 94 | 95 | * 数据绑定使得Bug 很难被调试。你看到界面异常了,有可能是你 View 的代码有 Bug,也可能是 Model 的代码有问题。数据绑定使得一个位置的 Bug 被快速传递到别的位置,要定位原始出问题的地方就变得不那么容易了。 96 | * 对于过大的项目,数据绑定和数据转化需要花费更多的内存(成本)。主要成本在于: 97 | * 数组内容的转化成本较高:数组里面每项都要转化成Item对象,如果Item对象中还有类似数组,就很头疼。 98 | * 转化之后的数据在大部分情况是不能直接被展示的,为了能够被展示,还需要第二次转化。 99 | * 只有在API返回的数据高度标准化时,这些对象原型(Item)的可复用程度才高,否则容易出现类型爆炸,提高维护成本。 100 | * 调试时通过对象原型查看数据内容不如直接通过NSDictionary/NSArray直观。 101 | * 同一API的数据被不同View展示时,难以控制数据转化的代码,它们有可能会散落在任何需要的地方。 102 | 103 | - 总结 104 | * MVC的设计模式也并非是病入膏肓,无药可救的架构,最起码目前MVC设计模式仍旧是iOS开发的主流框架,存在即合理。针对文章所述的弊端,我们依旧有许多可行的方法去避免和解决,从而打造一个轻量级的ViewController。 105 | 106 | * MVVM是MVC的升级版,完全兼容当前的MVC架构,MVVM虽然促进了UI 代码与业务逻辑的分离,一定程度上减轻了ViewController的臃肿度,但是View和ViewModel之间的数据绑定使得 MVVM变得复杂和难用了,如果我们不能更好的驾驭两者之间的数据绑定,同样会造成Controller 代码过于复杂,代码逻辑不易维护的问题。 107 | 108 | * 一个轻量级的ViewController是基于MVC和MVVM模式进行代码职责的分离而打造的。MVC和MVVM有优点也有缺点,但缺点在他们所带来的好处面前时不值一提的。他们的低耦合性,封装性,可测试性,可维护性和多人协作便利大大提高了开法效率。 109 | 110 | * 同时,我们需要保持的是一个拥抱变化的心,以及理性分析的态度。在新技术的面前,不盲从,也不守旧,一切的决策都应该建立在认真分析的基础上,这样才能应对技术的变化。 111 | 112 |
113 | 114 | 115 | ### UIButton防止多次点击 116 |
117 | 参考内容 118 | - userInteractionEnabled 119 | - 通过UIButton的enabled属性和userInteractionEnabled属性控制按钮是否可点击。 120 | - 此方案在逻辑上比较清晰、易懂,**但具体代码书写分散**,常常涉及多个地方。 121 | 122 | - cancelPreviousPerformRequestsWithTarget:selector:object 123 | - 总结:会出现延时现象,并且需要对大量的UIButton做处理,工作量大,不方便。 124 | 125 | ``` 126 | /** 方法一 */ 127 | - (void)tapBtn:(UIButton *)btn { 128 | NSLog(@"按钮点击了..."); 129 | // 此方法会在连续点击按钮时取消之前的点击事件,从而只执行最后一次点击事件 130 | [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(buttonClickedAction:) object:btn]; 131 | // 多长时间后做某件事情 132 | [self performSelector:@selector(buttonClickedAction:) withObject:btn afterDelay:2.0]; 133 | } 134 | 135 | - (void)buttonClickedAction:(UIButton *)btn { 136 | NSLog(@"真正开始执行业务 - 比如网络请求..."); 137 | } 138 | 139 | ``` 140 | - 通过Runtime交换UIButton的响应事件方法,从而控制响应事件的时间间隔。 141 | * 创建一个UIButton的分类,使用runtime增加public属性cs_eventInterval和private属性cs_eventInvalid。 142 | * 在+load方法中使用runtime将UIButton的-sendAction:to:forEvent:方法与自定义的cs_sendAction:to:forEvent:方法进行交换 143 | * 使用cs_eventInterval作为控制cs_eventInvalid的计时因子,用cs_eventInvalid控制UIButton的event事件是否有效。 144 | 145 | 146 | ``` 147 | 148 | @interface UIButton (Extension) 149 | 150 | /** 时间间隔 */ 151 | @property(nonatomic, assign)NSTimeInterval cs_eventInterval; 152 | 153 | @end 154 | 155 | static char *const kEventIntervalKey = "kEventIntervalKey"; // 时间间隔 156 | static char *const kEventInvalidKey = "kEventInvalidKey"; // 是否失效 157 | 158 | @interface UIButton() 159 | 160 | /** 是否失效 - 即不可以点击 */ 161 | @property(nonatomic, assign)BOOL cs_eventInvalid; 162 | 163 | @end 164 | 165 | @implementation UIButton (Extension) 166 | 167 | + (void)load { 168 | // 交换方法 169 | Method clickMethod = class_getInstanceMethod(self, @selector(sendAction:to:forEvent:)); 170 | Method cs_clickMethod = class_getInstanceMethod(self, @selector(cs_sendAction:to:forEvent:)); 171 | method_exchangeImplementations(clickMethod, cs_clickMethod); 172 | } 173 | 174 | 175 | 176 | - (void)cs_sendAction:(SEL)action to:(id)target forEvent:(UIEvent *)event { 177 | if (!self.cs_eventInvalid) { 178 | self.cs_eventInvalid = YES; 179 | [self cs_sendAction:action to:target forEvent:event]; 180 | [self performSelector:@selector(setCs_eventInvalid:) withObject:@(NO) afterDelay:self.cs_eventInterval]; 181 | } 182 | } 183 | 184 | 185 | 186 | - (NSTimeInterval)cs_eventInterval { 187 | return [objc_getAssociatedObject(self, kEventIntervalKey) doubleValue]; 188 | } 189 | 190 | - (void)setCs_eventInterval:(NSTimeInterval)cs_eventInterval { 191 | objc_setAssociatedObject(self, kEventIntervalKey, @(cs_eventInterval), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 192 | } 193 | 194 | - (BOOL)cs_eventInvalid { 195 | return [objc_getAssociatedObject(self, kEventInvalidKey) boolValue]; 196 | } 197 | 198 | - (void)setCs_eventInvalid:(BOOL)cs_eventInvalid { 199 | objc_setAssociatedObject(self, kEventInvalidKey, @(cs_eventInvalid), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 200 | } 201 | 202 | ``` 203 |
204 | 205 | ### 弱网相关 206 | 207 |
208 | 参考内容 209 | - 合适的超时时间,针对不同网络设定不同的超时时间,加快超时,尽快重试 210 | - 按子模块多请求去拉取数据,避免一次性加载,导致数据太多请求返回慢; 211 | - 缓存和增量请求 212 | - 优化DNS查询:应尽量减少DNS查询,做DNS缓存,避免域名劫持、DNS污染,同时把用户调度到“最优接入点”。 213 | - 减小数据包大小和优化包量:通过压缩、精简包头、消息合并等方式,来减小数据包大小和包量。 214 | - 优化ACK包:平衡冗余包和ACK包个数,达到降低延时,提高吞吐量的目的。(这些难度有点高) 215 | - 断线重连,因为我们是 socket 通信的,所以需要做断线重连,重连时间可以递增 216 | - 减少数据连接的创建次数,由于创建连接是一个非常昂贵的操作,所以应尽量减少数据连接的创建次数,且在 217 | - 一次请求中应尽量以批量的方式执行任务。如果多次发送小数据包,应该尽量保证在2秒以内发送出去。在短时间内访问不同服务器时,尽可能地复用无线连接。 218 | - 用户 UI 体验优化,加载一些动画什么的分散下注意力 219 | - 根据不同网络情况动态调节方案,比如图片下载和视频流就可以按照 3G 4G 和 WIFI 进行区分返回 220 | - HTTP3.0 221 |
222 | 223 | ### 卡顿检测 224 | 225 | - 通过监测Runloop的kCFRunLoopAfterWaiting,用一个子线程去检查,一次循环是否时间太长。 226 | - 如果超出预定时间,则可以dump堆栈,确定卡顿函数 227 | 228 | ### NSCache,NSDictionary,NSArray的区别 229 |
230 | 参考内容 231 | - NSArray 232 | - 在数组的开头和结尾插入/删除元素通常是一个O(1)操作,而随机的插入/删除通常是 O(N)的。 233 | - NSDictionary 234 | - NSDictionary中的键是被拷贝的并且需要是恒定的。如果在一个键在被用于在字典中放入一个值后被改变,那么这个值可能就会变得无法获取了。一个有趣的细节,在NSDictionary中键是被拷贝的,而在使用一个toll-free桥接的CFDictionary时却只被retain。CoreFoundation类没有通用对象的拷贝方法,因此这时拷贝是不可能的(*)。这只适用于使用CFDictionarySetValue()的时候。如果通过setObject:forKey使用toll-free桥接的CFDictionary,苹果增加了额外处理逻辑来使键被拷贝。反过来这个结论则不成立 — 转换为CFDictionary的NSDictionary对象,对其使用CFDictionarySetValue()方法会调用回setObject:forKey并拷贝键。 235 | - NSCache 236 | - 当系统资源将要耗尽时,NSCache可以自动删减缓存。如果采用普通的字典,那么就要自己编写挂钩,在系统通知时手动删减缓存,NSCache会先行删减 时间最久为被使用的对象 237 | - NSCache 并不会拷贝键,而是会保留它。此行为用NSDictionary也可以实现,但是需要编写比较复杂的代码。NSCache对象不拷贝键的原因在于,很多时候键都是不支持拷贝操作的对象来充当的。因此NSCache对象不会自动拷贝键,所以在键不支持拷贝操作的情况下,该类比字典用起来更方便 238 | - NScache是线程安全的,NSDictionary不是。在开发者自己不编写加锁代码的前提下,多个线程可以同时访问NSCache。对缓存来说,线程安全通常是很重要的,因为开发者可能在某个线程中读取数据,此时如果发现缓存里找不着指定的键,那么就要下载该键对应的数据了 239 | 240 |
241 | 242 | ### SDWebImage里面用了哪种缓存策略? 243 | 244 | - 使用了NSCache做缓存策略 245 | 246 | ### self + weakSelf + strongSelf ? 247 |
248 | 参考内容 249 | - 在 Block 内如果需要访问 self 的方法、变量,建议使用 weakSelf。 250 | - 如果在 Block 内需要多次 访问 self,则需要使用 strongSelf。 251 | 252 | ``` 253 | 1.使用__weak __typeof是在编译的时候,另外创建一个局部变量weak对象来操作self,引用计数不变。 254 | block 会将这个局部变量捕获为自己的属性, 255 | 访问这个属性,从而达到访问 self 的效果,因为他们的内存地址都是一样的。 256 | 257 | 2.因为weakSelf和self是两个变量,doSomething有可能就直接对self自身引用计数减到0了. 258 | 所以在[weakSelf doSomething]的时候,你很难控制这里self是否就会被释放了.weakSelf只能看着. 259 | 260 | 3.__strong __typeof在编译的时候,实际是对weakSelf的强引用. 261 | 指针连带关系self的引用计数会增加.但是你这个是在block里面,生命周期也只在当前block的作用域. 262 | 所以,当这个block结束, strongSelf随之也就被释放了.不会影响block外部的self的生命周期. 263 | 264 | __weak __typeof(self)weakSelf = self; //1 265 | 266 | [self.context performBlock:^{ 267 | [weakSelf doSomething]; //2 268 | __strong __typeof(weakSelf)strongSelf = weakSelf; //3 269 | [strongSelf doAnotherSomething]; 270 | }]; 271 | 272 | ``` 273 |
274 | 275 | ## 链接 276 | 277 | - [面试题系列目录](../README.md) 278 | - **上一份**: [苏州蜗牛iOS开发面试题2018年春](18苏州蜗牛iOS开发面试题2018年春.md) 279 | - **下一份**: [阿里字节一套高效的iOS面试题2020年2月](20阿里字节一套高效的iOS面试题2020年2月.md) 280 | 281 | ## 赞赏一下旺仔(收集整理不易,且赞且珍惜) 282 | 283 |

284 | 285 | 286 |

287 | -------------------------------------------------------------------------------- /interview-iOS/03interview-iOS-3.md: -------------------------------------------------------------------------------- 1 | 2 | # interview-iOS PartThree (profound understanding) 3 | 4 | - [SEL和Method和IMP?](#sel和method和imp) 5 | - [Autorelease的原理 ?](#autorelease的原理) 6 | - [ARC的工作原理](#arc的工作原理) 7 | - [weak弱引用的代码逻辑实现?](#weak弱引用的代码逻辑实现) 8 | - [大文件离线下载怎么处理?会遇到哪些问题?又如何解决](#大文件离线下载怎么处理会遇到哪些问题又如何解决) 9 | - [Socket建立网络连接的步骤](#socket建立网络连接的步骤) 10 | 11 | ## SEL和Method和IMP? 12 | > 谈下对IMP的理解? 13 | 14 |
15 | 参考内容 16 | 17 | - SEL是“selector”的一个类型,表示一个方法的名字 18 | - Method(我们常说的方法)表示一种类型,这种类型与selector和实现(implementation)相关 19 | - IMP定义为 **id (*IMP) (id, SEL, …)**。这样说来,**IMP是一个指向函数的指针**,这个被指向的函数包括id(“self”指针),调用的SEL(方法名),再加上一些其他参数.说白了**IMP就是实现方法**。 20 | 21 | > 知名框架AFN源码涉及IMP的代码 22 | 23 | ```objc 24 | NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; 25 | NSURLSession * session = [NSURLSession sessionWithConfiguration:configuration]; 26 | NSURLSessionDataTask *localDataTask = [session dataTaskWithURL:nil]; 27 | IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([self class], @selector(af_resume))); 28 | Class currentClass = [localDataTask class]; 29 | 30 | while (class_getInstanceMethod(currentClass, @selector(resume))) { 31 | Class superClass = [currentClass superclass]; 32 | IMP classResumeIMP = method_getImplementation(class_getInstanceMethod(currentClass, @selector(resume))); 33 | IMP superclassResumeIMP = method_getImplementation(class_getInstanceMethod(superClass, @selector(resume))); 34 | if (classResumeIMP != superclassResumeIMP && 35 | originalAFResumeIMP != classResumeIMP) { 36 | [self swizzleResumeAndSuspendMethodForClass:currentClass]; 37 | } 38 | currentClass = [currentClass superclass]; 39 | } 40 | 41 | [localDataTask cancel]; 42 | [session finishTasksAndInvalidate]; 43 | ``` 44 | 45 |
46 | 47 | ## Autorelease的原理 ? 48 |
49 | 参考内容 50 | 51 | > ARC下面,我们使用`@autoreleasepool{}`来使用一个Autoreleasepool,实际上UIKit 通过RunLoopObserver 在RunLoop二次Sleep间Autoreleasepool进行Pop和Push,将这次Loop产生的autorelease对象释放 对编译器会编译大致如下: 52 | 53 | ```objc 54 | 55 | void *DragonLiContext = objc_ AutoreleasepoolPush(); 56 | // {} 的 code 57 | objc_ AutoreleasepoolPop(DragonLiContext); 58 | 59 | ``` 60 | 61 | - 释放时机: 当前RunLoop迭代结束时候释放. 62 | 63 |
64 | 65 | 66 | ## ARC的工作原理 67 |
68 | 参考内容 69 | 70 | - Automatic Reference Counting,自动引用计数,即ARC,ARC会自动帮你插入retain和release语句,ARC编译器有两部分,分别是前端编译器和优化器 71 | - 前端编译器:前端编译器会为“拥有的”每一个对象插入相应的release语句。如果对象的所有权修饰符是__strong,那么它就是被拥有的。如果在某个方法内创建了一个对象,前端编译器会在方法末尾自动插入release语句以销毁它。而类拥有的对象(实例变量/属性)会在dealloc方法内被释放。事实上,你并不需要写dealloc方法或调用父类的dealloc方法,ARC会自动帮你完成一切。此外,由编译器生成的代码甚至会比你自己写的release语句的性能还要好,因为编辑器可以作出一些假设。在ARC中,没有类可以覆盖release方法,也没有调用它的必要。ARC会通过直接使用objc_release来优化调用过程。而对于retain也是同样的方法。ARC会调用objc_retain来取代保留消息 72 | 73 | - ARC优化器: 虽然前端编译器听起来很厉害的样子,但代码中有时仍会出现几个对retain和release的重复调用。ARC优化器负责移除多余的retain和release语句,**确保生成的代码运行速度高于手动引用计数的代码** 74 | 75 | 76 |
77 | 78 | 79 | ## weak弱引用的代码逻辑实现? 80 |
81 | 参考内容 82 | 83 | ```objc 84 | objc_storeWeak() 实现 85 | // HaveOld: true - 变量有值 86 | // false - 需要被及时清理,当前值可能为 nil 87 | // HaveNew: true - 需要被分配的新值,当前值可能为 nil 88 | // false - 不需要分配新值 89 | // CrashIfDeallocating: true - 说明 newObj 已经释放或者 newObj 不支持弱引用,该过程需要暂停 90 | // false - 用 nil 替代存储 91 | template bool HaveOld, bool HaveNew, bool CrashIfDeallocating> 92 | static id storeWeak(id *location, objc_object *newObj) { 93 | // 该过程用来更新弱引用指针的指向 94 | // 初始化 previouslyInitializedClass 指针 95 | Class previouslyInitializedClass = nil; 96 | id oldObj; 97 | // 声明两个 SideTable 98 | // ① 新旧散列创建 99 | SideTable *oldTable; 100 | SideTable *newTable; 101 | // 获得新值和旧值的锁存位置(用地址作为唯一标示) 102 | // 通过地址来建立索引标志,防止桶重复 103 | // 下面指向的操作会改变旧值 104 | retry: 105 | if (HaveOld) { 106 | // 更改指针,获得以 oldObj 为索引所存储的值地址 107 | oldObj = *location; 108 | oldTable = &SideTables()[oldObj]; 109 | } else { 110 | oldTable = nil; 111 | } 112 | if (HaveNew) { 113 | // 更改新值指针,获得以 newObj 为索引所存储的值地址 114 | newTable = &SideTables()[newObj]; 115 | } else { 116 | newTable = nil; 117 | } 118 | // 加锁操作,防止多线程中竞争冲突 119 | SideTable::lockTwoHaveOld, HaveNew>(oldTable, newTable); 120 | // 避免线程冲突重处理 121 | // location 应该与 oldObj 保持一致,如果不同,说明当前的 location 已经处理过 oldObj 可是又被其他线程所修改 122 | if (HaveOld && *location != oldObj) { 123 | SideTable::unlockTwoHaveOld, HaveNew>(oldTable, newTable); 124 | goto retry; 125 | } 126 | // 防止弱引用间死锁 127 | // 并且通过 +initialize 初始化构造器保证所有弱引用的 isa 非空指向 128 | if (HaveNew && newObj) { 129 | // 获得新对象的 isa 指针 130 | Class cls = newObj->getIsa(); 131 | // 判断 isa 非空且已经初始化 132 | if (cls != previouslyInitializedClass && 133 | !((objc_class *)cls)->isInitialized()) { 134 | // 解锁 135 | SideTable::unlockTwoHaveOld, HaveNew>(oldTable, newTable); 136 | // 对其 isa 指针进行初始化 137 | _class_initialize(_class_getNonMetaClass(cls, (id)newObj)); 138 | // 如果该类已经完成执行 +initialize 方法是最理想情况 139 | // 如果该类 +initialize 在线程中 140 | // 例如 +initialize 正在调用 storeWeak 方法 141 | // 需要手动对其增加保护策略,并设置 previouslyInitializedClass 指针进行标记 142 | previouslyInitializedClass = cls; 143 | // 重新尝试 144 | goto retry; 145 | } 146 | } 147 | // ② 清除旧值 148 | if (HaveOld) { 149 | weak_unregister_no_lock(&oldTable->weak_table, oldObj, location); 150 | } 151 | // ③ 分配新值 152 | if (HaveNew) { 153 | newObj = (objc_object *)weak_register_no_lock(&newTable->weak_table, 154 | (id)newObj, location, 155 | CrashIfDeallocating); 156 | // 如果弱引用被释放 weak_register_no_lock 方法返回 nil 157 | // 在引用计数表中设置若引用标记位 158 | if (newObj && !newObj->isTaggedPointer()) { 159 | // 弱引用位初始化操作 160 | // 引用计数那张散列表的weak引用对象的引用计数中标识为weak引用 161 | newObj->setWeaklyReferenced_nolock(); 162 | } 163 | // 之前不要设置 location 对象,这里需要更改指针指向 164 | *location = (id)newObj; 165 | } 166 | else { 167 | // 没有新值,则无需更改 168 | } 169 | SideTable::unlockTwoHaveOld, HaveNew>(oldTable, newTable); 170 | return (id)newObj; 171 | } 172 | 173 | ``` 174 | 175 | 176 |
177 | 178 | 179 | ## 大文件离线下载怎么处理?会遇到哪些问题?又如何解决 180 |
181 | 参考内容 182 | 183 | - NSURLSessionDataTask 大文件离线断点下载 (AFN等框架,旧的connection类已经废弃) 184 | 185 | - 内存飙升问题:(apple 默认实现机制导致),在下载文件的过程中,系统会先把文件保存在内存中,等到文件下载完毕之后再写入到磁盘! 在下载文件时,`一边下载一边写入到磁盘`,减小内存使用 186 | 187 | - 具体实现方法: 188 | - 1.`NSFileHandle` 文件句柄 189 | - 2.`NSOutputStream` 输出流 190 | 191 | ```objc 192 | // code copy from jianshu 193 | ///: 1. NSFileHandle 194 | -(void)URLSession:(NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask 195 | didReceiveResponse:(nonnull NSURLResponse *)response 196 | completionHandler:(nonnull void (^)(NSURLSessionResponseDisposition))completionHandler { 197 | //接受到响应的时候 告诉系统如何处理服务器返回的数据 198 | completionHandler(NSURLSessionResponseAllow); 199 | //得到请求文件的数据大小 200 | self.totalLength = response.expectedContentLength; 201 | //拼接文件的全路径 202 | NSString *fileName = response.suggestedFilename; 203 | NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; 204 | NSString *fullPath = [cachePath stringByAppendingPathComponent:fileName]; 205 | 206 | //【1】在沙盒中创建一个空的文件 207 | [[NSFileManager defaultManager] createFileAtPath:fullPath contents:nil attributes:nil]; 208 | //【2】创建一个文件句柄指针指向该文件(默认指向文件开头) 209 | self.handle = [NSFileHandle fileHandleForWritingAtPath:fullPath]; 210 | } 211 | -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { 212 | //【3】使用文件句柄指针来写数据(边写边移动) 213 | [self.handle writeData:data]; 214 | //累加已经下载的文件数据大小 215 | self.currentLength += data.length; 216 | //计算文件的下载进度 = 已经下载的 / 文件的总大小 217 | self.progressView.progress = 1.0 * self.currentLength / self.totalLength; 218 | } 219 | -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { 220 | //【4】关闭文件句柄 221 | [self.handle closeFile]; 222 | } 223 | ///:NSOutputStream 224 | -(void)URLSession:(NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask 225 | didReceiveResponse:(nonnull NSURLResponse *)response 226 | completionHandler:(nonnull void (^)(NSURLSessionResponseDisposition))completionHandler { 227 | //接受到响应的时候 告诉系统如何处理服务器返回的数据 228 | completionHandler(NSURLSessionResponseAllow); 229 | //得到请求文件的数据大小 230 | self.totalLength = response.expectedContentLength; 231 | //拼接文件的全路径 232 | NSString *fileName = response.suggestedFilename; 233 | NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; 234 | NSString *fullPath = [cachePath stringByAppendingPathComponent:fileName]; 235 | 236 | //(1)创建输出流,并打开 237 | self.outStream = [[NSOutputStream alloc] initToFileAtPath:fullPath append:YES]; 238 | [self.outStream open]; 239 | } 240 | -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { 241 | //(2)使用输出流写数据 242 | [self.outStream write:data.bytes maxLength:data.length]; 243 | //累加已经下载的文件数据大小 244 | self.currentLength += data.length; 245 | //计算文件的下载进度 = 已经下载的 / 文件的总大小 246 | self.progressView.progress = 1.0 * self.currentLength / self.totalLength; 247 | } 248 | -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { 249 | //(3)关闭输出流 250 | [self.outStream close]; 251 | } 252 | 253 | ``` 254 | 255 | - 开始(resume) | 暂停(suspend) | 取消( | 恢复等 256 | 257 | ``` 258 | [self.dataTask cancel]; 259 | //默认情况下取消下载不能进行恢复,若要取消之后还可以恢复,可以清空下载任务,再新建 260 | self.dataTask = nil; 261 | 262 | ``` 263 | 264 | - **下载进度值发生跳跃错乱** :已经下载的数据 / 文件的总数据,在第一个代理方法中,我们得到的文件大小并不是真正的文件大小,而是剩余未下载的大小,所以在第一次开始下载时,可以得到正确的数据,但是在下载过程中执行其他操作,就会使得到的数据大小发生变化,从而导致下载进度值出现问题 `解决方案`:`文件总大小 = 已经下载的数据 + 剩余未下载的数据` 265 | 266 | 267 | - 优化性能(句柄和流一样) 只有第一次接收到响应的时候才需要创建空的文件(lazy load ) 268 | 269 |
270 | 271 | 272 | ## Socket建立网络连接的步骤 273 | 274 |
275 | 参考内容 276 | 277 | 278 | > 建立Socket连接至少需要一对套接字,其中一个运行于客户端,称为ClientSocket ,另一个运行于服务器端,称为ServerSocket 。套接字之间的连接过程分为三个步骤:服务器监听,客户端请求,连接确认。(知名的框架 AsyncSocket) 279 | 280 | - 服务器监听:服务器端套接字并不定位具体的客户端套接字,而是处于等待连接的状态,实时监控网络状态,等待客户端的连接请求 281 | 282 | - 客户端请求:指客户端的套接字提出连接请求,要连接的目标是服务器端的套接字。为此,客户端的套接字必须首先描述它要连接的服务器的套接字,指出服务器端套接字的地址和端口号,然后就向服务器端套接字提出连接请求 283 | 284 | - 连接确认:当服务器端套接字监听到或者说接收到客户端套接字的连接请求时,就响应客户端套接字的请求,建立一个新的线程,把服务器端套接字的描述发给客户端,一旦客户端确认了此描述,双方就正式建立连接。而服务器端套接字继续处于监听状态,继续接收其他客户端套接字的连接请求 285 | 286 | - AsyncSocket 相关代码 287 | 288 | ``` 289 | 290 | // socket连接 291 | -(void)socketConnectHost{} 292 | self.socket = [[AsyncSocket alloc] initWithDelegate:self]; 293 | NSError *error = nil; 294 | [self.socket connectToHost:self.socketHost onPort:self.socketPort withTimeout:-1 error:&error]; 295 | } 296 | 297 | 心跳通过计时器来实现 // NStimer 298 | -(void)onSocket:(AsyncSocket *)sock didConnectToHost:(NSString *)host port:(UInt16)port 299 | { 300 | 301 | LFLog(@"socket连接成功"); 302 | // 每隔1s像服务器发送心跳包 303 | self.connectTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(longConnectToSocket) userInfo:nil repeats:YES]; 304 | // 在longConnectToSocket方法中进行长连接需要向服务器发送的讯息 305 | [self.connectTimer fire]; 306 | } 307 | 308 | // socket发送数据是以栈的形式存放,所有数据放在一个栈中,存取时会出现粘包的现象,所以很多时候服务器在收发数据时是以先发送内容字节长度,再发送内容的形式,得到数据时也是先得到一个长度,再根据这个长度在栈中读取这个长度的字节流,如果是这种情况,发送数据时只需在发送内容前发送一个长度,发送方法与发送内容一样 309 | NSData *dataStream = [@8 dataUsingEncoding:NSUTF8StringEncoding]; 310 | 311 | [self.socket writeData:dataStream withTimeout:1 tag:1]; 312 | // 接收数据 313 | 314 | -(void)onSocket:(AsyncSocket *)sock didReadData:(NSData *)data withTag:(long)tag 315 | { 316 | // 对得到的data值进行解析与转换即可 317 | [self.socket readDataWithTimeout:30 tag:0]; 318 | 319 | } 320 | 321 | ``` 322 | 323 |
324 | 325 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 326 | 327 |

328 | 329 |

330 | 331 | ## 链接 332 | 333 | - [面试题系列目录](../README.md) 334 | - **上一份**: [interview-iOS-2](02interview-iOS-2.md) 335 | - **下一份**: [interview-iOS-4](04interview-iOS-4.md) 336 | -------------------------------------------------------------------------------- /interview-iOS/12校招攻略43份优质面经汇总iOS开发2018年.md: -------------------------------------------------------------------------------- 1 | # 校招攻略43份优质面经汇总iOS开发2018年 2 | 3 | - [origin github link ](https://github.com/NtZheng/NTBlog/issues/2) 4 | 5 |

6 |

我是一名普通本科的大四学生(软件工程专业),应聘方向是iOS开发,我在招聘中一共面试了30家左右的公司,每次面试后,都及时进行面经整理和解答扩展,现在筛选出优质面经,将它们汇总,分享给大家

7 |

目录

8 |

实习面试

9 |
    10 |
  1. 百度
  2. 11 |
  3. 今日头条
  4. 12 |
  5. 饿了么
  6. 13 |
  7. SAP
  8. 14 |
  9. 360健康
  10. 15 |
16 |

校招面试

17 |
    18 |
  1. 阿里巴巴
  2. 19 |
  3. 百度
  4. 20 |
  5. 腾讯
  6. 21 |
  7. 美团点评
  8. 22 |
  9. 今日头条
  10. 23 |
  11. 京东
  12. 24 |
  13. 小米
  14. 25 |
  15. 迅雷
  16. 26 |
  17. 深信服
  18. 27 |
  19. 商汤科技
  20. 28 |
  21. 顺丰科技
  22. 29 |
  23. 招银网络
  24. 30 |
31 |

实习面试

32 |

百度

33 |

百度一面

34 |

iOS

35 | 43 |

计算机网络

44 | 52 |

算法

53 | 56 |

百度二面

57 |

iOS

58 | 82 |

算法

83 | 88 |

计算机网络

89 | 93 |

今日头条

94 |

今日头条一面

95 |

算法

96 | 99 |

iOS

100 | 111 |

计算机网路

112 | 115 |

今日头条二面

116 |

算法

117 | 120 |

iOS

121 | 125 |

今日头条三面

126 |

计算机网络

127 | 133 |

iOS

134 | 137 |

饿了么

138 |

饿了么一面

139 |

热身

140 | 146 |

数据库

147 | 153 |

计算机网络

154 | 160 |

iOS

161 | 177 |

算法

178 | 182 |

其他

183 | 187 |

饿了么二面

188 |

热身

189 | 198 |

设计

199 | 209 |

SAP

210 |

SAP一面

211 |

计算机网络

212 | 217 |

iOS

218 | 222 |

算法

223 | 226 |

SAP二面

227 |

计算机网络

228 | 234 |

算法

235 | 238 |

校招面试

239 |

阿里巴巴

240 |

阿里巴巴一面

241 |

自我介绍

242 |

...

243 |

数据库

244 | 248 |

操作系统

249 | 252 |

计算机网络

253 | 257 |

设计模式

258 | 263 |

iOS

264 | 278 |

java

279 | 283 |

算法

284 | 288 |

数据结构

289 | 292 |

阿里巴巴二面

293 |

闲聊

294 |

面:哈哈,看你很多地方都是这个名字,nineteen,你是很喜欢这个吗?

295 |

我:.......

296 |

面:那我们就直接进入正题吧

297 |

项目

298 | 304 |

算法

305 | 308 |

结尾

309 |

面:稍微等一下,这边安排一个加面

310 |

面:你赶紧吃个饭吧

311 |

我:哦好的......

312 |

阿里巴巴加面一

313 |

自我介绍

314 |

...

315 |

算法

316 | 319 |

编程

320 | 325 |

问题

326 | 337 |

阿里HR面

338 |

自我介绍

339 |

面:这是我今天听过的最简单的自我介绍

340 |

我:严肃脸

341 |

项目相关

342 |

公司实习相关

343 |

对自己的认识

344 |

阿里加面二

345 |

闲聊

346 |

晚上7点一个电话响起,铃铃铃~

347 |

面:现在又把你叫过来面试,你今天应该面了5轮吧

348 |

我:恩......

349 |

项目

350 | 361 |

实习

362 | 366 |

技术

367 | 373 |

自我认知

374 | 377 |

阿里补招一面

378 |

项目

379 | 383 |

iOS

384 | 392 |

阿里补招二面

393 |

热身

394 | 398 |

iOS

399 | 412 |

计算机基础

413 | 417 |

算法

418 | 421 |

项目

422 | 426 |

百度

427 |

百度一面

428 |

自我介绍

429 |

......

430 |

算法

431 | 434 |

项目

435 |

iOS

436 | 444 |

计算机网络

445 | 449 |

数据库

450 | 453 |

百度二面

454 |

自我介绍

455 |

面试官好像认识我的样子,并没有自我介绍环节

456 |

算法

457 | 461 |

iOS

462 | 465 |

计算机网络

466 | 470 |

设计模式

471 | 474 |

百度三面

475 |

技术相关

476 | 480 |

其他

481 | 506 |

腾讯

507 |

腾讯一面

508 |

自我介绍

509 |

......

510 |

闲聊

511 | 515 |

计算机网络

516 | 521 |

项目

522 | 525 |

iOS

526 | 532 |

结尾

533 | 539 |

腾讯二面

540 |

自我介绍

541 |

项目

542 | 545 |

按照简历问

546 | 554 |

美团点评

555 |

美团点评一面

556 |

自我介绍

557 |

......

558 |

iOS基础

559 | 569 |

iOS项目

570 | 574 |

算法

575 | 578 |

计算机网络

579 | 582 |

美团点评二面

583 |

自我介绍

584 |

面:这边没有找到你的简历

585 |

我:啊?那会不会没有优势啊

586 |

面:不会的,讲的好就行

587 |

iOS

588 | 591 |

操作系统

592 | 595 |

计算机网络

596 | 602 |

智力题

603 | 606 |

算法

607 | 610 |

美团点评三面

611 |

自我介绍

612 |

面:没有我的简历

613 |

我:我用手机传一份吧

614 |

于是加了微信

615 |

项目

616 | 626 |

技术相关

627 | 633 |

产品经理

634 | 640 |

个人

641 | 647 |

美团点评HR面

648 |

闲聊

649 | 654 |

问题

655 | 660 |

项目

661 | 664 |
提问
665 | 670 |

今日头条

671 |

今日头条一面

672 |

自我介绍

673 | 676 |

算法

677 | 681 |

操作系统

682 | 686 |

iOS

687 | 694 |

今日头条二面

695 |

算法

696 | 699 |

iOS

700 | 707 |

今日头条三面

708 |

算法

709 | 712 |

闲聊

713 | 719 |

iOS

720 | 725 |

计算机网络

726 | 730 |

京东

731 |

京东一面

732 |

自我介绍

733 |

......

734 |

项目

735 | 738 |

iOS

739 | 750 |

小米

751 |

小米一面

752 |

自我介绍

753 |

......

754 |

问:面试官您是从事什么岗位的呢

755 |

面:我是后台开发的

756 |

我:......

757 |

算法

758 | 761 |

计算机网络

762 | 765 |

项目

766 |

小米二面

767 |

闲聊

768 |

问: 面试官您是从事什么岗位的呢

769 |

面:Andriod系统层开发

770 |

我:......

771 |

算法

772 | 775 |

java多线程

776 | 779 |

java基础

780 | 783 |

项目

784 |

迅雷

785 |

迅雷一面

786 |

自我介绍

787 |

......

788 |

iOS

789 | 796 |

项目

797 | 800 |

算法

801 | 804 |

深信服

805 |

深信服一面

806 |

自我介绍

807 |

......

808 |

面前摆放着一台联想笔记本

809 |

我:面试官是做什么开发的

810 |

面:我是做Linux开发的

811 |

我:......

812 |

面试体验

813 | 816 |

算法

817 | 825 |

笔试题(可能测试是否作弊)

826 | 831 |

C语言

832 | 837 |

数据库

838 | 841 |

深信服二面

842 |

自我介绍

843 |

......

844 |

我:面试官您是做什么的岗位的呢

845 |

面:哦,我不是iOS的,可能没法面iOS方面的,我们就问一些算法吧

846 |

我:......

847 |

面试体验

848 | 852 |

算法

853 | 858 |

商汤科技

859 |

商汤科技一面

860 |

自我介绍

861 |

面:不好意思,我这边好像找不到你的简历了,所以你得比较详细地介绍一下你自己

862 |

我:......

863 |

算法

864 |

数羊,给定一个初始数N,第一次数的数为N,第二次为2N,依次类推,直到kN,那么求当0-9的数全部都出现的时候的k值

865 |

iOS

866 | 875 |

商汤科技二面

876 |

自我介绍

877 |

我:接触iOS开发三年,上架的项目有5个...
878 | 面:哇,你比我开发还久,我上架项目也没有你多(见笑了大佬),不过我是做底层SDK开发的

879 |

算法

880 | 887 |

设计模式

888 | 894 |

计算机网络

895 | 900 |

操作系统

901 | 904 |

iOS

905 | 918 |

商汤科技三面

919 |

自我介绍

920 |

我:开发过五个上架APP

921 |

面:哇,这么多

922 |

项目

923 | 931 |

技术

932 | 936 |

人生

937 | 942 |

商汤科技HR面

943 | 952 |

顺丰科技

953 |

顺丰科技一面

954 |
自我介绍
955 |

......

956 |

项目

957 | 960 |

计算机网络

961 | 964 |

Java

965 | 968 |

设计模式

969 | 977 |

算法

978 | 982 |

iOS

983 | 987 |

顺丰科技HR面

988 |

自我介绍

989 |

......

990 |

项目

991 | 994 |

闲聊

995 | 1004 |

我的提问

1005 | 1011 |

招银网络

1012 |

招银网络一面

1013 |

自我介绍

1014 |

......

1015 |

项目

1016 | 1021 |

iOS

1022 | 1029 |

招银网络二面

1030 |

自我介绍

1031 |

面:你面试这么多了,自我介绍太累了,就省去吧

1032 |

我:(中国好面试官!)

1033 |

项目

1034 | 1039 |

招银网络HR面

1040 |

自我介绍

1041 |

.....

1042 |

项目

1043 | 1046 |

闲聊

1047 | 1054 |

结尾

1055 |

看到这里的童鞋们,预祝你们秋招成功,成为Offer收割机!
1056 | 点个赞吧~

1057 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | ### 觉得整理的蛮不错,可以赞赏一下旺仔(收集整理不易,且赞且珍惜) 1066 | 1067 |

1068 | 1069 |

1070 | 1071 | ## 链接 1072 | 1073 | - [面试题系列目录](../README.md) 1074 | - **上一份**: [天猫蚂蚁金服百度面试题2018年4月](11天猫蚂蚁金服百度面试题2018年4月.md) 1075 | - **下一份**: [秋招iOS面试总结2018年](13秋招iOS面试总结2018年.md) 1076 | --------------------------------------------------------------------------------