关于ios:cocoapod出问题重装过程

明天想应用Realm,pod install之后发现pod版本过低了,尝试更新pod之后,pod忽然出了问题,执行pod install就始终失败。只好重新安装1.尝试应用 sudo gem install cocoapods始终失败,报错相似"Failed to build gem native extension",看问题仿佛是ruby有问题,但通过查问ruby版本没问题,不过重新安装仿佛也始终不胜利,而后尝试用brew 装置2.brew install cocoapods这个一开始也是始终报错,失败。我在想是不是真的ruby不对,先尝试应用brew重装ruby试下3.brew install ruby这个装的货色巨多,但装置还算顺利,我装置了ruby一半,尝试从新执行步骤2去装置pod,发现可能是ruby环境失常了,pod装置胜利了。但还是报错“Error: The brew link step did not complete successfullyThe formula built, but is not symlinked into /usr/localCould not symlink bin/xcodeproj”Target /usr/local/bin/xcodeprojalready exists. You may want to remove it: rm '/usr/local/bin/xcodeproj' To force the link and overwrite all conflicting files: brew link --overwrite cocoapods To list all files that would be deleted: brew link --overwrite --dry-run cocoapods ...

January 24, 2022 · 1 min · jiezi

关于ios:iOS-逆向之hook系统app

要想注入零碎app,首先的找到适合的切入点,如何找到切入点,最开始想到的时候class-dump一下零碎的程序,就要去找到程序所在中央,这里以SpringBoard为例1.通过ssh 登录到手机,ps -el |grep Spring失去地位/System/Library/CoreServices/SpringBoard.app,找到程序.2.通过class-dump导出头文件,发现啥也没有,最初用mach-o发现,代码都在另外一个第三方库里,找到这个第三方库也没找到对应的头文件,可能还在更深处.3.经他人点拨得悉,只有iOS9及其以下,库里能力dump出残缺的头文件,iOS9当前都扩散在各个第三方库里,找起来简单很多. 有一个简略的形式找头文件,谷搜寻SpringBoard.h第一个、第二个答案,前人曾经dump好了,就不须要咱们去dump了.地址:https://github.com/MP0w/iOS-H...

January 16, 2022 · 1 min · jiezi

关于ios:iOS-逆向之unicorn-模拟执行

IDA遇到hariki等等各种工具的混同,字符串被加密,难以看出加密之后的字符串.如何失去该字符串.能够试着尝试unicorn模仿执行脚本. 1.用pip装置unicorn,留神pip版本必须是2.x+版本.如果没有请参照:pip装置教程装置. pip install unicorn2.依据unicorn,编写python脚本,这里在网上找了一个脚本: #!/usr/bin/env python2# -*- coding: utf-8 -*-# @Author: smartdone# @Date: 2019-07-01 11:00import idaapiimport idautilsimport idcfrom Simulator import *#from capstone import *sys.path.append('/usr/local/lib/python2.7/site-packages/')addr = 0x100075B00PatchDword(addr,0)print(addr, 0)sim = Simulator()sim.sp = 4sim.arch = UC_ARCH_ARM64sim.mode = UC_MODE_ARMfor func in idautils.Functions(): func_name = idc.GetFunctionName(func) func_data = idaapi.get_func(func) start = func_data.start_ea end = func_data.end_ea# print(func_name, hex(start), hex(end))# if "ijm_obf_fun_globalstub_" in func_name : print(func_name, hex(start), hex(end)) start = 0x0000000100006AC8 end = 0x0000000100006B70 sim.emu_start(start, end) break# start=0x00000000002B8B7C# end=0x00000000002B9BA0 sim.patch_segment('data')for seg in sim.segments: if "data" in seg['name']: # 把data段全副undefined print("MakeUnknown %s" % seg['name']) idc.MakeUnknown(seg['start'], seg['end'] - seg['start'], idaapi.DELIT_DELNAMES) # 调用ida从新解析data段 print("analyze area: 0x%x - 0x%x" % (seg['start'], seg['end'])) idaapi.analyze_area(seg['start'], seg['end']) # idaapi.clear_strlist() # idaapi.build_strlist()# 查问string的穿插援用,在援用地位增加备注s = idautils.Strings(False)s.setup()for i, str_info in enumerate(s): if str_info: # print("%x: len=%d index=%d-> '%s'" % (str_info.ea, str_info.length, i, str(str_info))) str_cont = str(str_info) refs = idautils.DataRefsTo(str_info.ea) for ref in refs: idc.MakeComm(ref, str_cont)通过管制脚本里的 start和end地址 start = 0x0000000100006AC8、end = 0x0000000100006B70,就能够模仿执行对应的地址的代码,最终出现成果比照图: ...

January 14, 2022 · 4 min · jiezi

关于ios:尝试输入密码的次数太多-还原-Apple-Watch-并重新配对的正确解法

请拜访原文链接:https://sysin.org/blog/apple-...,查看最新版。原创作品,转载请保留出处。 作者:gc(at)sysin.org,主页:www.sysin.org 阐明:本文实用于 watchOS 7 和 iOS 14,不排除将来产品更新以致操作方法有所变更。 今日一不小心也中招,如图。开始搜寻一通,排在后面的全副是谬误解法。切实无语... 正确官网解法如下:https://support.apple.com/zh-... 操作步骤: 将手表放在充电器上,直到您实现这些步骤为止。按住侧边按钮,直到您看到“关机”。按住数码表冠,直到您看到“抹掉所有内容和设置”。轻点“还原”,而后再次轻点“还原”以确认。期待这个过程实现,而后从新设置您的 Apple Watch。零碎提醒时,请抉择从备份复原。“抹掉所有内容和设置”会抹掉 Apple Watch 上的所有媒体、数据和设置,但不会移除激活锁。要移除激活锁,请先勾销配对手表。在抹掉手表之前,您的 iPhone 上会创立手表内容的备份。 要点提醒: 肯定要先连贯充电器,没有充电器,操作有效。按住侧边按钮呈现“关机”界面后,要按数码表冠,不是所谓按屏幕的“关机”。这样不会移除激活锁,不会让你捡到宝。关上 iPhone 上的 Watch app 勾销配对手表,会提醒输出 iCloud 账号。从新配对,跟新的 Watch 一样操作。会提醒从备份中复原,所有数据和设置都在,主动备份的。 移除多余的备份: 提醒从备份中复原,可能发现有好几个备份能够抉择,抉择最近工夫的备份即可,多余的备份能够按以下步骤移除: 设置 > 通用 > iPhone 存储空间 > Watch 能够看到有多个备份列表,要删除某个备份,向左侧滑动,呈现删除按钮,确认删除即可。

December 31, 2021 · 1 min · jiezi

关于ios:iOS-app卡住了该如何排查问题

如果是本人的工程的话,1.如果在运行状态下,能够间接Pause program excution,能够查看停在什么中央,2.如果没有在运行状态下,能够在xcode-->debug-->attach to process抉择过程

December 21, 2021 · 1 min · jiezi

关于ios:iOS-无网和mac端也无网用websocket通讯

最近tx投诉咱们的产品须要手机和电脑在一个网络下,能力发动工作无网状况下,或者网络限度状态下,如何能力建设连贯:1.ios端建设一个绑定127.0.0.1或0.0.0.0 ip的websocket服务,假websocket端口为6037,即在手机端起一个地址为ws://127.0.0.1:6037的websocket服务,这个益处就是不须要网络都能够起气来.2.mac启动终端用iproxy进行转发,终端输出iproxy 30010 60373.mac端即可通过:ws://127.0.0.1:30010去拜访 iOS端的websocket服务. ps:iproxy貌似是只能通过127.0.0.1去拜访,阐明转发端口,是间接转发的这个127.0.0.1的ip,而不是所有ip

December 16, 2021 · 1 min · jiezi

关于ios:如何使用dSYM符号化crash日志解析线上crash

如何应用dSYM符号化crash日志。解析线上crash1 获取未解析的crash日志。2 获取dSYM文件3 应用xcode的symbolicatecrash工具进行符号化 3.1 找到symbolicatecrash3.2 将crash, dSYM,symbolicatecrash搁置在同一个文件夹3.3 执行命令,生成符号化的文件4 常见问题 4.1 Error: "DEVELOPER_DIR" is not defined at ./symbolicatecrash4.2 Warning: Unable to symbolicate from required binary: ~/Xcode/iOS DeviceSupport/13.6 (17G68) arm64e/Symbols/System/Library/Frameworks/CFNetwork.framework/CFNetwork 4.21 如何查看uuid dsym的uuidcrash日志的uuid1 获取未解析的crash日志。iPhone连贯mac,从Xcode->Window->Devices View Device Logs ,能够下载在此iPhone上过后crash的日志。 2 获取dSYM文件每次编译我的项目,生成一个与APP同名的dSYM文件。 不同的公司,用不同的形式打包。如果自动化流程做得好,通常是有集群的,找到相应的dsym文件下载即可。命名通常是XXX.app.dSYM 3 应用xcode的symbolicatecrash工具进行符号化3.1 找到symbolicatecrash关上终端输出命令: find /Applications/Xcode.app -name symbolicatecrash -type f我的mac呈现的后果: /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/iOSSupport/Library/PrivateFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrash/Applications/Xcode.app/Contents/Developer/Platforms/WatchSimulator.platform/Developer/Library/PrivateFrameworks/DVTFoundation.framework/symbolicatecrash/Applications/Xcode.app/Contents/Developer/Platforms/AppleTVSimulator.platform/Developer/Library/PrivateFrameworks/DVTFoundation.framework/symbolicatecrash/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/Library/PrivateFrameworks/DVTFoundation.framework/symbolicatecrash/Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/symbolicatecrashmac, 手机,模拟器等不同的版本。如果是iPhone真机就抉择最初一个。关上门路: /Applications/Xcode.app/Contents/SharedFrameworks/DVTFoundation.framework/Versions/A/Resources/将symbolicatecrash复制进去。 3.2 将crash, dSYM,symbolicatecrash搁置在同一个文件夹比方我搁置在了 /Users/kqy/Documents/crashProblem12113.3 执行命令,生成符号化的文件./symbolicatecrash my.crash my1211.app.dSYM > result.crash其中my.crash是crash日志;my1211.app.dSYM是dSYM文件。 所有命令汇聚一张图 4 常见问题4.1 Error: "DEVELOPER_DIR" is not defined at ./symbolicatecrash解决办法是在终端执行命令: ...

December 11, 2021 · 1 min · jiezi

关于ios:iOS边下边播总结

边下边播总结(一)概述最近批改了我的项目中的视频播放性能, 由之前的全量下载完再播, 改为了边下边播的形式. 因为咱们我的项目中的视频在收回时都进行了加密, 所以整个过程其实就是边下载边解密边播放. 边下边播的技术计划, 网上的博客很容易搜到, 不外乎两种形式, 内置本地代理服务器和AVAssetResourceLoader. 咱们采取了零碎提供的AVAssetResourceLoader这一计划. 计划原理具体的AVAssetResourceLoader实现原理网上能够找到很多逻辑图, 如下图(来自网络)所示. 这里联合咱们的理论代码简略的介绍一个这个图片. 在平时应用AVPlayer播放url时, 咱们会这样创立一个播放器(简略) let videoAsset = AVURLAsset(url: "http://resource_url/xxxxx")let item = AVPlayerItem(asset: videoAsset)let player = AVPlayer(playerItem: item)如果咱们这样设置播放, 整个播放的外部流程其实都咱们都是不可见的, 视频的下载和缓存等, 咱们只能通过已知的一些办法,来管制播放器的播放暂停等. 如果想要实现咱们我的项目中想要的成果, 边下载边播放, 同时, 咱们可能须要接手视频的缓存这一模块, 所以咱们就必须得能进入到整个播放流程中, AVAssetResourceLoader其实就算是苹果给咱们留的一个小口子, 而后通过设置恪守AVAssetResourceLoaderDelegate这一协定的代理对象, 接手数据处理的这一过程(包含获取数据和向播放器填充数据). videoAsset.resourceLoader.setDelegate(self, queue: queue)注意事项 要进入到 AVAssetResourceLoader的代理回调, 除了要给videoAsset.resourceLoader设置delegate之外, 还须要把咱们的url改为不能辨认的scheme. 咱们一遍的资源门路都是http或者https, 咱们须要把url的scheme改为不能辨认的(公有的), 比方http://resource/xxx/xxx.mp4改为http-prefix://reource/xxxx/xxx.mp4url门路的最初必须要有视频的后缀, 相似.mp4, 我之前应用的资源门路是没有后缀的, 导致了播放器无奈起播.AVAssetResourceLoaderDelegateAVAssetResourceLoaderDelegate有两个罕用的回调办法如下 // MARK: - AVAssetResourceLoaderDelegatefunc resourceLoader(_ resourceLoader: AVAssetResourceLoader, shouldWaitForLoadingOfRequestedResource loadingRequest: AVAssetResourceLoadingRequest) -> Bool {}func resourceLoader(_ resourceLoader: AVAssetResourceLoader, didCancel loadingRequest: AVAssetResourceLoadingRequest) {}当播放器开始播放的时候, 会通过shouldWaitForLoadingOfRequestedResource这个回调办法向咱们索要数据, 具体所要数据的信息细节都封装在loadingRequest外面. 因为这个回调会走很屡次, 上图中示意的是要保存起来每一次的loadingRequest, 但在理论我的项目中, 我应用了不太一样的策略, 我把每一次loadingRequest都对应一个worker对象来解决, 这样每次索要数据, 都有一个独自的worker来解决绝对应的网络申请(暂不思考缓存), 这样比拟条理. 同时咱们也须要保留起咱们的worker, 因为如果播放器须要反对进度条拖动时, 须要手动seek到某一个地位, 这样会触发didCancel这个回调, 所以咱们也须要把咱们对应的worker外部停掉. ...

December 10, 2021 · 1 min · jiezi

关于ios:iOS-Pod-Update-指数级变慢看-Flutter-新一代仲裁算法-Pubgrub-如何解

作者:洪尉(洪茶) 如果你是一名iOS程序员,或者你对包治理技术感兴趣,举荐你浏览本文。你能够理解到iOS版本仲裁的底层原理、它的潜在性能危险 、以及如何预防Pod update的性能好转,从而对CocoaPods有更深刻的了解。此外,你还能理解到利用在Flutter的新一代的版本仲裁算法Pubgrub,以及不同技术栈依赖管理策略的差别,从而对包治理技术畛域有更全面的了解。 Pod Update 慢了8倍!!!周五早晨,帅帅在iOS群求助:“我主工程跑Pod update,始终卡着不动,有人遇到过吗?好奇怪!CPU被Ruby过程占满,但没有任何网络申请。”小明看了帅帅的截图,回了一句:“我遇到过,这是失常的,CocoaPods在做解决依赖”。帅帅只好无奈地承受了漫长的期待。 第二天早上,我看到昨晚群里的音讯,感觉有点奇怪,于是关上终端尝试更新Pod环境,工作运行后始终卡了很久。 依据运行日志,Pod更新总共耗时872S,其中“版本仲裁”过程耗时810秒。下一步,我切到旧版本进行比照测试,旧版本"版本仲裁"耗时120S,其余阶段工夫差不多,也就是说新版本“版本仲裁”好转验证,相比旧版本耗时涨了8倍! 接着我应用二办法比照各个commit,最初发现其中一个commit导致了“版本仲裁”变慢,它减少了几个模块的依赖,这会扭转主工程间接依赖的关系,从而扭转CocoaPods版本仲裁的搜寻程序。因为CocoaPods输入的日志不蕴含版本仲裁的过程,须要进一部剖析Cocapods的源码逻辑。 [CP cost] prepare :0.002s [CP cost] resolve_dependencies :810.734s [CP cost] download_dependencies :20.774s ... [CP cost] Total :872.28s 剖析版本仲裁的底层逻辑打印依赖抵触的搜寻门路CocoaPods版本仲裁性能基于Molinillo实现,须要剖析和调试Molinillo源码。不理解依赖仲裁工具的读者请先查看文末《附录2:依赖仲裁工具的职责》 。 首现下载Molinillo和CocoaPods源码到本地门路,而后批改Gemfile文件的依赖申明,将版本依赖批改为本地门路依赖。 gem 'molinillo', :path=>'/.../Molinillo'gem 'cocoapods', :path=>'/.../CocoaPods'版本仲裁的入口代码在 resolution.rb 文件的 Resolver 函数,为了剖析仲裁时具体搜寻门路,我将仲裁过程解决的包名和未解决的需要数量都通过日志打印进去。 def resolve # 初始化依赖图和依赖栈 start_resolution while state break if !state.requirement && state.requirements.empty? indicate_progress # 打印以后未解决的需要的数量 puts "BT:requirements.length" + state.requirements.length # 打印以后需要的模块名 puts "BT:requirement" + state.requirement if state.respond_to?(:pop_possibility_state) # DependencyState state.pop_possibility_state.tap do |s| if s states.push(s) activated.tag(s) end end end # 解决栈顶的模块申明 process_topmost_state end # 遍历依赖图 resolve_activated_specsensure end_resolutionend呈现抵触后Cocopod会调用create_conflict函数解决,我同样将仲裁过程解决的包名和未解决的需要数量都打印进去。 ...

December 3, 2021 · 2 min · jiezi

关于ios:苹果关闭-iOS-151-系统验证通道已升级用户无法降级

11 月 18 日,苹果公布了  iOS 15.1.1,依据苹果的公布阐明,iOS 15.1.1 修复了 iPhone 12 和 iPhone 13 的呼叫时掉话问题,以及惯例的谬误修复。 12 月 1 日,苹果公司进行了对 iOS 15.1 的验证。这意味着更新到 iOS 15.1.1 或 iOS 15.2 测试版的用户无奈再降级到 iOS 15.1 版本,一旦呈现了问题,只能等后续苹果公布新的iOS版本。 苹果通常会在推送正式版更新之后的几周内进行对旧版 iOS 的验证。对于一些更新至最新 iOS 零碎的用户,当其遇到重大 Bug 时,降级的形式有时会非常无效。这也是苹果在敞开旧版 iOS 系统验证通道之前会期待一段时间的起因。 此外,iOS 15.1 新增了同播共享性能,还退出了在 iPhone 13 Pro 和 iPhone 13 Pro Max 上拍摄 ProRes 视频的性能。同时,苹果钱包中引入了可验证 COVID-19 疫苗接种卡,这也是该更新公布后的第一个谬误修复版本。

December 2, 2021 · 1 min · jiezi

关于ios:iOS逆向之断点技巧

如何断在没有源码的第三方库里,这里波及到lldb命令:br s -a +函数地址如何取得函数地址:1.能够通过IDA查找2.能够通过打断点到他的上级调用函数在函数栈切换成汇编模式能力看到函数起始地址@1.xcode-->Debug-->Debug Workflow->Always Show Disassembly查看汇编@2.已知0x100f0a2b0为函数的起始地址@3.通过函数地址-ASLR=函数mach-o的地址,通过image list -o -f |grep +二进制名可获取ASLR随机地址可得ASLR = 0x0000000000f00000mach-o地址=函数地址-ASLR = 0x100f0a2b0 - 0x0000000000f00000=0x10000A2B0@4.当前每次启动的时候通过br s -a ASLR+mach-o地址即可针对函数打上断点

December 1, 2021 · 1 min · jiezi

关于ios:关于-Github-打不开无法打开无法访问访问不了解决方案

前言Github 时常抽风,不是加载慢就是打不开,本文分享一个不必搭梯子就能解决的方法。 具体操作关上终端输出sudo vi /etc/hosts输出本机明码此时终端关上了 Host 文件,输出i进入编辑模式 应用站长工具https://tool.chinaz.com/dns/?...获取 TTL值较高的 DNS 输出终端内如: 66.249.89.104 github.com52.69.186.44 github.com编辑实现后,应用 Control + C 退出编辑模式输出:wq保留并退出

December 1, 2021 · 1 min · jiezi

关于ios:iOS对图片进行像素读取

图片解码常见的图片压缩格局次要是PNG和JPEG,在iOS的程序开发中,个别不须要获取一张图片解码后的数据,但如果须要对像素进行操作,可能就须要理解怎么获取相干的像素值。位图图像(bitmap),是由多个像素点排列组成的。当咱们对PNG和JPG进行解码后,应该获取到一组像素点数据,这样一组数据就组成了解码后的位图。图片解码能够看做一次解压缩,所以位图占用的空间会更大,位图所占的空间很好计算,图片的面积*每个像素占用的字节。+ (nullable UIImage *)imageWithContentsOfFile:(NSString *)path; 通常会应用 imageWithContentsOfFile 来加载一张图片,这样创立 UIImage 时并不会在这里进行解码, 当 UIImage 被绘制时才会解码。 CGImageCGImage 的解释是位图或者图片蒙版,也就是说能够通过 CGImage 来读取像素值。当间接对 CGImage 的像素读取时能够应用上面的形式。 NSData *imageData = [NSData dataWithContentsOfFile:imagePath];CFDataRef dataRef = (__bridge CFDataRef)imageData;CGImageSourceRef source = CGImageSourceCreateWithData(dataRef, nil);CGImageRef cgImage = CGImageSourceCreateImageAtIndex(source, 0, nil);width = (int)CGImageGetWidth(cgImage);height = (int)CGImageGetHeight(cgImage);size_t pixelCount = width * height;CGDataProviderRef provider = CGImageGetDataProvider(cgImage);CFDataRef data = CGDataProviderCopyData(provider);CFRelease(data);CGImageRelease(cgImage); CFRelease(source);这种读取像素的形式无奈指定色彩格局,而是读取图片原有的色彩空间所组成像素的组合。须要留神的是,所有创立进去的数据都须要调用相应的release来进行开释。这里创立 CGImage 的办法也能够对 CGImage 的缓存形式进行设置。而且当咱们从 CGImage 的 dataProvider 中获取数据时,目前只能拷贝一份到 CFDataRef 中,而无奈间接读取。 CGBitmapContext以 RGB 色彩空间为例, 色彩相干的数据可能有以上这么多,CGImage 有相干的办法能够读取相应的数据,但有些办法iOS12之后才反对。 typedef CF_ENUM(uint32_t, CGImageAlphaInfo) { kCGImageAlphaNone, /* For example, RGB. */ kCGImageAlphaPremultipliedLast, /* For example, premultiplied RGBA */ kCGImageAlphaPremultipliedFirst, /* For example, premultiplied ARGB */ kCGImageAlphaLast, /* For example, non-premultiplied RGBA */ kCGImageAlphaFirst, /* For example, non-premultiplied ARGB */ kCGImageAlphaNoneSkipLast, /* For example, RBGX. */ kCGImageAlphaNoneSkipFirst, /* For example, XRGB. */ kCGImageAlphaOnly /* No color data, alpha data only */};typedef CF_ENUM(uint32_t, CGImageByteOrderInfo) { kCGImageByteOrderMask = 0x7000, kCGImageByteOrderDefault = (0 << 12), kCGImageByteOrder16Little = (1 << 12), kCGImageByteOrder32Little = (2 << 12), kCGImageByteOrder16Big = (3 << 12), kCGImageByteOrder32Big = (4 << 12)} CG_AVAILABLE_STARTING(10.0, 2.0);typedef CF_ENUM(uint32_t, CGImagePixelFormatInfo) { kCGImagePixelFormatMask = 0xF0000, kCGImagePixelFormatPacked = (0 << 16), kCGImagePixelFormatRGB555 = (1 << 16), /* Only for RGB 16 bits per pixel */ kCGImagePixelFormatRGB565 = (2 << 16), /* Only for RGB 16 bits per pixel */ kCGImagePixelFormatRGB101010 = (3 << 16), /* Only for RGB 32 bits per pixel */ kCGImagePixelFormatRGBCIF10 = (4 << 16), /* Only for RGB 32 bits per pixel */} CG_AVAILABLE_STARTING(10.14, 12.0);typedef CF_OPTIONS(uint32_t, CGBitmapInfo) { kCGBitmapAlphaInfoMask = 0x1F, kCGBitmapFloatInfoMask = 0xF00, kCGBitmapFloatComponents = (1 << 8), kCGBitmapByteOrderMask = kCGImageByteOrderMask, kCGBitmapByteOrderDefault = kCGImageByteOrderDefault, kCGBitmapByteOrder16Little = kCGImageByteOrder16Little, kCGBitmapByteOrder32Little = kCGImageByteOrder32Little, kCGBitmapByteOrder16Big = kCGImageByteOrder16Big, kCGBitmapByteOrder32Big = kCGImageByteOrder32Big} CG_AVAILABLE_STARTING(10.0, 2.0);#ifdef __BIG_ENDIAN__# define kCGBitmapByteOrder16Host kCGBitmapByteOrder16Big# define kCGBitmapByteOrder32Host kCGBitmapByteOrder32Big#else /* Little endian. */# define kCGBitmapByteOrder16Host kCGBitmapByteOrder16Little# define kCGBitmapByteOrder32Host kCGBitmapByteOrder32Little#endif图片中单个像素的组成依据色彩空间,排列,以及占位有很多排列组合的形式,所以为了防止解决过多的状况,可能应用 CGBitmapContext 是一种对使用者来说比拟敌对的形式。CGBitmapContext 能够用来把位图按位画进内存的画布。画布上每个像素点都是依照 CGBitmapContext 中指定的色彩空间来排布的。在 CGBitmapContext 创立时,须要传入一些参数来指定咱们须要的画布是什么样的。 ...

November 29, 2021 · 2 min · jiezi

关于ios:块存储监控与服务压测调优利器EBS-Lens发布

简介:SLS团队联结EBS团队公布了EBS Lens,针对块存储提供数据分析、资源监控的性能,能够帮忙用户获取云上块存储资源信息与性能监控数据、晋升云上块存储资源的管理效率、高效剖析业务稳定与资源性能耗费状况。 EBS监控现状块存储是阿里云为云服务器ECS提供的块设施产品,具备高性能和低时延的特点。邻近双十一,在大促的时候,磁盘IO往往是运维的重点,如果磁盘被打爆了,那么要害的业务可能会停滞甚至解体。EBS监控目前存在几个问题: 块存储提供的原生监控仅限度在单实例级别,只能查看单个云盘的性能监控,短少对全局云盘状态的监控,如果云盘数量很多,那么云盘状态的监控就十分麻烦 通过SLS Logtail, Telegraf或者云监控agent等,能够实现对单个ECS实例所有云盘的状态的监控。然而这些监控形式都是侵入式的,agent的装置、监控大盘的保护、云盘实例监控精细化管制、以及跨ECS实例的监控,对于用户来说,都有很大的学习老本和代价剖析维度繁多,以上场景下,对云盘的监控和剖析还是基于云盘id的,而云盘资产自身的属性也蕴含很多信息。比方用户想看到一个本人所有云盘资产的大图、各个地区的云盘散布、各个云盘类型的比例等信息,都是很难做到的。正是思考到用户对EBS监控的应用有如上的痛点,SLS团队联结EBS团队公布了EBS Lens(Lens, 透镜的意思,取名为Lens意味着洞察云产品轻微的变动),针对块存储提供数据分析、资源监控的性能,能够帮忙用户获取云上块存储资源信息与性能监控数据、晋升云上块存储资源的管理效率、高效剖析业务稳定与资源性能耗费状况。EBS Lens产品特点自动化数据采集EBS Lens开启后,SLS会主动从用户的EBS资产中拉取云盘列表。进入APP后首先展现的就是接入治理页面,在这个页面,能够看到EBS云盘全局的一个治理视图,蕴含以下信息: 展现以后接入的云盘总量、数据采集的云盘数量、云盘的地区和指标存储库的数量。展现EBS实例信息。例如,实例ID、标签、云盘品种、云盘类型、可用区信息、采集状态、采集操作等信息。如果用户在开启EBS Lens之后,对EBS云盘有新建、更新和删除操作的话,SLS会自动更新这里的云盘列表 采集配置EBS云盘资产同步过去之后,须要用户开启云盘资产的监控数据采集。在这里,咱们提供两种采集形式,一种是供用户进行精细化治理的手动采集,还有一种是在EBS云盘数量过多的状况下,不便用户全局治理的自动化采集。 手动采集 反对对单个实例的采集状态进行治理思考到EBS实例数量会比拟多,这里反对在单个分页上面进行批量开启/批量敞开操作自动化采集 当用户云盘有几百甚至上千个的时候,手动采集的治理形式显然不能满足需要,因而咱们还提供了一个自动化采集的性能。自动化采集提供了图形化的配置界面:能够应用地区、实例ID、付费类型、磁盘类型、标签等属性设置采集条件。规范模式下各个条件之间为且关系。高级模式下,您能够灵便组合与嵌套条件。配置保留之后,自动化采集立即开启。所有满足条件的云盘,都会主动关上日志采集,从而省去了手动操作的步骤,另外当实例有所增减的时候,自动化采集也可能感知实例的变动,进行相应的调整。 存储库信息展现开启云盘监控数据采集之后,SLS会从EBS云盘上拉取监控数据,而后投递到用户配置的指标存储库里,以时序数据的模式进行存储,在指标存储库这个tab里,反对的性能有: 反对查看存储指标库的地区、数据保留工夫反对数据保留工夫的调整 点击指标库,能够进入SLS的project页面,查看原始监控数据 EBS云盘资产同步、日志采集开启之后,EBS Lens就有了EBS云盘资产和云盘的监控数据了,基于这两个数据,EBS Lens做了两个监控大盘,资源概览和性能剖析页面。 多维度数据聚合与丰盛的数据指标类型资源概览页面,提供一个全局的资产大盘,默认依照用户维度,提供用户账号下所有云盘的统计信息,包含: 云盘总数量云盘总容量云盘实例所属地区个数云盘实例所属可用区个数启用快照云盘占比加密云盘占比Top10容量的区域Top10容量的可用区云盘类型容量散布付费类型容量散布 除了账号的维度外,还反对对地区、付费类型、磁盘类型进行筛选,充沛满足用户的各种统计需要 高精度的数据监控粒度性能剖析页面提供了一个全局的云盘监控大盘,默认会统计用户账号下所有磁盘要害指标的监控,包含 吞吐量总的吞吐量变动曲线读/写吞吐存储Top100的实例,以及吞吐变动曲线 IOPS总的IOPS变动曲线读写IOPS Top100的实例,以及IOPS变动曲线 性能剖析页面还反对对地区、付费类型、云盘类型、云盘id进行筛选,满足用户精细化监控的需要 云盘监控粒度为10s,监控提早为10s内,对于抖动类场景能够无效进行监控 应用场景EBS Lens有这么便捷的治理形式以及丰盛、多维度的监控指标,上面咱们列举了几个罕用的场景,来具体阐明下EBS Lens的性能: 监控场景上面咱们模仿日常常见的磁盘IO异样的场景,展现下EBS Lens的在监控场景下的利用。 环境筹备 首先咱们创立一个云盘,或者应用已有的云盘,挂载到ECS实例上。挂载云盘的操作参见:https://help.aliyun.com/docum...,留神云盘挂载到ECS实例后,必须创立分区和文件系统,使云盘变为可用。将账号下所有云盘通过自动化采集配置,关上监控数据采集 关上性能剖析页面,确认云盘监控数据已接入进来 异样模仿 咱们进入ECS实例中,应用dd来模仿一个对磁盘的异样写入的操作: EBS Lens监控后果 在EBS Lens性能剖析页面,从大盘里,咱们发现有一块磁盘的吞吐量和IOPS迅速晋升到TOP1。为了查看磁盘的具体指标,咱们在过滤框内输出磁盘id,能够看到这个磁盘在选定工夫范畴内吞吐量和IOPS的变动。而该实例id,正是咱们模仿的写入异样的磁盘。在线上,如果呈现相似的问题,那么接下来咱们就该去进行具体的问题定位,比方异样的服务日志打印、不合理的数据落盘等。通过调整工夫范畴,对于设置ttl范畴内的数据,EBS Lens都反对在该页面进行展现,对于故障的复盘和剖析也是有十分大的帮忙的。 配合SLS的告警性能https://help.aliyun.com/docum...,用户齐全能够自动化的监控云盘的性能,精确定位异样云盘。 服务压测和性能调优除了监控场景,EBS Lens在服务压测和性能调优的场景,同样有十分大的作用。所有对于性能方面的测试,最要害的基础设施就是监控指标。EBS Lens性能剖析大盘就能够提供云盘实时的性能指标,这能够无效的帮忙用户疾速定位云盘是否存在性能瓶颈。咱们模仿一个简略的写入场景:大量级的数据要以最快的速度写到磁盘上。 环境筹备 咱们采纳跟下面环境一样的ECS环境,在这个场景下咱们指定一个固定的云盘做测试 在EBS Lens的页面关上该云盘的监控数据采集 场景模仿 第一版本,这里应用FIO模仿性能比拟差的一个随机写的实现场景: fio -filename=/mnt/test1 -direct=1 -iodepth 1 -thread -rw=randwrite -ioengine=psync -bs=16k -size=2G -numjobs=10 -runtime=60 -group_reporting -name=mytest ...

November 26, 2021 · 1 min · jiezi

关于ios:我们如何实现业务-100-云原生化让阿里中间件全面升级到公共云架构

简介: 在往年的天猫双 11 中,中间件撑持了 5403 亿的交易量,并全面降级到了公共云架构。 此次的架构降级,是以开源为内核、以公共云为根底、以 OpenAPI 进行解偶扩大,在架构上,对开源、自研、商业化进行对立。通过采纳和反哺开源、推动社区建设,通过阿里巴巴丰盛的业务场景、打磨技术的性能和可用性,通过云上商业化服务更多企业、打造更好的用户体验,全方位锻炼云上产品的竞争力。 作者 | 中间件反对团体上云技术小组 2019 年,阿里巴巴外围零碎 100% 运行在阿里云上。2021年,阿里巴巴业务 100% 云原生化。阿里巴巴曾经成为寰球首家,将所有业务都放在自家公共云上的大型科技公司。 举全团体之力,将业务全副迁徙至公共云,不仅是对云的笃定,也证实了阿里云有能力应答高难度、超简单环境下的技术挑战,为客户享受云上技术红利提供了更松软的实际保障。 01 架构一致性,开源、自研、商业化三位一体在往年的天猫双 11 中,中间件撑持了 5403 亿的交易量,并全面降级到了公共云架构。 此次的架构降级,是以开源为内核、以公共云为根底、以 OpenAPI 进行解偶扩大,在架构上,对开源、自研、商业化进行对立。通过采纳和反哺开源、推动社区建设,通过阿里巴巴丰盛的业务场景、打磨技术的性能和可用性,通过云上商业化服务更多企业、打造更好的用户体验,全方位锻炼云上产品的竞争力。 这个过程中,阿里巴巴业务的研发效率晋升了 20%,CPU 资源利用率晋升了 30%,利用 100%云原生化,在线业务容器可达百万规模,计算效率大幅晋升,双 11 计算成本降落 30%。 接下去,咱们将全方位揭秘业务 100%云化过程中,后端 BaaS 化,运行时 Mesh 化,业务侧 Serverless 化的全过程。 02 中间件后端 BaaS 化,有状态利用也可分钟级交付以往的双 11 建站交付都是线性的。先交付 IaaS 资源,而后再交付中间件,最初再交付业务。 往年,中间件降级到公共云架构后,IaaS 资源和中间件同步交付,节俭了两者串行交付的工夫。中间件公共云架构运维底座全副切到 K8s 上,让有状态的中间件也能做到极致弹性,使得中间件的交付效率从天级别,升高到了分钟级,极大地晋升了交付效率,升高了资源保有工夫和资源老本。 后端的撑持零碎也全面降级,如通过对接阿里云账号权限体系,来解决平安问题;通过对接计量计费体系,来解决 IT 资产数字化问题,为团体各个技术团队的经营者能够通过账单模式,可视化的进行老本优化。 在用户界面上,也降级反对了 IPv6,为阿里巴巴生产网全面向 IPv6 架构演进做好了筹备。 03 海内业务 Mesh 化,异地多活可下沉 Sidecar阿里巴巴海内有 AE&Lazada 等多种业务状态,异地多活体系侵入性大,技术架构不对立,从而影响了全局高可用和研发协同效率。 ...

November 25, 2021 · 1 min · jiezi

关于ios:企业级数据湖最佳实践

简介:2021云栖大会云原生企业级数据湖专场,阿里云智能高级解决方案架构师周皓为咱们带来《企业级数据湖最佳实际》的分享。 本文次要分享了数据湖的外围能力及几个最佳实际案例。 以下是精彩视频内容整顿: 一、对立数据存储,多引擎对接,运存拆散在这一节开始之前,先回顾一下数据湖几个外围的能力: 集中存储、多种引擎对接各种类型的数据用集中形式对立存储在OSS,无缝对接如 EMR 等各类计算引擎,反对开源计算生态 数据无需解决、间接存储对接多种数据输出源,提供便捷的数据接入和数据生产通道,多种类型数据都能够依照原始产生的状态间接存储,随需再进行解决,比照传统数仓 schema 限度构造,更适配业务疾速倒退的利用场景 更灵便架构、运存拆散存算拆散架构带来十分好的灵活性,通过计算与存储解耦合提供更灵便的零碎架构设计空间,让计算、存储资源具备更好的扩展性,充沛进步资源利用率,极大升高运维治理难度、优化 TCO。这也是本文介绍案例中,客户抉择数据湖计划的一个重要起因。 二、最佳实际案例Yeahmobi- 挪动互联网广告实际案例Yeahmobi,作为一家技术驱动倒退的企业国际化智能营销服务公司,次要波及到的就是智能营销业务,每天的业务稳定十分大。如果采纳传统的架构,势必要依照业务的峰值筹备资源,就会造成很多 CPU 资源无奈失去最大化的利用。这也是许多智能营销互联网公司的痛点。基于此,大多企业抉择了数据湖计划。 存储与计算解耦合,让计算资源使用量能够依照线上业务量的变动动静增减,缩小常驻资源量多种不同类型计算引擎,轻松对接在线广告各种场景所须要的剖析要求通过数据湖计划,整体TCO优化达到30%,让业务状态更具竞争力只有将数据存储在数据湖中,计算资源能够依照业务的变动实现动静的伸缩与创立,只需保护一个最小的常驻计算资源就足够了。在这种状况下,再联合兼具半托管和全托管模式的 EMR 动静伸缩计算及剖析的能力,能够极大地升高运维的难度。这也是许多智能营销公司抉择这套数据湖计划的起因。Yeahmobi 抉择这套数据湖计划后,TCO 升高了30%。 数禾科技-互联网金融实际案例数禾科技是一家互联网金融科技公司,因其所在行业的个性及自身的业务场景需要,对数据的平安可靠性,以及数据访问控制的细粒度都有很高的要求。数禾服务了大量外部和内部用户,数据安全敏感,要求严格的数据权限隔离。其次,整个业务变动也须要十分强劲的吞吐能力来撑持计算及存储。 其实在数禾的倒退过程中,最早采纳的是最常见最通用的大数据集群构建形式既通过服务器搭建,然而很快就发现这种形式无奈跟上业务的疾速倒退:一是存储老本显著增长,一个规范的 HDFS 集群是三个冗余备份,在思考到水位,整个文件系统的开销等因素后,存储老本是显著减少的。二是因为业务的疾速扩容, 如果频繁减少 HDFS 集群节点,会影响业务的可用性。 基于以上起因,数禾抉择了阿里云数据湖计划。数据湖采纳 对象存储 OSS 作为底座,无需放心容量的扩大或是小文件的减少。文件数量的疾速减少会对 HDFS 集群的 NameNode 造成比拟大的压力,然而对象存储构造无需放心文件数量减少,哪怕是到万亿级的 object 的数量,也没有任何压力。采纳了数据湖形式当前,多 bucket 切分搭配阿里云的 RAM 体系,能够做到十分细腻度的访问控制。再通过例如 OSS 与 EMR 在软件层单干优化的 JindoFS 计划,可能输入超过 TBS 的吞吐能力,以撑持整个业务的需要,实际操作体验超过自建HDFS。此外,通过云上弹性资源能力,工作能够随需进行千台规模节点的弹性伸缩,达到降本增效的成果。 数据湖经典应用场景-冷热数据分层模式特点 利用与业务零碎的长期运行积攒了大量的冷数据,一直增长的冷数据对现有集群的存储空间压力大须要解决冷数据存储空间,同时为拜访频繁的热数据留出性能优化空间优化冷数据的长期存储老本,要能远低于热数据存储老本,并且冷数据要能便于读取冷热数据分层是数据湖的一个经典应用形式。利用与业务零碎的长期运行会产生大量冷数据,对整个集群的运维产生十分大的压力。一方面是规模上的压力,通用的大数据集群外面的服务器架构比拟同构导致冷数据的优化的空间不大,如果通过减少高密度的或者异购的机型,在实践中会导致集群运维治理难度的大幅度晋升。另外一方面是在 IDC 环境中,要想疾速扩容,物理集群会受限于很多因素。这也是很多数据湖客户从传统的大数据集群架构往数据湖迁徙的起因。目前曾经有很多客户拥抱了数据湖,全面应用 OSS。无奈一步到位的时候,客户会先将温数据和冷数据先沉降到 OSS。早在2016年,OSS 就曾经与 Hadoop 生态充沛交融,Hadoop 3.0能够间接拜访 OSS,写好的工作不必做任何批改就能够间接运行,大幅缩小了迁徙的难度。迁徙过去之后,OSS 上的智能生命周期治理简略地配置一个生命周期策略,就能够依照规定把冷数据进一步沉降到归档和冷归档类型中,进一步降低成本。 教育科技平台实际案例客户价值 通过 OSS 多存储类型和数据生命周期治理,实现冷数据长期存储的老本优化,通过云上承载冷数据,IDC 自建集群无需扩容,解决机房空间难题通过 OSS 数据湖的高可扩展性,无效的帮忙客户解决了大数据存储的性能吞吐问题,躲避了自建 HDFS 文件系统在元数据节点的性能瓶颈客户曾经在布局进一步通过云上弹性资源去扩容计算资源,减小一次性资源投入这是一个冷热分层的理论案例。教育平台波及到的业务场景蕴含各种日志的采集,通过应用的日志帮忙学生改良学习。这个客户也面临一个问题,大量日志采集当前对于空间占用会造成十分大的压力。客户又是自建 IDC,很难在一段时间内就实现物理空间的扩容,所以最初抉择了数据湖计划。通过专线买通了 IDC 和阿里云的连贯,应用阿里云的资源扩容现有 IDC ,再通过专线将线下的冷数据迁徙到了数据湖中,为线下的业务腾出了空间,压力开释当前,空间就非常灵活了。而后进一步将很多利用日志间接入湖,通过对象存储及多版本能力,为数据可靠性提供更多的保障,同时也应用了冷归档能力将温数据进一步沉降以降低成本。入湖的数据则通过专线拉到本地计算,然而在数据湖的应用过程中,客户想进一步应用云上的计算资源以扩容计算能力,就无需一次性洽购线下的计算服务器,进一步降低成本。 ...

November 24, 2021 · 1 min · jiezi

关于ios:if-else-if理解订正

int n = 100; if (n >= 60) { NSLog(@"及格了"); } else if (n >= 90) { NSLog(@"优良"); } else { NSLog(@"挂科了"); }以前我始终认为if else if会以最初一个 else if来显示,其实理论只有满足第一个遇到的if条件,就不会再忘下走了,下面就是证据,发现变量n等于100满足了 n >= 60之后,就不会往下持续走了,即便满足了 n >= 90的条件。

November 23, 2021 · 1 min · jiezi

关于ios:敏捷版全链路压测

简介: PTS 联合 10 多年来阿里的全链路压测的教训,让阿里云的用户能够如同享受满汉全席般的享受全套规范的全链路压测,也能够依据本人的需要,抉择最适宜本人的形式。 作者:子矜 客户的故事全链路压测被誉为大促备战的 “核武器” ,如果之前有关注过阿里双 11 相干的技术总结,对 “全链路压测” 肯定不会生疏,这个词的出场率简直 100%。从对双 11 稳定性的价值来看,用 “核武器” 来形容全链路压测毫不为过。 在某出名电商大促中,该电商平台也想用全链路压测来为本人的大促提前排除危险。然而他遇到几个艰难: 全链路压测是一个须要多角色参加的流动:业务方,测试,运维,研发,数据库,都须要参加进来。然而可能像阿里具备成熟的组织体系,能够强有力的推动各种不同的角色,都是须要较长时间来积攒的。全链路压测,经常波及到框架的革新:而该电商平台的业务简单,做构造梳理与业务革新并不事实。那这个出名电商平台,有什么方法能够在 1 个星期之内,不进行业务革新,不扭转业务部署,就可能用上全链路压测呢? 接下来的内容,咱们会从全链路压测的原理开始,并引入基于同样原理的 “麻利版” 全链路压测,让该出名电商平台可能在 2 周之内就能用上全链路压测的计划。 全链路压测首先,咱们来看看阿里的全链路压测,到底解决了什么问题: 全链路压测实际上解决的问题是:在线上的压测。线上压测,可能最快、最间接的发现线上的问题。然而,线上压测会带来数据净化的问题:如何把压测数据和实在数据辨别开来,是压测里至关重要的一点。那么,阿里是怎么做的呢?咱们一起来看下图: 阿里的全链路压测具备一套成熟又简单的零碎:压测的梳理、构建、筹备、发送。然而,这套体系对于一个云上的用户是须要长期建设失去的。那咱们如何可能让用户疾速,麻利的享受这套技术呢? 在这里,PTS 把整个流程进行积淀,都以标准化的输入来提供给云上的用户。用户能够间接享受一整套的全链路压测体系,也能够在压测的关键环节:例如场景梳理、申请构建、压测环境、压测等步骤中,依据本人的需要来定制本人想要的压测成果。 场景梳理业务场景,即对应的是压测的输出申请。这是压测第一步,也是最重要的一步。最常见的是把波及到业务的 URL 进行梳理,汇总。例如下图就是一个常见的场景汇总: 然而,这是不够的。当若干个 URL 汇总成一个场景之后,URL 之间的比例、工夫距离,也是影响业务场景的要害。用常见的场景打一个比如:一个用户的下单,可能背地蕴含着 10 个用户登录,每个用户均匀浏览了 4 个商品,每个商品中均匀被浏览了 5 个评估,最初一个用户在 10 点大促开始的时候,购买了一个商品。 这些 URL 之间的关系、工夫点,须要人员有丰盛的业务知识能力梳理分明。为此,PTS 提供服务端流量录制的性能,不便用户来录制流量,并且轻松的失去其中不同维度的比例关系: 如上图所示,用户能够清晰的失去 URL 之间的比例关系、用户 URL 之间的工夫行为等等。基于这个梳理好的数据模型,用户能够在这个根底上进行裁剪。 测试数据结构接下来,就是结构用户数据了。这一步波及的角色最多,也最为繁琐。整个数据结构由三个步骤形成,如下图所示: 首先是数据发现。通常,咱们能够通过人工业务梳理,失去该业务所波及到的所有表,并进行剖析。PTS 为罢黜这个懊恼,和DMS买通,提供表构造预览,让测试人员不便的看清楚和场景相关联的构造,大大的晋升效率。 如果还是感觉太简单,PTS将提供数据录制工具,装置了这个 agent 之后,该业务所波及的表,都会被残缺的记录下来: 有了这些工具,测试人员就能够毋庸 DBA 的帮助,轻松的失去场景关联的表信息了。 ...

November 23, 2021 · 1 min · jiezi

关于ios:iOS-App启动优化

前言作为程序猿来说,“性能优化”是咱们都很相熟的词,也是咱们须要一直努⼒以及继续进⾏的事件;其实优化是⼀个很⼤的课题,因为细分来说的话有⼤⼤⼩⼩⼗⼏种优化⽅向 ,然而切忌在理论开发过程中不能盲⽬的 为了优化⽽优化,这样有时可能会造成事与愿违的负成果,须要咱们依据理论场景以及业务需要进⾏正当优化。接下来进⼊正题,本⽂将会以iOS App的启动优化为开展点进⾏探讨。 启动流程iOS App的启动咱们都晓得分为为pre-main和main()两个阶段,并且在这两个阶段中,零碎会进⾏⼀系列的加载操作,过程如下: 1、 pre-main阶段加载应⽤的可执⾏⽂件加载dyld动静连接器dyld递归加载应⽤所有依赖的动态链接库dylib2、 main()阶段dyld调⽤main()调⽤UIApplicationMain()调⽤applicationWillFinishLaunching调⽤didFinishLaunchingWithOptions阶段优化项1、 pre-main阶段针对 pre-main 阶段做优化时,咱们须要先具体理解其加载过程,这个能够在2016年WWDC 的 Optimizing App Startup Time 中具体理解到, 相干资料 1.1 Load dylibs 这⼀阶段dyld会剖析应⽤依赖的dylib(xcode7当前.dylib已改为名.tbd),找到其 mach-o⽂件,关上和读取这些⽂件并验证其有效性,接着会找到代码签名注册到内核,最初对dylib的每⼀个segment调⽤mmap()。不过这⾥的dylib⼤局部都是零碎库,不须要咱们去做额定的优化。 优化论断:1、尽量不使⽤内嵌的dylib,从⽽防止减少 Load dylibs开销2、合并已有的dylib和使⽤动态库(static archives),缩小dylib的使⽤个数3、懒加载dylib,然而要留神dlopen()可能造成⼀些问题,且实际上懒加载做的⼯作会更多 1.2 Rebase/Bind在dylib的加载过程中,零碎为了平安思考,引⼊了ASLR(Address Space Layout Randomization)技术和代码签名。因为ASLR的存在,镜像(Image,包含可执⾏⽂件、 dylib和bundle)会在随机的地址上加载,和之前指针指向的地址(preferred_address)会有⼀个偏差(slide),dyld须要修改这个偏差,来指向正确的地址。Rebase在前,Bind在后,Rebase做的是将镜像读⼊内存,修改镜像外部的指针,性能耗费次要在IO。Bind做的是查问符号表,设置指向镜像内部的指针,性能耗费次要在CPU计算。 优化论断:在此过程中,咱们须要留神的是尽量减少指针数量,⽐如: 缩小ObjC类(class)、⽅法(selector)、分类(category)的数量缩小C++虚函数的的数量(创立虚函数表有开销)使⽤ Swift struct (外部做了优化,符号数量更少)1.3 Objc setup⼤局部ObjC初始化⼯作曾经在Rebase/Bind阶段做完了,这⼀步dyld会注册所有申明过的ObjC类,将分类插 ⼊到类的⽅法列表⾥,再查看每个selector的唯⼀性。在这⼀步倒没什么优化可做的,Rebase/Bind阶段优化好了,这⼀步的耗时也会缩小。 1.4 Initializers在这⼀阶段,dyld开始运⾏程序的初始化函数,调⽤每个Objc类和分类的+load⽅法,调⽤C/C++ 中的结构器函数(⽤attribute((constructor))润饰的函数),和创立⾮根本类型的C++动态全局变量。Initializers阶段执⾏完后,dyld开始调⽤main()函数。 优化论断: 少在类的+load⽅法⾥做事件,尽量把这些事件推延到+initiailize缩小结构器函数个数,在结构器函数⾥少做些事件缩小结构器函数个数,在结构器函数⾥少做些事件2、 main()阶段在这⼀阶段⾥,次要优化重点放在 SDK初始化、业务⼯具注册、整体didFinishLaunchingWithOptions⽅法中,因为咱们的⼀些第三⽅app⻛格配置、启动疏导⻚显示状态逻辑、版本更新逻辑等等根本⽅都会在这⾥进⾏,如果这部分逻辑没有做好优化梳理,随着业务一直拓展,臃肿的业务逻辑会间接导致启动工夫加⻓。 优化论断:在满⾜业务需要的前提下,尽量减少 didFinishLaunchingWithOptions ⽅法在主线程中的事件处理逻辑,⽐如: 依据理论业务情况,梳理各个⼆⽅/三⽅库,找到能够提早加载的库,做提早加载解决,⽐如放到⾸⻚控制器 的viewDidAppear⽅法⾥。梳理业务逻辑,把能够提早执⾏的逻辑,做提早执⾏解决。⽐如查看新版本、注册推送告诉等逻辑防止进⾏⼀些简单/多余的计算逻辑,这类逻辑尽量进⾏异步提早解决防止在⾸⻚控制器的viewDidLoad和viewWillAppear做太多容易阻塞主线程的事件,这2个⽅法执⾏完,⾸⻚控制器能力显示场景补充另外,在咱们理论开发过程中,很多项⽬的⾸⻚控制器都会有⼀些后盾可配、较为丰盛的构造或者举荐数据进⾏展现,⽽且咱们的⾸⻚展现速度通常也会被纳⼊启动优化的⼀局部,其实对于这种类型的优化,如果咱们还只是⽤传统的api -> data -> UI⽅式进⾏的话,就很难有显著的改善空间,因为⽤户的⽹络状态 并不是可控项,如果不做其余解决的话,那在很多场景下对⽤户来说,即便咱们放上⼀些占位图,展现的款式也是很不敌对的,毕竟⾸⻚控制器对⽤户的第⼀视觉冲击影响还是⽐较⼤的。 对于这种场景下的优化来说,⼀般咱们能够采取 Local + Network + Update 的⽅式在⼀定水平上优化⾸⻚加载速度: 即:1、app更新过程中,⾸先进⾏本地内嵌解决逻辑,内嵌⾸⻚数据结构( localDataBase)、内嵌⾸⻚款式所需 资源( localStorage)2、在装置启动之后,对本地与线上数据更新记录进⾏对⽐,检测是否须要更新本地内嵌数据结构3、检测到有须要更新的数据时,才会对指定构造进⾏静默更新,并且同步更新本地数据结构 ...

November 19, 2021 · 1 min · jiezi

关于ios:iOS启动优化

启动速度优化背景:咱们的我的项目在我的项目为一个开发迭代多年的老我的项目,之前对我的项目的启动性能没有太多的关注,导致APP的启动速度比较慢,启动有时要耗时3、4s钟,整体启动性能堪忧。咱们主管安顿我负责优化,全力优化APP启动速度。 遇到挑战:最大挑战有2个,一是代码历史代码性能耗费没有把控,很多中央存在不合理的代码;二是做为入职不久的新人须要在1个月实现左右优化,工夫紧工作重; 优化步骤:首先咱们梳理好指标,iOS启动能够分为冷启动和热启动。冷启动是指APP自身不在后盾零碎,从用户点击利用icon到appDelegate didFinishLaunching办法执行实现用户看到APP首页为止;热启动是APP自身在零碎后盾运行,从后到点击到进入APP场景。咱们重点是优化冷启动的速度,启动速度工夫指标由3s降到1.2s;有了明确指标后接下来是对指标进行拆解,要进行冷启动优化咱们须要晓得冷启动过程具体做了什么,具体哪局部执行节点耗时较多。APP冷启动能够大略分为三个阶段,第一阶段是main函数之前,零碎执行一系列加载和链接工作;第二阶段是main函数之后,从main函数开始到AppDelegate的didFinishLaunchingWithOptions执行结束;第三阶段是从didFinishLaunchingWithOptions执行到APP渲染出APP的首页;咱们须要从这三个阶段来进行优化,首先咱们须要剖析这三个阶段的耗时状况。测算main函数之前的耗时,咱们能够通过配置xcode来进行,在xcode的editScheme中Run→ Environment Variables 增加name为DYLD_PRINT_STATISTICS为1,这样就能够在xcode控制台中一份输入报告示例如下: 从上图中咱们能够清晰理解main函数前的耗时,以及过程中加载动静库耗时、oc类初始化耗时、指针重定义耗时。对于main函数后咱们能够通过退出计时代码来统计,这块统计比较简单; main函数前外围优化:次要包含优化动静加载库、Rebase/Binding优化和优化初始化阶段 动静库加载优化:咱们次要进行2方面的优化,1.毁灭内嵌的动静库,因为零碎加载内嵌动静库会耗费比拟大的性能;2.缩小动静库的数量,能够通过合并已有的动静库来达到目标,动静库越多性能开销越多; Rebase/Binding优化:次要进行了2类优化,1.缩小oc类、缩小办法、缩小分类数量;2.应用Swift structs能够大幅缩小符号数量; Initializers阶段优化:最外围是缩小load办法应用,load执行代码越多启动会越慢,咱们能够把load的实现代码提早放到initiailize办法中,在initiailize办法不会影响APP的启动速度; main函数后阶段优化:这个阶段外围优化思路是缩小主线程的性能耗费,对于根底组件的初始化做到能延后的延后,能放到子线程初始化的放到子线程初始化。通过以上优化后咱们APP的启动速度有了很大的晋升,由原来的3s出头优化到了1.2s左右。 接入总结和倡议:整体接入还是比较简单,官网在整体的阐明文档方面比拟清晰。整个apm在解体做的比拟好,比照之前用的听云和bugly还是不错的,在信息收集的全面性方面特地好,另外对于解体日志解析和准确性方面比拟好,解体的堆栈绝对其余产品更易懂。 对产品的倡议:在应用过程中发现以下问题倡议参考优化(1) 从u-apm注册后,在之后的主页就找不到对于u-apm的内容了,注册完后注册了一个APP发现是接入友盟根底SDK,不是我想要的,只能通过返回到流动也才找到u-apm。(2) 想接入一个没有idfa的版本,没找到,看接入留神是强制收集了idfa,定位和idfa国家对咱们这个行业有限度,特地是地位权限不容许用;(3) 官网上播放视频和上面的介绍叠在一起,无奈全屏看(Safari浏览器)(4) 概览中,解体率、ANR形容应用专门名词,当初都应用“谬误“统称,并不合乎开发的认知,比方解体就是解体率,anr就说是anr,而不是统称为解体;(5) 实时概览更心愿看的是一些总的数据表,比方解体Android解体心愿看java和原生底层加起来的总解体,另外倡议实时概览减少卡顿率、网络错误率、启动速度等一些要害指标的总览图;二级页面再减少卡顿、解体等详情; 作者:隆冬从事iOS开发5年,做过社交和教育APP研发

November 19, 2021 · 1 min · jiezi

关于ios:从更高到更好-揭秘2021阿里双11背后的技术亮点

简介: 往年,是阿里巴巴第13个双11。往年双11,阿里巴巴大促峰值的计算成本相比去年降落50%;截至11日,小蛮驴无人车在双11期间累计配送快递已超过100万件。更多的阿里自研技术投入到双11,在芯片、服务器等硬核技术攻坚的同时,技术也在推动全链路的降本增效。除了深耕自立自强的高科技,阿里还在践行“人人受害、责任担当、凋谢共享”的好科技,心愿用技术给客户发明更好的价值,为社会发明更大的奉献。从更高到更好,往年双11,阿里巴巴的技术有什么不一样? 作者 | Alibaba Tech起源 | 阿里技术公众号 往年,是阿里巴巴第13个双11。 往年双11,阿里巴巴大促峰值的计算成本相比去年降落50%; 截至11日,小蛮驴无人车在双11期间累计配送快递已超过100万件。 更多的阿里自研技术投入到双11,在芯片、服务器等硬核技术攻坚的同时,技术也在推动全链路的降本增效。 除了深耕自立自强的高科技,阿里还在践行“人人受害、责任担当、凋谢共享”的好科技,心愿用技术给客户发明更好的价值,为社会发明更大的奉献。 从更高到更好,往年双11,阿里巴巴的技术有什么不一样? 绿色低碳1 绿色科技 助力每笔订单碳排放量继续降落交易背地的碳老本次要有三局部:一是商品交易/数字交易自身的碳老本;二是物流运输中的碳老本;三是商品生产和生产中的碳老本。 低碳双11,必须解答好三个考题:首先,如何让数据中心变得更“绿”、更加节能;其次,如何通过算力共享,晋升资源对立调度效率;再次,如何让单位算力的效率和价值最大化。 在绿色数据中心方面,阿里云以低碳选址、清洁能源、液冷技术等交融AI利用,减速绿色节能技术创新及迭代降级,做到“少用电、用好电、用绿电”;在绿色计算方面,通过技术创新实现资源利用率显著晋升、助力本身节能减排,往年每一笔订单在交易环节的碳排放进一步缩小;在绿色算力方面,云提供了算力充沛复用、高效利用的技术架构与经济模式,让算力自身更绿色;在绿色数字供应链方面,以算法驱动,采纳预测+决策的算法体系,从机器学习向深度学习技术栈演进,实现数据驱动的预测决策一体化优化,继续优化、翻新供应链打算和运配等环节,升高货损、晋升运配效率,帮忙商家升高碳排放。 2 技术驱动,建设阿里巴巴绿色数字供应链往年双11,数字供应链采纳预测+决策的算法体系,实现数据驱动的预测决策一体化优化,升高货损,对立调度缩小节约;在运配场景,晋升车辆装载率及运输效率;通过建设一盘货、全链路可售能力,帮忙商家库存共享,更精准地进行补货备货,助力商家多端销售,升高畅销。 3 阿里云数据中心大规模应用绿电,为“双11减碳打算”提供绿色“后盾”为助力数据中心低碳绿色倒退,近年来,阿里巴巴积极响应国家“双碳”策略要求,发展清洁能源电力交易。2018年,张北数据中心退出张家口“四方合作机制”风电交易,率先在全国数据中心行业发展非水可再生能源电力交易。往年9月,作为首批全国绿色电力交易主体,达成1亿千瓦时光伏电力交易,成为本次交易中互联网行业最大的绿色电力购买主体,践行了绿色倒退的理念,摸索了通过新交易种类取得绿色电力的门路。双11期间,预计阿里张北数据中心将应用绿电近3000万千瓦时,减排二氧化碳2.6万吨。公开数据显示,2021年1-9月,阿里巴巴共交易绿电2.48亿千瓦时。自2018年至2021年9月,仅张北数据中心就累计交易约6亿千瓦时新能源电量,累计实现二氧化碳减排近52.3万吨。 值得一提的是,阿里巴巴张北数据中心成为行业内首个碳普惠试点我的项目,获评2020年国家绿色数据中心,入选2021年国家生态环境部低碳绿色典型案例。 4 对立调度、对立资源池稳固、高效、低成本撑持双 11在利用侧,针对高并发场景,在保障生产体验的同时,阿里技术大幅优化交易链路,应答脉冲式流量。在软件侧,通过对立资源池进行对立调度,撑持大规模的离在线混部,实现在线业务优先调度。在云方面,基于阿里自研的神龙云服务器、自研的数据库PolarDB等,大大晋升了服务器资源应用效率,可搭建百万级规模的容器集群,大规模开释云原生的技术红利。 5 绿色物流全面降级,通过智能切箱、绿色回箱、碳账单等让绿色心智充沛触达消费者,打造人人都能参加的绿色双11通过优化纸箱型号和举荐正当的装箱计划,菜鸟智能切箱算法反对菜鸟全行业仓内包材举荐,均匀缩小应用15%包材,仅在菜鸟仓一年可为5.3亿个包裹“瘦身”。 通过碳排放测算和绿色物流各环节的信息化盘查,在2021年天猫双11期间推出了物流行业首个“集体减碳账单”,并在6万个菜鸟驿站发动“快递包装回收 全面换鸡蛋”、1万个菜鸟驿站试行旧包装循环寄件我的项目,买通消费者可感知、可参加的快递包装循环应用闭环。 技术创新1 平头哥芯片含光800规模化反对搜寻举荐等场景2021双11期间,含光800通过阿里云平台反对了淘宝搜寻、举荐等业务,其中淘宝主搜100%的AI算力由该芯片提供。理论利用状况显示,含光800无效施展了芯片与云计算环境交融的劣势,既晋升了零碎的性能又升高了整体能耗,以搜寻场景为例,相比传统GPU,应用含光800运行的算法效率最高可晋升近2倍,单位算力能耗升高58%。 2 自研磐久服务器新一代硬件技术全新上阵磐久服务器新一代硬件和技术全新利用于双11,提供行业当先的计算及存储生产力,场景化性能晋升30%以上。往年云栖大会上,阿里巴巴公布自研磐久服务器系列,包含高性能计算系列、高性能存储系列、大容量存储系列。采纳对立的方升架构,实现从芯片、部件到整机的技术及架构翻新和自研,应用灵便模块化与全栈软硬件交融技术,提供多种通用和异构计算、多层级存储解决方案,为客户带来行业当先的、更高可靠性和更极致的性能体验。 3 双11云原生技术实现自研、开源、商业化三位一体中间件迈向产品三位一体架构进行演进,后端BaaS化,运行时Mesh化,业务Serverless化,做到开箱即用,按量付费,全面晋升研发运维效率。其中根底中间件进行BaaS革新,微服务降级到MSE,音讯降级到MQ,可观测降级到ARMS,高可用降级到AHAS,全链路压测降级到PTS,升级成私有云产品,极致弹性,大促分钟级建站和扩容,大大晋升建站效率。Mesh化在国际化大规模落地,把非业务逻辑下沉到Sidecar,让业务聚焦业务开发。业务Serverless化,淘宝导购前端100%上FC函数计算云产品,实现疾速扩容、疾速响应,帮忙业务晋升运维效率。将来预计将有更多企业采纳阿里双十一起款中间件撑持业务峰值,疾速共享中间件积淀的技术和能力。 4 多模态大模型M6首次反对双11 落地40多个业务场景超大规模模型成为人工智能畛域的焦点。近期,阿里达摩院实现了寰球首个10万亿参数的多模态大模型M6,并公布了对外平台,涵盖各项单模态和跨模态的了解及生成工作。作为国内首个商业化落地的多模态大模型,M6已在阿里巴巴超40个业务场景中利用,日调用量超5亿。 往年,大模型首次反对双11。依附多模态理解能力,M6正在增进淘宝、支付宝等平台的搜寻及内容认知精度;凭借晦涩的写作能力,M6正为天猫虚构主播等创作剧本和文案;M6已在犀牛智造上岗,其高清图像生成能力让设计师工作效率晋升5倍,新款服饰开发周期从过来的1-3个月升高到最快2周,首批AI设计服装已在淘宝上线。 尤其值得一提的是,M6做到了业内极致的低碳高效,相比去年公布的大模型GPT-3,M6实现等同参数规模,能耗仅为其1%,极大升高了大模型实现门槛,并推动了普惠AI的倒退。 5 IPv6大规模利用于双11在过来三年多工夫,阿里巴巴在技术生态中踊跃推动IPv6超大规模部署和利用,截止2021年10月,团体利用月活IPv6用户曾经超过6亿。双11期间电商APP淘宝,天猫,闲鱼,考拉的挪动互联网IPv6流量占比超过76%。淘宝的外围业务性能 "交易订单"链路曾经实现IPv6革新并有1/3 流量通过IPv6承载,首次撑持双11大促。此外,钉钉已实现IPv6全链路革新,是国内首款端到端全链路反对IPv6-only的试点利用。 6 全栈式数字供应链技术创新,助力晋升商业效率数字供应链为行业与商家提供端到端的数字供应链解决方案,实现从洽购到流通、从商家到消费者的全链路场景的笼罩。 往年双11数字供应链一直技术创新,自研深度时序预测算法Falcon,帮忙商家进行智能的销量预测及补货入库,并打造了智能时序预测机器人产品DChain Forecast,让商家也具备高准确度的时序预测能力;继续建设供应链仿真平台,实现供应链全链路高保真仿真,反对品仓部署、网络布局等沙盘推演,优化库存治理,晋升在架;提供智能履约决策能力,实现对仓配路由、订单集批、配送调度等作业场景的笼罩,保障远近场、标品生鲜等不同时效要求的服务指标达成。 本次大促,数字供应链驱动了超过数以亿件商品与订单的流动,以数字化技术助力晋升商业效率与经济生机。 7 阿里灵杰产品全面拥抱云原生,性能和可用性全面晋升阿里灵杰全面拥抱云原生,包含MaxCompute上线对立调度、实时计算Flink版 VVP平台降级Serverless、Hologres 全面上线到云原生平台,带来集群稳定性和资源弹性能力的晋升。MaxCompute对立调度集群承当了交易量的40%,性能也是混部集群中最高的,实时计算Flink版 引擎优化、Hologres高可用能力建设等帮忙外围业务营销流动剖析、生意顾问等节俭大促资源的同时,可用性也有大的晋升。 8 云原生架构在国际化全面铺开,联合业务架构翻新进一步实际云原生价值双11期间国际化所有外围利用100%云原生,100%ASI开启Mesh数据面能力,Mesh管制面下沉笼罩外围交易链路大部分外围零碎,云原生去中心化网关架构胜利在AE规模化落地,承接大促流量,并禁受双11峰值流量考验; 业务架构:为晋升架构继续演进能力,将网关类组件实现容器化剥离,基于容器编排部署,实现去中心化网关架构,为云原生业务架构演进建立新的标杆。 基础架构:以服务网格为底座,实现企业级流量治理规范与产品架构,反对了双十一数千应用服务级别流量管控与治理,实现了流量治理规定上线由以天为单位利用维度降级到秒级上线失效,人均效率晋升1倍以上。 体验降级1 淘宝3D沉迷式直播间、虚构主播 打造沉迷式生产新体验双11期间,淘宝直播交融3D沉迷式直播间、3D化商品与虚构主播(AI数字人)为消费者带来全新的沉迷式生产新体验。 淘宝直播3D沉迷式直播间基于寰球首个影视级扩大事实的云拍摄技术,冲破了以往影视级XR直播拍摄中云渲染、AI、简单光影模仿、云3D资产库等关键技术,反对主播仅用一般绿幕就可虚构出上千平米的直播会场、近千盏舞台灯光、特种摄像设施的直播成果,成为首个具备低成本、可复用、低碳环保等劣势的商家自播影视级拍摄解决方案。 ...

November 19, 2021 · 1 min · jiezi

关于ios:OC如何编译swift-pod库

对于OC引入Swift pod库遇到的问题简书地址:www.jianshu.com/p/0330e04fd… 因为公司要实现线状图, 我最终抉择了Charts这个第三方控件, 然而这个库只有swift版本. 我平时开发就用OC, 那只能混编, 在此记录下混编时遇到的问题 首先批改Podfile, 减少pod 'Charts' 而后pod install 这样做还不行, 须要在Podfile中退出 use_frameworks!, 这个很重要 而后pod install 也就是最终后果是 platform :ios, '10.0'use_frameworks!target 'HDMI' do pod 'AFNetworking' pod 'MBProgressHUD', '~> 1.0.0' pod 'UMengAnalytics' pod 'SAMKeychain' pod 'FMDB', '~> 2.6.2' pod 'MJExtension', '~> 3.0.13' pod 'BearSkill' pod 'Masonry' pod 'IQKeyboardManager' pod 'Charts'end复制代码然而这样做还不行, OC与swift兼容还须要桥接文件 我的项目工程名-Bridging-Header.h 怎么产生这个文件呢, 不要本人去生成这个文件 最好是通过File->New->File->Swift File创立swift文件 这样做的话, 我的项目就会主动生成 我的项目工程名-Bridging-Header.h文件 并且在build setting中会多出 015A8C7C-1A70-43BA-8F6B-198EB8739728.png为什么不要本人去生成这个文件呢? 起因在于本人生成的这个文件, xcode无奈主动将生成$(SWIFT_MODULE_NAME)-Swift.h, 也就是图中的Objective-C Generated Interface Header Name这个选项 有了这个选项, 那么接下来在应用pod库中的swift文件都能够间接import 比方Charts #import <Charts/Charts-Swift.h> 在Charts后加一个-Swift.h即可 ...

November 19, 2021 · 1 min · jiezi

关于ios:拒绝编译等待-动态研发模式-ARK

作者:字节跳动终端技术——徐纪光 背景iOS 业界研发模式多为 CocoaPods + Xcode + Git 的多仓组件化开发模型。为谋求极致的研发体验、晋升研发效率,对该研发模式进行了大量优化,但目前遇到了以下瓶颈,亟需冲破: pod install 工夫长:编译优化绝大部分工作放在了 CocoaPods 上,CocoaPods 承当了更多工作,执行工夫因而变长。编译工夫长:尽管现阶段绝大部分工程曾经从源码编译转型成二进制编译,但编译耗时仍旧在十分钟左右,且现有工程根底上已无更好优化伎俩。超大型工程通病:Xcode Index 慢、爆内存、甚至卡死,链接工夫长。如何解决这些问题?究其实质,产生这些问题的起因在于工程规模宏大。据此咱们停下了对传统模式各节点的优化工作,以"放大工程规模"为切入点,摸索新型研发模式——动静研发模式 ARK。 ARK[1] 是全链路笼罩的动静研发模式,旨在保障工程体验的前提下放大工程规模:通过基线构建的形式,提供线下研发所需物料;同时通过实时的动静库转化技术,保障本地研发仅需下载和编译开发仓库。 Show Case动静研发模式本地研发流程图如下。接下来就以抖音产品为例,论述如何应用 ARK 做一次本地开发。 演示基于字节跳动本地研发工具 MBox[2] 。 流程图 仓库下载ARK 研发模式下,本地研发不再拉取主仓代码,取而代之的是 ARK 仓库。ARK 仓库含有与主仓对应的所有配置,一次适配接入前期不须要继续保护。 相较传统 APP 仓库动辄几个 GB 的大小,ARK 仓库贯彻了缩减代码规模这一概念。仓库仅有利用配置信息,不蕴含任何组件代码。ARK 仓库大小仅 2 MB,在 1 s 内能够实现仓库下载 。 在 MBox 中的应用仅需几步点击操作。首先抉择要开发的产品,而后勾选 ark 模式,抉择开发分支,最初点击 Create 便能够数秒实现仓库下载。 开发组件CocoaPods 下进行组件开发个别是将组件仓库下载到本地,批改 Podfile 对应组件 A 为本地援用 pod A, :path =>'./A' ,之后进行本地开发。而在 MBox 和 ARK 的研发流程中,仅需抉择要开发的组件点击 Add 便可进行本地开发。 ...

November 17, 2021 · 1 min · jiezi

关于ios:iOS-App-启动优化

简介: 作为程序猿来说,“性能优化”是咱们都很相熟的词,也是咱们须要一直努⼒以及继续进⾏的事件;其实优化是⼀个很⼤的课题,因为细分来说的话有⼤⼤⼩⼩⼗⼏种优化⽅向 ,然而切忌在理论开发过程中不能盲⽬的 为了优化⽽优化,这样有时可能会造成事与愿违的负成果,须要咱们依据理论场景以及业务需要进⾏正当优 化。接下来进⼊正题,本⽂将会以iOS App的启动优化为开展点进⾏探讨。 前言作为程序猿来说,“性能优化”是咱们都很相熟的词,也是咱们须要一直努⼒以及继续进⾏的事件;其实优化是⼀个很⼤的课题,因为细分来说的话有⼤⼤⼩⼩⼗⼏种优化⽅向 ,然而切忌在理论开发过程中不能盲⽬的 为了优化⽽优化,这样有时可能会造成事与愿违的负成果,须要咱们依据理论场景以及业务需要进⾏正当优 化。接下来进⼊正题,本⽂将会以iOS App的启动优化为开展点进⾏探讨。 启动流程: iOS App 的启动咱们都晓得分为 为pre-main 和 main() 两个阶段,并且在这两个阶段中,零碎会进 ⾏⼀系列的加载操作,过程如下: pre-main阶段 加载应⽤的可执⾏⽂件加载dyld动静连接器dyld递归加载应⽤所有依赖的动态链接库dylibmain()阶段 dyld调⽤ main()调⽤UIApplicationMain()调⽤applicationWillFinishLaunching调⽤didFinishLaunchingWithOptions阶段优化项 1、pre-main阶段 针对 pre-main 阶段做优化时,咱们须要先具体理解其加载过程,这个能够在2016年WWDC 的 Optimizing App Startup Time 中具体理解到, 相干资料 1.1 Load dylibs 这⼀阶段dyld会剖析应⽤依赖的 dylib (xcode7当前.dylib已改为名.tbd),找到其 mach-o ⽂件,关上和读取这些⽂件并验证其有效性,接着会找到代码签名注册到内核,最初对 dylib 的每⼀个 segment 调⽤ mmap()。不过这⾥的 dylib ⼤局部都是零碎库,不须要咱们去做额定的优化。 优化论断: 1、尽量不使⽤内嵌的dylib,从⽽防止减少 Load dylibs开销 2、合并已有的dylib和使⽤动态库(static archives),缩小dylib的使⽤个数 3、懒加载dylib,然而要留神dlopen()可能造成⼀些问题,且实际上懒加载做的⼯作会更多 1.2 Rebase/Bind 在dylib的加载过程中,零碎为了平安思考,引⼊了ASLR (Address Space Layout Randomization)技术和 代码签名。因为ASLR的存在,镜像(Image,包含可执⾏⽂件、 dylib和bundle)会在随机的地址上加载,和 之前指针指向的地址(preferred_address)会有⼀个偏差(slide), dyld须要修改这个偏差,来指向正确的 地址。 Rebase在前, Bind在后, Rebase做的是将镜像读⼊内存,修改镜像外部的指针,性能耗费次要在 IO。 Bind做的是查问符号表,设置指向镜像内部的指针,性能耗费次要在CPU计算。 ...

November 16, 2021 · 1 min · jiezi

关于ios:iOS精选面试题基础篇

面试题目都是网上收集,答复是本人尝试答复,网上的很多答复我感觉不肯定对,会本人批改,有问题心愿能够及时指出来 1.Object-c的类能够多重继承么?能够实现多个接口么?Category是什么?重写一个类的形式用继承好还是分类好?为什么?1.OC没有多重集成2.但能够遵循多个协定也就是protocol3.Category是类别4.重写一个类的形式,用继承好还是分类好?为什么?这个问题中“重写”和“形式”这两个词就很奇怪,这个类如果是你本人写的,对不称心的中央间接批改就能够了,干嘛要继承和分类退场呢?即便这个类你没源码,然而你对这个类各种不称心,你要重写一个类代替,也跟继承和分类没间接关系啊。我从两个方向去尝试猜想下这道面试题的意思,猜想1:“形式”改为“”办法“,面试官是想问重写一个类的办法,用继承好还是分类好?这里网上的很多答复曾经重大不对了,例如网上大多答复是这样的: “个别状况用分类好,用Category去重写类的办法,仅对本Category无效,不会影响到其余类与原有类的关系”这个答复如果回答者的意思是说如果其余类没有引入这个分类,就不会调用到分类的实现,还会是这个类原有的实现,就打错特错了,实际上如果只有你分类笼罩了这个类的某个办法的实现,你在工程中即便不引入这个分类,也都会调用到分类的实现。咱们能够写代码试下:咱们先新建一个工程,而后写一个Test的类,间接继承NSObject就好,而后咱们定义了两个办法,一个办法让分类间接笼罩,一个分类间接笼罩真正的实现 - (NSString *)whoAmI; //让分类间接笼罩- (void)indirectMethodTest; //分类笼罩间接的办法实现代码如下 - (NSString *)whoAmI { return @"Test";}- (void)indirectMethodTest { [self iAmDirect]; //真正调用的是iAmDirect}- (void)iAmDirect { NSLog(@"iAmDirect Test");}而后咱们让分类别离实现,“whoAmI”和“iAmDirect” - (NSString *)whoAmI { return @"Test+Change";}- (void)iAmDirect { NSLog(@"iAmDirect Test+Change");}咱们在管制其中不引入类别只引入Test.h控制器viewDidLoad退出如下代码 Test *test = [Test new]; NSString *string = [test whoAmI]; NSLog(@"string = %@", string); [test indirectMethodTest];而后控制台打印下这两个办法的后果 能够发现即便你没引入类别,这个类的实现,也会被分类的办法替换掉,具体起因,能够看下分类的实现原理,我当前会具体说下,简略来说就是runtime把categoray实现的办法,放在了原来类办法的后面,这样必然每次都会先找到分类的办法。不过要记住分类只会笼罩这个类的原有实现,对子类是不会笼罩的,这个是msgsend的调用流程决定的。所以针对猜想1,重写一个类的办法来说,我感觉用继承最好,除非你真的感觉这个原来的办法没救了,你要一劳永逸的替换原有类的实现,而且不想批改应用到这个办法的其余类的代码了,你也曾经告诉了你在的开发组共事了,你能够去这么做,不过这种形式切实不明智,连苹果都给了正告不要这么做 ”Category is implementing a method which will also be implemented by its primary class“用继承的形式则要好的多:1.你用子类重写这办法之后,你只须要在不称心的中央,用子类替换即可,不须要改的中央,还能够持续应用以前的类。2.能够应用super调用这个类的原来的实现前后,子类做一些批改,因为子类的super指向的是这个类,而类别的super,指向的是还是这个类的父类,因为类别毕竟不是继承啊。 猜想2:重写改为扩大,面试官想问:扩大一个类的形式,用继承好还是分类好?为什么?这个好答复很多,就是问继承和分类的区别,优劣势。继承:1.要重写原来类中的办法,但父类的这个办法也想持续应用。2.减少成员变量,属性 类别:1.零碎特定类没法继承,重点说的就是类簇,比方NSString,NSArray,NSNumber等,这些返回的实在的类,都是一些公有暗藏的类,如果继承,将相当麻烦。相同应用类别去扩大一些性能,将不便很多。2.用分类,将一些简单的类,按性能将的办法拆分到独自的文件中,能够进步可维护性,iOS零碎中的类就常常这么做。例如把NSObject延时执行的办法例如: (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay等办法放到了runloop文件中,因为这些办法runloop相干的。 ...

November 10, 2021 · 1 min · jiezi

关于ios:ios113之前H5中input框光标位置怪异不正确已解决

问题形容:在ios11.3之前H5中在弹出层应用input框,光标地位怪异(不正确),偶现状况,在后续ios更新中,曾经将此bug修复,然而为了避免用户零碎低导致问题,还是做了适配。 起因:是因为在弹出层中应用了position:fixed导致的ios定位不精确,ios解析fixed有问题。 解决1:在弹出层中不要应用position:fixed; 解决2:不免还是应用position:fixed是比拟寻常的,所以,另外一种解决形式:在input onfocus时,设置: document.body.style.position = 'fixed'; //ios11 适配光标地位问题在input onBlur时,设置: document.body.style.position = 'static'; //ios11 适配光标地位问题解决3:如果能够,间接设置body的css款式 position: fixed; width: 100%;以上,依据状况能够自选形式尝试修复!

November 5, 2021 · 1 min · jiezi

关于ios:划重点|iOS15正式发布-全新的通知推送系统你必须要知道

简介: 往年友盟+联结达摩院决策智能实验室讲算法技术,推出国内首个智能推送性能,帮忙产品经营人员实现一键式触达的精细化经营。通过精心打磨的在线学习与优化算法,对推送人群与推送文案进行精准匹配,最大化用户点击量。通过对不同用户场景感知和各种束缚配额下的最佳调配,将无用推送信息降权显示,升高对用户的烦扰,优化用户维度的推送体验。 作者:友盟+ 技术团队 越来越多的APP频繁推送信息曾经导致用户不堪重负,友盟+ 数据显示:45%的iOS用户被动敞开了告诉权限。 为了激励开发者更正当的应用推送告诉。近日,苹果iOS 15公布了全新的告诉推送零碎,并对告诉零碎进行大范畴的优化,友盟+ 技术团队为开发者划了三个重点,让你轻松理解全新的告诉推送零碎。 第一、苹果为iOS15设计了4种告诉分级 passive(被动型告诉):指用户在空闲时查看信息,比方餐厅举荐。active(流动型告诉):指用户心愿在某个工夫理解的信息,比方最喜爱的球队的最新比分。time-sensitive(工夫敏感型告诉):指须要用户立即关注到的告诉,比方快递进度。critical(要害告诉):须要立即得悉且优先级超高的告诉,比方来自政府机构的平安告诉等。 Apns最新文档中,苹果为iOS15设计了4种告诉分级,激励开发者正确的设置告诉级别以带给用户更好的体验。但文档中依然强调了“Build trust by accurately representing the urgency of each notification. ”,苹果并不会对告诉级别做更多干涉。 告诉级别通过在Apns发送中新增参数实现 interruption-level: 告诉级别有“passive”, “active”, “time-sensitive”, “critical”四个选项,默认“active”。 第二、新增摘要性能 在iOS15零碎的设置-告诉选项中新增了摘要性能,摘要开启后会缓存“passive” (被动型告诉),“active” (流动型告诉)级别的告诉,并在配置的工夫点批量显示。告诉摘要通过自定义时段聚合信息的形式解决用户工夫被大量非紧急信息碎片化的问题。比方在你追一部剧并订阅了相干更新告诉,你心愿绝对及时的获取信息然而又不心愿在工作工夫频繁收到也没有精力解决这类信息。个别厂商并不分明用户的时段诉求,这造成了用户抉择两难的窘境。通过告诉摘要,用户可抉择在一天中的哪些时间段一次性的浏览相干信息,进步信息获取效率和体验。 亮屏解锁状态下开启了摘要,且敞开“显示下个摘要”告诉不会弹框,不会触动响铃。用户无奈感知告诉达到,直至下次摘要指定工夫批量一次性显示。亮屏解锁状态下开启摘要,且开启“显示下个摘要”告诉不会触动响铃声,弹框会被对立收揽到“您的下个摘要”分组。黑屏状态下,开启摘要的APP会放弃静默状态,除非收到“time-sensitive”, “critical”级别告诉。Apns提到可通过减少relevance-score实现告诉摘要的排序,目前测试发现该性能未实装。 第三、推出场景相干的专一模式 iOS15推出了场景相干的专一模式,开发者可通过将音讯告诉级别设置成“passive”,“active”防止对专一模式的用户产生打搅。开启专一模式后告诉被对立收录到“专一模式期间”分组,不会响铃触动。同时专一模式还反对快捷时间段设定、地位设定主打场景相干。 将来的告诉体验博弈 从Android8到iOS15曾经进入了博弈红海阶段。将来开发者面临告诉服务的多项挑战。厂商通道通过告诉分类逐步推进告诉限额,告诉作为从来被粗放漫灌的触达能力亟待回归ROI实质,解决老本问题问题。与以往对送达率的一味谋求不同,将来考验怎么用更少的告诉发送,更弱的用户打搅度获取更高的用户踊跃反馈。长期以来开发者在告诉场景中次要关注送达率,历史中不乏通过流氓过程、频繁自启、链式唤起等伎俩一味谋求送达率。近些年,更多开发者尤其是行业TOP级产品将指标转向了点击率和理论业务正反馈(如唤起率)。对告诉经营提出了更高的要求。业务更加直白的关注告诉所带来的业务成果,其中用户体验是绕不过来的一环。 往年友盟+联结达摩院决策智能实验室讲算法技术,推出国内首个智能推送性能,帮忙产品经营人员实现一键式触达的精细化经营。通过精心打磨的在线学习与优化算法,对推送人群与推送文案进行精准匹配,最大化用户点击量。通过对不同用户场景感知和各种束缚配额下的最佳调配,将无用推送信息降权显示,升高对用户的烦扰,优化用户维度的推送体验。 发送成果见顶,数据技术能力凸显 用户群品质:适合的音讯发给适合的人,考验开发者用户疏导和积淀能力。 告诉通道品质:保障用户及时精确的获取告诉,依赖告诉服务商技术实力和服务质量。 经营策略成果:怎么收回适合的时刻和频次的告诉。 能够预感iOS15的遍及会极大影响用户点击志愿从而升高点击率,随着《个保法》落地,将来开发者和用户博弈的天平逐步向用户歪斜。在正当合规非法的大环境下,对要害数据的解决能力在告诉成果的评判中更加重要,告诉服务商须要更多施展数据技术的短处为开发者经营提供助力。 以上,就是友盟+ 技术团队针对iOS15公布的告诉推送零碎所划的重点。置信随着iOS15的遍及,用户点击志愿会受到极大影响, 那么,开发者将来则须要借助更智能的算法,发送更优质的内容,能力牢牢抓住用户的心。 原文链接本文为阿里云原创内容,未经容许不得转载。

November 5, 2021 · 1 min · jiezi

关于ios:Mac上自制终端命令行程序

终端(Shell)上命令实质上就是可执行程序。那么如何实现本人的命令,如何让Shell能辨认和运行咱们本人的可执行程序呢? 运行环境用户在Shell中输出一个外部命令后,只是将可执行文件的名字通知了Shell,而后Shell就会去寻找这个文件并执行。 为了解决这个问题shell引入了一个PATH变量 $echo $PATH /usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbinShell即会到PATH对应的目录中找寻用户输出的命令程序,当然咱们能够追加本人的可执行文件目录,也就是常说的环境变量配置 实现可执行文件接下来用OC来实现一个可执行程序,首先Xcode创立一个Command Line Tool 创立完失去一个洁净的C语言的main函数入口 1. 获取输出参数首先配置main函数输出参数,仅在Xcode运行测试应用,Product-Scheme-Edit Scheme-Arguments int main(int argc, const char * argv[]) { @autoreleasepool { for (int i =0; i< argc; i++) { printf("输出参数:%s\n",argv[i]); } } return 0;}失去以下输入 输出参数:/Users/niang/Library/Developer/Xcode/DerivedData/TSProj-celbcreghvkbbochdmxixomyftvb/Build/Products/Debug/MyCMD输出参数:aaa输出参数:bbbProgram ended with exit code: 0由输入可得,第一个参数默认是可执行程序所在的目录 2. 终端运行测试首先配置以后可执行文件目录到PATH export MY_CMD_PATH=/Users/niang/Library/Developer/Xcode/DerivedData/TSProj-celbcreghvkbbochdmxixomyftvb/Build/Products/Debug/export PATH=$MY_CMD_PATH:$PATH再输出咱们的程序名,疏忽大小写 第一个参数并未如之前猜想那样的是可执行文件目录,它仅仅输入一个程序名 3. 获取可执行文件目录和以后所在目录int main(int argc, const char * argv[]) { @autoreleasepool { NSString *url = [NSBundle mainBundle].executableURL.absoluteString; url = [url stringByReplacingOccurrencesOfString:@"file://" withString:@""]; url = [url stringByDeletingLastPathComponent]; printf("可执行文件目录 : %s\n", url.UTF8String); //https://stackoverflow.com/questions/65702034/getcwd-vs-get-current-dir-name char cd_path[256]; memset(cd_path, 0, sizeof(cd_path)); if (getcwd(cd_path, sizeof(cd_path)) == NULL) { perror("getcwd"); exit(EXIT_FAILURE); // or abort() } NSString *cdPath = [NSString stringWithUTF8String:cd_path]; printf("shell当前目录 : %s\n", cdPath.UTF8String); } return 0;} ...

November 2, 2021 · 1 min · jiezi

关于ios:划重点|iOS15正式发布-全新的通知推送系统你必须要知道

作者:友盟+ 技术团队 越来越多的APP频繁推送信息曾经导致用户不堪重负,友盟+ 数据显示:45%的iOS用户被动敞开了告诉权限。 为了激励开发者更正当的应用推送告诉。近日,苹果iOS 15公布了全新的告诉推送零碎,并对告诉零碎进行大范畴的优化,友盟+ 技术团队为开发者划了三个重点,让你轻松理解全新的告诉推送零碎。 第一、苹果为iOS15设计了4种告诉分级 passive(被动型告诉):指用户在空闲时查看信息,比方餐厅举荐。active(流动型告诉):指用户心愿在某个工夫理解的信息,比方最喜爱的球队的最新比分。time-sensitive(工夫敏感型告诉):指须要用户立即关注到的告诉,比方快递进度。critical(要害告诉):须要立即得悉且优先级超高的告诉,比方来自政府机构的平安告诉等。 Apns最新文档中,苹果为iOS15设计了4种告诉分级,激励开发者正确的设置告诉级别以带给用户更好的体验。但文档中依然强调了“Build trust by accurately representing the urgency of each notification. ”,苹果并不会对告诉级别做更多干涉。 告诉级别通过在Apns发送中新增参数实现 interruption-level: 告诉级别有“passive”, “active”, “time-sensitive”, “critical”四个选项,默认“active”。 第二、新增摘要性能 在iOS15零碎的设置-告诉选项中新增了摘要性能,摘要开启后会缓存“passive” (被动型告诉),“active” (流动型告诉)级别的告诉,并在配置的工夫点批量显示。告诉摘要通过自定义时段聚合信息的形式解决用户工夫被大量非紧急信息碎片化的问题。比方在你追一部剧并订阅了相干更新告诉,你心愿绝对及时的获取信息然而又不心愿在工作工夫频繁收到也没有精力解决这类信息。个别厂商并不分明用户的时段诉求,这造成了用户抉择两难的窘境。通过告诉摘要,用户可抉择在一天中的哪些时间段一次性的浏览相干信息,进步信息获取效率和体验。 亮屏解锁状态下开启了摘要,且敞开“显示下个摘要”告诉不会弹框,不会触动响铃。用户无奈感知告诉达到,直至下次摘要指定工夫批量一次性显示。亮屏解锁状态下开启摘要,且开启“显示下个摘要”告诉不会触动响铃声,弹框会被对立收揽到“您的下个摘要”分组。黑屏状态下,开启摘要的APP会放弃静默状态,除非收到“time-sensitive”, “critical”级别告诉。Apns提到可通过减少relevance-score实现告诉摘要的排序,目前测试发现该性能未实装。 第三、推出场景相干的专一模式 iOS15推出了场景相干的专一模式,开发者可通过将音讯告诉级别设置成“passive”,“active”防止对专一模式的用户产生打搅。开启专一模式后告诉被对立收录到“专一模式期间”分组,不会响铃触动。同时专一模式还反对快捷时间段设定、地位设定主打场景相干。 将来的告诉体验博弈 从Android8到iOS15曾经进入了博弈红海阶段。将来开发者面临告诉服务的多项挑战。厂商通道通过告诉分类逐步推进告诉限额,告诉作为从来被粗放漫灌的触达能力亟待回归ROI实质,解决老本问题问题。与以往对送达率的一味谋求不同,将来考验怎么用更少的告诉发送,更弱的用户打搅度获取更高的用户踊跃反馈。长期以来开发者在告诉场景中次要关注送达率,历史中不乏通过流氓过程、频繁自启、链式唤起等伎俩一味谋求送达率。近些年,更多开发者尤其是行业TOP级产品将指标转向了点击率和理论业务正反馈(如唤起率)。对告诉经营提出了更高的要求。业务更加直白的关注告诉所带来的业务成果,其中用户体验是绕不过来的一环。 往年友盟+联结达摩院决策智能实验室讲算法技术,推出国内首个智能推送性能,帮忙产品经营人员实现一键式触达的精细化经营。通过精心打磨的在线学习与优化算法,对推送人群与推送文案进行精准匹配,最大化用户点击量。通过对不同用户场景感知和各种束缚配额下的最佳调配,将无用推送信息降权显示,升高对用户的烦扰,优化用户维度的推送体验。 发送成果见顶,数据技术能力凸显 用户群品质:适合的音讯发给适合的人,考验开发者用户疏导和积淀能力。 告诉通道品质:保障用户及时精确的获取告诉,依赖告诉服务商技术实力和服务质量。 经营策略成果:怎么收回适合的时刻和频次的告诉。 能够预感iOS15的遍及会极大影响用户点击志愿从而升高点击率,随着《个保法》落地,将来开发者和用户博弈的天平逐步向用户歪斜。在正当合规非法的大环境下,对要害数据的解决能力在告诉成果的评判中更加重要,告诉服务商须要更多施展数据技术的短处为开发者经营提供助力。 以上,就是友盟+ 技术团队针对iOS15公布的告诉推送零碎所划的重点。置信随着iOS15的遍及,用户点击志愿会受到极大影响, 那么,开发者将来则须要借助更智能的算法,发送更优质的内容,能力牢牢抓住用户的心。 欢送退出友盟+ 技术社群, 定期理解挪动开发者最新干货,更多精彩技术实际与独家干货解析。

November 1, 2021 · 1 min · jiezi

关于ios:自己做一款的AI相机App一魔法相机开源项目简介

我的项目起源你可能这App Store中搜到过很多AI相机App,提供各种AI变脸特效,这些性能都是怎么实现的呢?咱们本人能不能开发一款相近性能的App呢?出于这样的想法,就有了“魔法相机”这个开源我的项目。接下来的一段时间里,我会不断更新这个系列文章,和大家分享开发过程和各种技术细节,心愿能对大家有帮忙。 我的项目介绍魔法相机是一款基于SwiftUI和CoreML开发的 iOS AI 相机利用,实现了下列性能: 人像卡通化,能够让你的照片变成卡通头像人像格调迁徙,能够让你的照片变老、变年老、变发色等美颜相机,反对磨皮、瘦脸和各种滤镜成果艺术成果,让你的照片别成各种艺术风格 我的项目地址: william0wang/MagicCamera (github.com) 后续打算首先,打算将来一段时间,把开发过程中的心得和各种技术细节通过文章分享给大家,心愿对大家能用帮忙。 在性能方面,以后曾经实现了AI相机App最风行的拍照性能。后续打算会减少更多视频相干性能,例如视频变脸等。

November 1, 2021 · 1 min · jiezi

关于ios:探秘WKWebView

概述之前次要应用UIWebView进行页面的加载,然而UIWebView存在很多问题,在2020年曾经被苹果正式摈弃。所以本篇文章次要解说WKWebView,WKWebView从iOS8开始反对,当初大多数App应该都不反对iOS7了。 UIWebView存在两个问题,一个是内存耗费比拟大,另一个是性能很差。WKWebView绝对于UIWebView来说,性能要比UIWebView性能要好太多,刷新率能达到60FPS。内存占用也比UIWebView要小。 WKWebView是一个多过程组件,Network、UI Render都在独立的过程中实现。 因为WKWebView和App不在同一个过程,如果WKWebView过程解体并不会导致利用解体,仅仅是页面白屏等异样。页面的载入、渲染等耗费内存和性能的操作,都在WKWebView的过程中解决,解决后再将后果交给App过程用于显示,所以App过程的性能耗费会小很多。 网页加载流程通过域名的形式申请服务器,申请前浏览器会做一个DNS解析,并将IP地址返回给浏览器。浏览器应用IP地址申请服务器,并且开始握手过程。TCP是三次握手,如果应用https则还须要进行TLS的握手,握手后依据协定字段抉择是否放弃连贯。握手实现后,浏览器向服务端发送申请,获取html文件。服务器解析申请,并由CDN服务器返回对应的资源文件。浏览器收到服务器返回的html文件,交由html解析器进行解析。解析html由上到下进行解析xml标签,过程中如果遇到css或资源文件,都会进行异步加载,遇到js则会挂起以后html解析工作,申请js并返回后持续解析。因为js文件可能会对DOM树进行批改。解析完html,并执行完js代码,造成最终的DOM树。通过DOM配合css文件找出每个节点的最终展现款式,并交由浏览器进行渲染展现完结链接。代理办法WKWebView和UIWebView的代理办法产生了一些扭转,WKWebView的流程更加细化了。例如之前UI完结申请后,会立即渲染到webView上。而WKWebView则会在渲染到屏幕之前,会回调一个代理办法,代理办法决定是否渲染到屏幕上。这样就能够对申请下来的数据做一次校验,避免数据被更改,或验证视图是否容许被显示到屏幕上。 除此之外,WKWebView绝对于UIWebView还多了一些定制化操作。 重定向的回调,能够在申请重定向时获取到这次操作。当WKWebView过程异样退出时,能够通过回调获取。自定义解决证书。更深层的UI定制操作,将alert等UI操作交给原生层面解决,而UI计划UIAlertView是间接webView显示的。WKUIDelegateWKWebView将很多UI的显示都交给原生层面去解决,例如弹窗或者输入框的显示。这样如果我的项目里有对立定义的弹窗,就能够间接调用自定义弹窗,而不是只能展现零碎弹窗。 在WKWebView中,零碎将弹窗的显示交由客户端来管制。客户端能够通过上面的回调办法获取到弹窗的显示信息,并由客户端来调起UIAlertController来展现。参数中有一个completionHandler的回调block,须要客户端肯定要调用,如果不调用则会产生解体。 - (void)webView:(WKWebView *)webView runJavaScriptAlertPanelWithMessage:(NSString *)message initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(void))completionHandler;有时候H5会要求用户进行一些输出,例如用户名明码之类的。客户端能够通过上面的办法获取到输入框事件,并由客户端展现输入框,用户输出实现后将后果回调给completionHandler中。 - (void)webView:(WKWebView *)webView runJavaScriptTextInputPanelWithPrompt:(NSString *)prompt defaultText:(nullable NSString *)defaultText initiatedByFrame:(WKFrameInfo *)frame completionHandler:(void (^)(NSString * _Nullable result))completionHandler;WKNavigationDelegate对于加载流程相干的办法,都被形象到WKNavigationDelegate中,这里挑几个比拟罕用的办法讲一下。 上面的办法,通过decisionHandler回调中返回一个枚举类型的参数,示意是否容许页面加载。这里能够对域名进行判断,如果是站外域名,则能够提醒用户是否进行跳转。如果是跳转其余App或商店的URL,则能够通过openURL进行跳转,并将这次申请拦挡。包含cookie的解决也在此办法中实现,前面会具体讲到cookie的解决。 除此之外,很多页面显示前的逻辑解决,也在此办法中实现。但须要留神的是,办法中不要做过多的耗时解决,会影响页面加载速度。 - (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler;开始加载页面,并申请服务器。 - (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(null_unspecified WKNavigation *)navigation;当页面加载失败的时候,会回调此办法,包含timeout等谬误。在这个页面能够展现谬误页面,清空进度条,重置网络指示器等操作。须要留神的是,调用goBack时也会执行此办法,能够通过error的状态判断是否NSURLErrorCancelled来过滤掉。 - (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error;页面加载及渲染实现,会调用此办法,调用此办法时H5的dom曾经解析并渲染实现,展现在屏幕上。所以在此办法中能够进行一些加载实现的操作,例如移除进度条,重置网络指示器等。 - (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation;WKUserContentController回调WKWebView将和js的交互都由WKUserContentController类来解决,前面统称为userContent。 如果须要接管并解决js的调用,通过调用addScriptMessageHandler:name:办法,并传入一个实现了WKScriptMessageHandler协定的对象,即可接管js的回调,因为userContent会强援用传入的对象,所以应该是新创建一个对象,而不是self。注册对象时,前面的name就是js调用的函数名。 WKUserContentController *userContent = [[WKUserContentController alloc] init];[userContent addScriptMessageHandler:[[WKWeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"clientCallback"];在dealloc中应该通过上面的办法,移除对指定name的解决。 ...

November 1, 2021 · 3 min · jiezi

关于ios:MAC切换Flutter版本

历史背景:原先我的项目中应用了MXFlutter框架且指定应用v1.17.0版本的flutter SDK,但其余我的项目又想应用最新版本flutter的个性。 1.拷贝一份原有的flutter SDK,命名加对应的版本号 2.将现有flutter v1.17.0 进行降级 $ flutter upgrade3.配置环境变量 4.批改MY_FLUTTER_PATH后刷新环境变量 $ source ~/.bash_profile5.查看以后flutter环境是否失常 $ flutter doctor

October 27, 2021 · 1 min · jiezi

关于ios:如何优化iOS系统上的图文评论UI界面

在咱们的社交 APP 上,⽤户的动静由精美的照⽚ 、视频和⽂字组成。对于每张照⽚和视频, 咱们都会展现出残缺的题目和五个最新评论。 因为⽤户喜爱使⽤题目来讲述照⽚背地的故事,因而它们通常很⻓ 、很简单,并且可能蕴含超链接和表情符号。 渲染如此简单的⽂本带来了⼀些问题,它在滚动时造成性能降落。 即便在 iPhone 12 这样的新设施上,简单题目的初始⽂本绘制须要⻓达 50 毫秒,⽽⽂本展现须要⻓达 30 毫秒,渲染速度很慢。 ⽂本问题还是简略问题,有时咱们须要加载更加简单的图⽚甚⾄视频。 所有这些步骤都发⽣在 UI 线程上,导致app在⽤户滚动时丢帧。 当主线程必须解决太多操作时,最常⻅的结果是呈现丢帧景象,当咱们不能保障 60 fps (每 16.67 毫秒⼀ 帧) 时就会发⽣这种景象。 基础知识在开始之前,最好先理解本⽂的基本概念。 主线程不应该⽤于沉重的操作,⽽次要⽤于:1、承受⽤户输⼊/交互;2、显示后果并更新 UI。 精准地辨认并调试丢帧问题有时咱们很容易发现掉帧问题,因为掉帧最常⻅的表现形式是⽆响应/卡顿。 咱们能够使⽤友盟+ U-APM查看在 iPhone12 这样的新款设施上是否会发⽣卡顿。 显⽽易⻅在 iPhone12 上也发⽣了卡顿,由此推断咱们的代码存在优化空间,⽽并⾮⽤户的设施 配置问题。 接下来,咱们须要更精确的⽅法来跟踪卡顿问题。 咱们尝试了使⽤ CADisplayLink 和 TimeProfiler。 使⽤ CADisplayLink 类: class DroppingFramesHelper: NSObject {private var firstTime: TimeInterval = 0.0private var lastTime: TimeInterval = 0.0func activate() {let link = CADisplayLink(target: self, selector: #selector(updatlink.add(to: .main, forMode: .commonModes)}@objc private func update(link: CADisplayLink) {if lastTime == 0 {firstTime = link.timestamplastTime = link.timestamp}let currentTime = link.timestamplet elapsedTime = floor((currentTime - lastTime) * 10_000)/10let totalElapsedTime = currentTime - firstTimeif elapsedTime > 16.7 {print("[DFH] Frame was dropped with elpased time of \(elapse}lastTime = link.timestamp}}而后, 在 AppDelegate 的⽅法中拜访它的⼀个实例: ...

October 27, 2021 · 2 min · jiezi

关于ios:iOS计算Label的最合适的Size

iOS中常常有须要给Label一个最合适的宽度和高度,京东和淘宝的搜寻历史就是个典型利用:对于计算方法,以前始终应用的是NSString的一个办法: - (CGRect)boundingRectWithSize:(CGSize)size options:(NSStringDrawingOptions)options attributes:(nullable NSDictionary<NSAttributedStringKey, id> *)attributes context:(nullable NSStringDrawingContext *)context API_AVAILABLE(macos(10.11), ios(7.0));应用的例子如下,这里是想获取适合的宽度,就要给宽度传入一个很大的值,而后高度给一个固定的值: - (CGFloat)textWidth:(NSString *)text { CGFloat width = [text boundingRectWithSize:CGSizeMake(1000, 30) options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : [UIFont systemFontOfSize:14]} context:nil].size.width + 20; return width;}然而这个办法其实很不精确,所以大多还会在返回的根底上,加一个值,例如下面这个代码就加20,以防止给的宽度过小,导致无奈显示齐全。可即便这样做了,返回的这个宽度,我发现依然有可能偏小,并会引起一些UI问题,例如我在做这个历史搜寻界面的时候,就发现有些label,最右面会有一条线,如下所示:我一开始认为是我不小心加了一条线在Label上,后果用xcode查看了视图层级,发现没有其余图层了,我狐疑可能给的这个宽度不对,导致呈现的这个问题,我采纳了另外的办法,这个是UIView的一个办法,不过宽度不对,导致这条线呈现的更深层次的起因,应该是UILabel的实现的问题。: - (CGSize)sizeThatFits:(CGSize)size; // return 'best' size to fit given size. does not actually resize view. Default is return existing view size官网的正文曾经通知咱们这个,这个能够给出最佳的size,应用的时候必须是曾经实例化进去的View,比方Label的话,要先初始化,而后赋值text和font,例子如下: UILabel *contentLabel = [[UILabel alloc] initWithFrame:CGRectZero]; contentLabel.font = [UIFont systemFontOfSize:14]; contentLabel.text = historyArray[i]; CGFloat nowWidth = [self widthForLabel:contentLabel andheight:kSearchHistorySubViewHeight] ......- (CGFloat)widthForLabel:(UILabel *)label andheight:(CGFloat)height { CGSize sizeToFit = [label sizeThatFits:CGSizeMake(MAXFLOAT, height)]; CGFloat width = sizeToFit.width + 10; return width;}这个计算出的宽度的确准确,但都贴着字符的边了,所以咱们要加点宽度,不然很不美观。当前label再须要计算准确的宽度或高度,最好用这个办法了。 ...

October 27, 2021 · 1 min · jiezi

关于ios:IOS-APP启动优化

前言作为程序猿来说,“性能优化”是咱们都很相熟的词,也是咱们须要一直努⼒以及继续进⾏的事件;其实优化 是⼀个很⼤的课题,因为细分来说的话有⼤⼤⼩⼩⼗⼏种优化⽅向 ,然而切忌在理论开发过程中不能盲⽬的 为了优化⽽优化,这样有时可能会造成事与愿违的负成果,须要咱们依据理论场景以及业务需要进⾏正当优 化。接下来进⼊正题,本⽂将会以iOS App的启动优化为开展点进⾏探讨。 启动流程iOS App 的启动咱们都晓得分为pre-main 和 main() 两个阶段,并且在这两个阶段中,零碎会进⾏⼀系列的加载操作,过程如下: 1、 pre-main阶段1、加载应⽤的可执⾏⽂件2、加载dyld动静连接器3、dyld递归加载应⽤所有依赖的动态链接库dylib 2、 main()阶段1、dyld调⽤ main()2、调⽤ UIApplicationMain()3、调⽤ applicationWillFinishLaunching4、调⽤ didFinishLaunchingWithOptions 阶段优化项1、 pre-main阶段针对 pre-main 阶段做优化时,咱们须要先具体理解其加载过程,这个能够在2016年WWDC 的Optimizing App Startup Time 中具体理解到相干资料 1.1 Load dylibs 这⼀阶段dyld会剖析应⽤依赖的 dylib (xcode7当前.dylib已改为名.tbd),找到其 mach-o ⽂件,关上和读取这些⽂件并验证其有效性,接着会找到代码签名注册到内核,最初对 dylib 的每⼀个segment 调⽤ mmap() 。不过这⾥的 dylib ⼤局部都是零碎库,不须要咱们去做额定的优化。 优化论断: 1、尽量不使⽤内嵌的dylib,从⽽防止减少 Load dylibs开销2、合并已有的dylib和使⽤动态库(static archives),缩小dylib的使⽤个数3、懒加载dylib,然而要留神dlopen()可能造成⼀些问题,且实际上懒加载做的⼯作会更多 1.2 Rebase/Bind 在dylib的加载过程中,零碎为了平安思考,引⼊了ASLR (Address Space Layout Randomization)技术和代码签名。因为ASLR的存在,镜像(Image,包含可执⾏⽂件、dylib和bundle)会在随机的地址上加载,和之前指针指向的地址(preferred_address)会有⼀个偏差(slide), dyld须要修改这个偏差,来指向正确的地址。Rebase在前,Bind在后,Rebase做的是将镜像读⼊内存,修改镜像外部的指针,性能耗费次要在IO。 Bind做的是查问符号表,设置指向镜像内部的指针,性能耗费次要在CPU计算。 在此过程中,咱们须要留神的是尽量减少指针数量,⽐如:1、缩小ObjC类(class)、⽅法(selector)、分类(category)的数量2、缩小C++虚函数的的数量(创立虚函数表有开销)3、使⽤ Swift struct (外部做了优化,符号数量更少) 1.3 Objc setup⼤局部ObjC初始化⼯作曾经在Rebase/Bind阶段做完了,这⼀步dyld会注册所有申明过的ObjC类,将分类插 ⼊到类的⽅法列表⾥,再查看每个selector的唯⼀性。在这⼀步倒没什么优化可做的, Rebase/Bind阶段优化好了,这⼀步的耗时也会缩小。 1.4 Initializers在这⼀阶段,dyld开始运⾏程序的初始化函数,调⽤每个Objc类和分类的+load⽅法,调⽤C/C++ 中的结构器 函数(⽤attribute((constructor))润饰的函数),和创立⾮根本类型的C++动态全局变量。Initializers阶段执⾏ 完后,dyld开始调⽤main()函数。 ...

October 26, 2021 · 1 min · jiezi

关于ios:iOS-组件化构思

一、iOS 组件化罕用形式探讨应用openURL进行组件的注册和调用 App 启动时实例化各组件模块,而后这些组件向 ModuleManager 注册 URL ,有些时候不须要实例化,应用 class 注册。当组件A须要调用组件B时,向 ModuleManager 传递 URL ,参数追随 URL 以 GET 形式传递,相似openURL 。而后由 ModuleManager 负责调度组件B,最初实现工作。 计划剖析第一步的问题,在组件化的过程中,注册 URL 并不是充沛必要条件,组件是不须要向组件管理器注册Url的。而且注册了 URL 之后,会造成不必要的内存常驻,如果只是注册Class,内存常驻量就小一点,如果是注册实例,内存常驻量就大了。第二步。在 iOS 畛域里,肯定是组件化的中间件为 openURL 提供服务,而不是 openURL 形式为组件化提供服务。问题在于无奈表白非常规对象。如果是传递简单对象,如 UIImage ,只能做如下表白 [a openUrl:@"http://baidu.com/detail" params:@{ @"id":"abc123", @"type":"1", @"image":[UIImage imageNamed:@"iOSImage"]}]如果不像下面这么做,简单参数和非常规参数就无奈传递。如果这么做了,那么事实上这就是拆分近程调用和本地调用的入口了。URL 注册对于施行组件化计划是不必要的,且通过 URL 注册的形式造成的组件化计划,拓展性和可维护性都会被打折。注册 URL 的目标其实是一个服务发现的过程,在 iOS 畛域中,服务发现的形式是不须要通过被动注册的,应用 runtime 就能够了。另外,注册局部的代码的保护是一个绝对麻烦的事件,每一次反对新调用时,都要去保护一次注册列表。如果有调用被弃用了,是常常会遗记删我的项目的。runtime 因为不存在注册过程,那就也不会产生保护的操作,保护老本就升高了。 二、对组件化的构思以上形式次要是基于 Mediator 模式和 Target-Action 模式,两头采纳了 Runtime 来实现调用。这套组件化计划将近程利用调用和本地利用调用做了拆分,而且是由本地利用调用为近程利用调用提供服务,与罕用计划正好相同。 调用形式先说本地利用调用,本地组件A在某处调用[[Mediator sharedInstance] performTarget:targetName action:actionName params:@{...}]向 Mediator 发动跨组件调用,Mediator 依据取得的 target 和 action 信息,通过 Objective-C 的 runtime 转化生成 target 实例以及对应的 action 抉择子,而后最终调用到指标业务提供的逻辑,实现需要。 ...

October 26, 2021 · 1 min · jiezi

关于ios:iOS-组件化模块化架构设计实践

一、背景业务组件化(或者叫模块化)作为挪动端利用架构的支流形式之一,近年来始终是业界积极探索和实际的方向。有赞挪动团队自16年起也在一直尝试各种组件化计划,在有赞微信商城,有赞批发,有赞美业等多个利用中进行了实际。咱们踩过一些坑,也播种了很多贵重的教训,并积淀出 iOS 相干框架 Bifrost (雷神里的彩虹桥)。在过程中咱们粗浅领会到“没有相对正确的架构,只有最合适的架构”这句话的意义。 iOS 组件化/模块化的计划有很多,咱们只提供一种实现思路,对遇到相似问题的同学能有所启发,并不筹备对组件化架构设计计划给出一份标准答案。区别于功能模块/组件(比方图片库,网络库),本文探讨的是业务模块/组件(比方订单模块,商品模块)相干的架构设计。 二、 业务模块化/组件化传统的 App 架构设计更多强调的是分层,基于设计模式六大准则之一的繁多职责准则,将零碎划分为根底层,网络层,UI层等等,以便于保护和扩大。但随着业务的倒退,零碎变得越来越简单,只做分层就不够了。App 内各子系统之间耦合重大, 边界越来越含糊,常常产生你中有我我中有你的状况(图一)。这对代码品质,性能扩大,以及开发效率都会造成很大的影响。此时,个别会将各个子系统划分为绝对独立的模块,通过中介者模式收敛交互代码,把模块间交互局部进行集中封装, 所有模块间调用均通过中介者来做(图二)。这时架构逻辑会清晰很多,但因为中介者依然须要反向依赖业务模块,这并没有从根本上解除循坏依赖等问题。时不时产生一个模块进行改变,多个模块受影响编译不过的状况。进一步的,通过技术手段,打消中介者对业务模块依赖,即造成了业务模块化架构设计(图三)。 总的来说,通过业务模块化架构,个别能够达到明确模块职责及边界,晋升代码品质,缩小简单依赖,优化编译速度,晋升开发效率等成果。 三、常见模块化计划业务模块化设计通过对各业务模块的解耦革新,防止循环双向依赖,达到晋升开发效率和品质的目标。但业务需要的依赖是无奈打消的,所以模块化计划首先要解决的是如何在无代码依赖的状况下实现跨模块通信的问题。 iOS 因为其弱小的运行时个性,无论是基于 NSInvocation 还是基于 peformSelector 办法, 都能够很很容易做到这一点。但不能为理解耦而解耦,晋升品质与效率才是咱们的目标。间接基于 hardcode 字符串 + 反射的代码显著会极大侵害开发品质与效率,与指标南辕北辙。所以,模块化解耦需要的更精确的形容应该是“如何在保障开发品质和效率的前提下做到无代码依赖的跨模块通信”。 目前业界常见的模块间通信计划大抵如下几种: 基于路由 URL 的 UI 页面统跳治理。基于反射的近程接口调用封装。基于面向协定思维的服务注册计划。基于告诉的播送计划。3.1 路由 URL 统跳计划统跳路由是页面解耦的最常见形式,大量利用于前端页面。通过把一个 URL 与一个页面绑定,须要时通过 URL 能够不便的关上相应页面,如下所示。 //kRouteGoodsList = @"//goods/goods_list"UIViewController *vc = [Router handleURL:kRouteGoodsList]; if(vc) { [self.navigationController pushViewController:vc animated:YES];}当然有些场景会比这个简单,比方有些页面须要更多参数。 不过,根本类型的参数,URL 协定人造反对。 //kRouteGoodsDetails = @“//goods/goods_detail?goods_id=%d”NSString *urlStr = [NSString stringWithFormat:@"kRouteGoodsDetails", 123];UIViewController *vc = [Router handleURL:urlStr];if(vc) { [self.navigationController pushViewController:vc animated:YES];}而对于简单类型的参数,则能够通过提供一个额定的字典参数 complexParams,而后将简单参数放到字典中即可。 ...

October 25, 2021 · 4 min · jiezi

关于ios:iOS路由最佳选择是什么

背景记得四年前iOS路由开始流行,过后比拟有名的是蘑菇街的,起初CTMediator写了几篇文章把蘑菇街批的遍体鳞伤,导致我起初写新我的项目用了CTMediator,那一堆组件创立的叫一个酸爽啊!再起初陆续呈现了HHRouter、JLRoutes等;面对这么多优良的第三方路由,咱们如何抉择?是否须要重造轮子? 集体思考无论是路由还是工程架构都须要依据理论我的项目来抉择,比方你的工程就是小工程,而后还各种设计模式,这就会导致适度设计,原本一个小船就能搞定的事件你却动用了航空母舰;适度设计往往是一个业务研发过渡到架构师常犯的谬误。对于大项目前期肯定要思考好架构,起码便于前期迭代,这时候抉择什么路由以及根底组件怎么设计就关系到了将来路线是崎岖还是一帆风顺。 什么架构才适宜本人的我的项目呢?以我的了解,中小型我的项目肯定是应用cocoapod等组件管理工具来治理的,模块间低耦合是硬要求;一些第三方和独立的性能都用独立组件治理,一些下层逻辑能够临时全副放主工程,前期可能逐步优化;路由的抉择能够是任何一个第三方,无论target-action还是protocol,能解耦够用即可;对于大型项目,主工程就应该是一个壳工程,只负责整个我的项目的配置和组件的配置,除了配置不应该有任何业务逻辑,路由的抉择能够是自造轮子也能够应用优良第三方,工程也肯定是组件化;这种大型项目个别公司也是有实力的,有必要专门的架构组还解决架构的保护和运维,打造一套特有的CI/CD;甚至APS和APM零碎也要打造一套,人员上配置也必然是后盾、FE、安卓、iOS。 蘑菇街路由这个路由思维比拟经典,相干文章比拟多,不做过多介绍 CTMediator路由 github上3.7K个星实质上算不上是路由;路由思维的起源就是模拟web开发中的路由,路由肯定是有URL的;网上根本没有提CTMediator毛病的,不晓得是我用的不对还是咋地!CTMediator在应用的时候每个组件都还有一个两头组件作为直达(中间件),这样组件的个数就翻倍了,每批改一个组件接口,都须要从新公布俩组件!因而用于组件化的工程中,CTMediator至多有4个毛病:1,导致组件个数翻倍 2,导致组件公布简单3,保护老本变大4,基于runtime运行时,不反对Swift居然有面试题这么问:为什么CTMediator计划优于基于Router的计划?我感觉这种问法就有点夸夸其谈了,没有实际操作过就来做比照 JLRoutes github 5.5k个星自己没钻研过这个路由,看关注度应该是目前最火的一个,而且始终有保护 阿里的BeeHive github 4.1k个星自己没深入研究过这个路由,尽管是阿里的开源库,然而很少有公司去应用这个,更多是的学习钻研,最次要的是最近四年来没有任何更新保护 总结对于中小型我的项目,能够抉择JLRoutes作为第一思考对象,因为用的人多了,大家相互之间没有技术壁垒。对于大型项目,能够依据本人工程自造轮子,但肯定是在钻研了各种路由实现之后,思考好路由应有的性能范畴,而后开发一个更方便使用和适宜公司文化的路由;应用单例对象调用url咱们能够封装到object的分类中,这样调用会更加不便;另外能够依据我的项目构造,把跳转逻辑也定制化到路由中 更多技术文章以及iOS面试题解,请下载 iOS技术app 《逆天面经 》,每日背诵一个面试题,防止长期抱佛脚!另外,iOS组件开发模板大全 《资源库》app,收集了五千多个iOS组件模板,让你的开发更简略!

October 20, 2021 · 1 min · jiezi

关于ios:iOS签名校验那些事儿

导读:iOS签名校验机制是苹果生态平安的根底,日常工作中无论是开发阶段还是测试阶段经常会遇到很多须要通过签名机制解决的问题,理解iOS签名机制的原理有助于进步咱们解决相干问题的老本和效率。本文首先介绍数字签名和证书的原理,之后会介绍苹果开发者证书的生成装置过程,最初对苹果实现签名校验的流程及流程中波及的要害信息进行介绍,心愿能对大家有所帮忙。 全文9494字,预计浏览工夫24分钟。 背景iOS15 beta 版公布后,QA 同学须要测试新性能在iOS 15 零碎下的性能稳定性,然而通过公司流水线打出的企业包无奈装置在 iOS 15 零碎的设施上,具体报错见下图: 通过在控制台查看装置过程中的具体报错信息,发现具体的IPA 包的签名信息在iOS 15零碎上曾经不再被反对了: The code signature version is no longer supported.具体的控制台报错信息如下图所示: 也就是装置失败和IPA 的代码签名版本无关,为此通过codesign命令查看流水线产出的IPA 的相干签名信息,具体信息见下图,其中CodeDirectory的版本为v=20400: CodeDirectory直译是代码目录,记录的是将 Mach-O文件分页后每页的哈希值信息,除此之外还蕴含了资源文件的摘要信息、权限信息等,这些信息依照肯定的格局组合在一起,而不同的 signature version 对应这不同的信息品种、组合模式或计算算法。去年从iOS 14 beta2开始,苹果零碎采纳一种更为平安的签名格局,在其上运行应用旧签名格局签名的APP时会出正告弹窗。其官网介绍中提到 In a future release, the new format will become mandatory, and the system won’t launch apps with the old signature format.因而狐疑是签名格局在 iOS 15 零碎上进行了强制校验,导致装置失败: 在官网文档中提到 If you signed your app on a Mac running macOS 10.14 or later, the app already has the new signature format.换句话说 macOS 零碎的版本会影响到签名的格局; "For any value of v less than 20400, you’ll need to re-sign your app." ...

October 14, 2021 · 3 min · jiezi

关于ios:TextMeshPro备用字体疑问

1)TextMeshPro备用字体疑难2)iOS的局部语言的float分隔符变成了逗号3)ASTC格局反对与官网文档不符4)对于音效背景音乐的音频文件的格局设置求教5)LightProbe的信息地位 这是第269篇UWA技术常识分享的推送。明天咱们持续为大家精选了若干和开发、优化相干的问题,倡议浏览工夫10分钟,认真读完必有播种。 UWA 问答社区:answer.uwa4d.comUWA QQ群2:793972859(原群已满员) TextQ:TextMeshPro设置的Fallback “字体B”, 文本字体是“字体A”,如果文本显示的字符都是字体A的,CPU会不会收集字体B的贴图信息数据发送给GPU用来渲染? 不是很了解这个Fallback字体,发现字体A、字体B都在内存中,也就是说其实都是关联上的。是不是所有的后备字体都会在内存中呈现? A:问题一:TMP中所谓Fallback,也就是后备字体,其含意在于当理论应用中呈现了以后字体所不反对的字符时,依照:主字体(也就是以后字体)、主字体的后备字体、后备字体的后备字体、通用后备字体、通用后备字体的后备字体、通用默认字体、通用默认字体的后备字体等等的序列遍历所有设置的后备字体,直到找到可能反对的字体为止。 所以,引擎只有在内存中保留Fallback字体资源,能力在以后字体无奈显示所有字符时采纳Fallback字体。问题中提到的字体B也在内存中是正当的。 当然,如果开发者能确定字体A能够反对我的项目中呈现的所有字体,那么齐全能够查看Project Settings中全局的Default Font Asset、全局的Fallback Font Assets List、字体A的Fallback Font Assets,以上三处设置为空,则能够肯定水平上节俭内存。 问题二:我补充做了试验。对照状况是用某一种主字体显示“New Text”这一串字符,显然足够反对、而内存中也只有该主字体。而后在方才提到的主字体的后备字体、后备字体的后备字体、通用后备字体、通用后备字体的后备字体、通用默认字体、通用默认字体的后备字体这个序列的每个环节加上不同的字体,显然它们没有被理论用到,但都进入内存了。List外面有几种字体也是一样。 感激Faust@UWA问答社区提供了答复 iOSQ:最近咱们打包的时候发现,在iOS设施上,局部语言的小数的分隔符变成了逗号,比方俄罗斯语。起初发现是因为CurrentCulture变成了设施的语言,Android和之前的iOS设施都是en-US,也就导致了读取配置时用float.TryParse会转换失败。 咱们的Unity版本是2018.4.33,目前还没有定位是什么起因导致的,不晓得有没有人碰到过?如果在游戏启动时强制把CurrentCulture改成英语不晓得可不可行? A:咱们我的项目踩过这个坑,起因就是一些语言外面小数点分隔符不一样,比方法语里分隔符是逗号,属于文化差异。解决方案是游戏启动时设置CurrentCulture为CultureInfo.InvariantCulture: CultureInfo.DefaultThreadCurrentCulture = CultureInfo.InvariantCulture;CultureInfo.DefaultThreadCurrentUICulture = CultureInfo.InvariantCulture;Thread.CurrentThread.CurrentCulture = CultureInfo.InvariantCulture;Thread.CurrentThread.CurrentUICulture = CultureInfo.InvariantCulture;参考链接:CultureInfo.InvariantCulture 感激张迪@UWA问答社区提供了答复 TextureQ:ASTC格局反对与官网文档不符,依据官网文档(https://docs.unity3d.com/Manu...)。实践上咱们的测试机中,红米2是不反对的ASTC格局的。但理论测试中发现,它是反对的。这是怎么一回事? A:之前做过相干的测试,红米2(Adren 302)是反对ASTC的,但红米Note2(PowerVR Rogue G6200)是不反对的。并且从Unity 2017.4的Profiler中能够看到纹理的大小是正确的。 这和官网提供的:tvOS (all), iOS (A8), Android (PowerVR 6XT, Mali T600 series, Adreno 400 series, Tegra K1)不符。 从目前的测试来看,能够认为理论反对状况和文档提供的GPU型号并不完全一致。在不反对的机型上会软解成RGBA32或RGB24,理论内存也是一样。 感激OCEAN@UWA问答社区提供了答复 AudioQ:在UWA的报告中看到要用Streaming的形式读取音频。想问一下对于音频格式,有优化角度比拟全的倡议吗? 之前我的项目里的设置大略是这样子的,适合吗?大家常见的做法是怎么的?有没有一个绝对正当的经验值,比方10s的音效大小在100KB这样的参考值? A:并不举荐应用MP3播放音乐,起因是应用MP3制作素材会无奈防止在循环点引入空白音频,参见:https://sound.stackexchange.c... 之前应用过相似于MP3Loop的小工具,然而编码品质也无法控制,最初抉择用Ogg(Vorbis)一了百了。 早一些的开发者(1990-2000年前后)会采纳MIDI,但MIDI只是记录音乐信息用的格局,理论发声取决于所应用的音源,而音源设计通常会偏向于大而全所以为了无限的MIDI音乐加载残缺的音源也会造成资源冗余。 对于PCM或者ADPCM,通常被称为WAV及“三分之一的WAV”,能够依据音效具体内容来决定优化策略,有一个概念须要理解——奈奎斯特采样定理。 简略讲,如果一个声音比拟消沉,那么能够适当升高采样率来晋升PCM或者ADPCM的“压缩比”,这样能够既保留PCM/ADPCM的低功耗和疾速响应,又升高资源占用。假如一个声音比拟显著的能量都散布在4000hz之下,那么只须要8000hz的采样率就能够十分好的记录及还原这个声音了。 事实上Unity原声音频最现实的音乐格式是Tracker Module,只是国内开发者理解Demo Scene的比拟少,音乐创作者为此类格局创作的教训也十分稀少。 ...

October 11, 2021 · 1 min · jiezi

关于ios:智汀家庭云开发指南Golang用户认证与第三方授权

用户认证与第三方受权智汀家庭云提供用户登录认证与第三方受权性能,包含用户凭证、Scope Token与长期明码。 1. 用户凭证每一个用户帐号创立时都会主动生成一个随机的用户凭证,该凭证会保留在智汀家庭云与智汀 APP 内, 应用该凭证能够领有该用户的所有权限。用户凭证通过 smart-assistant-token HTTP 申请头的形式发送。 2. Scope Token第三方 APP 或者智汀云须要申请智汀家庭云的接口时,须要应用 Scope Token 进行鉴权拜访。Scope Token 在生成时 能够抉择其领有的接口权限范畴,并且会设置过期工夫,保障第三方无奈越权应用。Scope Token 通过 scope-token HTTP 申请头发送。 Scope Token 为 JWT 格局,其校验密钥为用户凭证。通常状况下应蕴含以下字段: sa_id: 智汀家庭云初始化时的 IDuid: 智汀家庭云中对应的用户 IDexp:过期工夫scopes: 权限范畴,字符串,以(,)分隔其余业务相干字段留神:敏感信息不能存储于 JWT 中Scope Token 受权流程如下: 3. 长期明码通常状况下,智汀家庭云通过颁发 Scope Token 来限度第三方拜访范畴,但偶然咱们也须要让可信赖的第三方执行某些治理性能, 但颁发具备全权限的 Scope Token 又放心存在危险;智汀家庭云提供长期明码来解决此问题: 智汀APP应用用户凭证申请智汀家庭云接口,生成长期明码,该长期明码具备用户的所有权限将长期明码输出到可信赖的第三方平台(如智汀云)第三方平台凭此长期明码与附加的用户ID,SA-ID等信息拜访智汀家庭云接口智汀家庭云解决申请后立即将该长期明码生效,防止越权应用

October 11, 2021 · 1 min · jiezi

关于ios:智汀家庭云开发指南Web扩展开发jsBridge使用

jsBridge应用【1】概述智汀Web端专业版作为做智汀APP的辅助程序,所以免不了要跟APP那边做交互,jsBridge就是咱们交互的桥梁,通过jsBridge咱们能够很顺畅的跟APP那边进行交互。 【2】 webview ua革新概述:为了区别于在APP内嵌入h5,退出特有的ua,用于判断是否在app内嵌入,在原有的ua上加上字符串“zhitingua”咱们能够通过判断ua就能够判断出咱们的智汀专业版是否是在app内关上 【3】JS-SDK文档APP间接在Webview内注入了一个zhiting的全局对象,并实现了invoke办法,咱们只有调用此办法并传入相应的参数就能够调用app内提供的办法。 (1) 查看app连网类型 (2)设置题目属性 (3) 获取用户信息 (4)是否是专业版APP 部署利用部署利用是指编译或构建代码并将生成的 JavaScript、CSS 和 HTML 托管到 Web 服务器上的过程。 构建和托管你的利用 咱们的我的项目开发完后,怎么公布,首先要构建咱们的我的项目 npm run build在根目录执行该命令后,我的项目的构建文件会输入到dist文件夹,咱们下一步就是把咱们的dist文件夹托管在服务器上,配置好申请转发和域名。至此,咱们的利用曾经部署胜利了。

October 8, 2021 · 1 min · jiezi

关于ios:智汀家庭云开发指南GolangHTTP-API-接口规范

1.接口鉴权应用smartassistant接口,需将用户凭证smart-assistant-token,放在http申请的header中。格局如下: "smart-assistant-token":"xxx"2.返回规范数据结构smartassistant接口均返回JSON格局数据,格局如下: { "status":0, // 状态码 "reason":"", // 状态码形容 "data":{} // 所有业务数据返回都蕴含在data对象中}3.错误码列表附录:错误码列表

September 30, 2021 · 1 min · jiezi

关于ios:导航控制器pushViewController-的转场动画

与 ViewController 的 present 转场动画不同1, 导航控制器,pushViewController 的转场动画,的代理是 navigationController?.delegate = self2, 指定动画的办法 extension Two: UINavigationControllerDelegate{ func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? { if operation == .push{ return navAnimatorPush } else{ return nil } } }具体的动画设置也不同应用 snapshotView , 会呈现奇怪的成果 代码很好了解 class NavBaseCustomAnimatorPush: NSObject, UIViewControllerAnimatedTransitioning{ func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return 1 } func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { guard let fromCtrl = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from), let toCtrl = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to), let fromView = fromCtrl.view, let toView = toCtrl.view else{ return } let containerView = transitionContext.containerView let f = UIScreen.main.bounds fromView.frame = f containerView.addSubview(fromView) containerView.addSubview(toView) toView.frame = presentingDirection.offsetF(withFrame: f) UIView.animate(withDuration: transitionDuration(using: transitionContext), delay: 0.0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.0, options: .curveLinear) { toView.frame = f } completion: { _ in let success = !transitionContext.transitionWasCancelled transitionContext.completeTransition(success) } } }github repo

September 26, 2021 · 1 min · jiezi

关于ios:苹果-iOS-15-仍存在零日安全漏洞100万美元的安全奖励计划受吐槽

近日,苹果一项高达“100万美元”的平安处分打算受到了来自匿名平安钻研人员的公开“吐槽”。该匿名人士在最新的博文中,公开对该苹果对于该打算的“搪塞”态度表白不满,一时间引发热议。 据悉,2019 年苹果向公众凋谢了其平安处分打算,为那些和苹果共享 iOS、iPad OS、Mac OS、tv OS 或 Watch OS 要害安全漏洞的钻研人员提供高达100万美元的奖金,通过这些破绽技术来晋升自家平台的安全性。 在尔后的工夫里,有报道表明一些平安钻研人员对该打算不称心。本周五,一位笔名为 “illusionofchaos” 的平安钻研人员就发文分享了这种“令人丧气的经验”。 该平安钻研人员的原文内容如下: “I want to share my frustrating experience participating in Apple Security Bounty program. I've reported four 0-day vulnerabilities this year between March 10 and May 4, as of now three of them are still present in the latest iOS version (15.0) and one was fixed in 14.7, but Apple decided to cover it up and not list it on the security content page. When I confronted them, they apologized, assured me it happened due to a processing issue and promised to list it on the security content page of the next update. There were three releases since then and they broke their promise each time.” ...

September 26, 2021 · 1 min · jiezi

关于ios:iOS-15升级卡在准备更新上如何解决

最近,一些用户反馈他们的iPhone 在降级iOS 15时卡在筹备更新屏幕上。造成这种状况的起因有很多。可能是手机存在软件或硬件问题,导致无奈齐全筹备好更新。如果你也筹备将iPhone更新到最新的iOS 15零碎,你能够参考这篇文章介绍的办法解决此更新问题。 办法 1. 删除以前的更新文件iOS 15降级卡在筹备更新屏幕上的起因之一是下载的更新已损坏。下载更新时呈现问题,导致更新文件无奈放弃残缺。在这种状况下,你能够尝试删除更新文件。 关上设置 > 单击通用。点击iPhone存储选项,找到iOS 15更新文件。点击更新文件,而后抉择删除更新。 更新文件将从你的设施中删除。而后,您须要进入 “设置” > “通用” > “软件更新” 将更新从新下载到你的iPhone上。 办法 2. 修复iOS零碎问题如果删除软件更新文件或重新启动设施没有解决问题,你可能是遇到了iOS零碎问题。这时,你能够尝试应用三方零碎修复工具 - 丰科iOS零碎复原工具。这个软件旨在修复各种iOS设施上常见的零碎问题,包含 iPhone降级OS 15卡在筹备更新上。 这个工具的应用非常简单。你能够依照以下步骤一步一步实现修复过程。而后,你能够疾速修复iPhone,之后下载并装置最新的iOS 15零碎。 下载丰科iOS零碎复原工具并将其装置在你的电脑上,将你的iPhone连贯到电脑并在程序中抉择“规范模式”。程序辨认设施后,单击“下载”开始下载最新的iOS 15固件。下载实现后,单击“立刻修复”开始修复iPhone上的更新问题。 办法 3. 查看网络情况iOS 15降级卡在筹备更新上的另一个可能起因是你iPhone的网络设置存在问题。iPhone呈现网络问题的起因有多种。可能是你的路由器有问题。在这种状况下,你须要修复路由器能力在iPhone上连贯网络。也可能是iPhone的网络设置没有正确配置。 解决iPhone上任何网络问题的最简略办法是还原网络设置。通过这个操作,iPhone会将所有网络设置还原为出厂默认设置。这样,你能够革除任何有问题的配置并修复 iPhone 上的问题。 关上设置 > 单击通用。点击还原以查看设施的还原设置。点击 “还原网络设置” 选项以重置所有网络设置。 网络还原之后,你须要从新输出明码连贯WiFi。你的iPhone当初应该能够失常连贯到网络并下载和装置iOS 15更新。

September 25, 2021 · 1 min · jiezi

关于ios:深入-iOS-静态链接器一-ld64

作者:字节跳动终端技术——李翔 前言动态链接(static linking)是程序构建中的一个重要环节,它负责剖析 compiler 等模块输入的 .o、.a、.dylib 、通过对 symbol 的解析、重定向、聚合,组装出 executable 供运行时 loader 和 dynamic linker 来执行,有着承前启后的作用。 对于 iOS 工程而言,目前负责动态链接的次要是 ld64。苹果对 ld64 加持了一些性能,以适配 iOS 我的项目的构建,比方: 当初在 Xcode 中即便不被动治理依赖的零碎动静库(如 UIKit),你的工程也能够失常链接胜利提供“强制加载动态库中 ObjC class 和 category” 的开关(默认开启),让 ObjC 的信息在输入中残缺不失落大量个性的实现也在动态链接这一步实现,如: 基于二进制重排的启动速度优化,利用 ld64 的-order_file 让 linker 依照指定程序生成 Mach-O用 -exported_symbols_list 优化构建产物中 export info 占用的空间,缩小包大小借助组件二进制化、自定义构建零碎等优化伎俩,以后大型工程中增量构建的效率曾经显著晋升,但动态链接作为每次必须执行的环节仍然“奉献”了大部分耗时。理解 ld64 的工作原理能辅助咱们加深对构建过程的了解、寻找晋升链接速度的办法、以及摸索更多品质和体验优化的可能性。 目录历史背景概念铺垫ld64 命令参数ld64 执行流程ld64 on iOS其余一、历史背景GNU ld:GNU ld,或者说 GNU linker,是 GNU 我的项目对 Unix ld 命令的实现。它是 GNU binary utils 的一部分,有两个版本:传统的基于 BFD & 只反对 ELF 的 gold)。(gold 由 Google 团队研发,2008 年被纳入 GNU binary utils。目前随着 Google 重心放到 llvm 的 lld 上,gold 简直不怎么保护了)。 ld 的命名据说是来自 LoaDer 、Link eDitor。ld64:ld64 是苹果为 Darwin 零碎从新设计的 ld。和 ld 的最大区别在于,ld64 是 atom-based 而不是 section-based(对于 atom 的介绍前面会开展)。在 macOS 上执行 ld (/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld)默认就是 ld64。零碎和 Xcode 自带的版本能够通过 ld -version_details 查问,如 650.9。苹果在这里 https://opensource.apple.com/... 凋谢了 ld64 的源码,但更新不那么及时,始终落后于正式版(如 2021.8 为止开源最新是 609 版本,Xcode 12.5.1 是 650.9) 。zld 等基于 ld64 的我的项目都是 fork 自开源版的 ld64。二、概念铺垫在介绍 ld64 的执行流程之前,须要先理解几个概念。 ...

September 23, 2021 · 13 min · jiezi

关于ios:iOS-15-正式版发布一天后iOS-151-相继更新一文盘点更新亮点

昨日凌晨 1 点,iOS 15 正式版如期公布,而在更新仅一天后,苹果公布了 iOS 15.1 和 iPadOS 15.1 的第一个测试版本,此外还有 watchOS 15.1 测试版和 tvOS 15.1 测试版。 iOS 15 正式版更新亮点尽管此次更新反对 iPhone 6S 及当前的机型,但受制于硬件条件,持有六年前公布机型的用户并不能充沛应用所有的新性能,例如备受期待的实况文本等。 苹果往年早些时候示意,因为种种原因,不会向用户主动推送 iOS 15,并指出它将在新操作系统推出后持续为 iOS 14 提供安全更新。依然应用 iOS 14 的用户将在设置中看到两个软件更新抉择,一个是带有破绽修复的最新 iOS 14 版本,另一个是 iOS 15。 接下来让咱们一起看看,苹果如何让 iOS 零碎「发明更多不凡形式施展 iPhone 效力」。 告诉性能告诉性能的新外观 新零碎中的告诉横幅间接显示联系人照片且本来的 APP 图标进行了放大,将会更加轻松地辨认音讯。 个性化的告诉摘要 最新的零碎中苹果提供了一项将大量 APP 推送归集整顿的性能。用户能够抉择工夫和频次来显示选定利用的告诉摘要,零碎将依照优先级进行排列。 这一性能须要用户手动开启,未被选入这一性能的 APP 将维持原来的告诉模式。 须要留神的是被告诉摘要汇总到的内容大多属于非紧急通知,优先级绝对较低,而微信音讯、短信等具备强时效性的信息,则会立即送达,并晋升至顶部。 FaceTime 通话从 iOS 15 开始,苹果零碎内置的视频通话软件 FaceTime 将容许用户生成链接,并邀请其余生态的对象(安卓、Windows 用户)通过浏览器开展视频对话。 人像模式能够将焦点放在你身上,营造出虚化的背景成果。此外还将反对空间音频、语音隔离模式 、宽频谱模式。 专一模式专一模式对以前的 iOS 版本中免打搅模式的扩大,包含勿扰模式、工作模式、集体模式以及睡眠模式,可依据本身需要设置不同类型的信息展现偏好。例如,咱们能够设置一个"工作"焦点,只容许以工作为核心的应用程序才能够告诉咱们。 其余 iOS 15 用户能够在 iMessage 中看到咱们的 Focus 状态,所以他们晓得他们的信息可能不会引起 iOS 设施发出通知。此外能够在特定的主屏幕上增加小部件和应用程序,而后让该屏幕只在某些焦点期间呈现。 ...

September 22, 2021 · 1 min · jiezi

关于ios:产品资讯-mPaaS-10168-适配-iOS-15

iOS15 将于 2021 年 9 月正式公布,针对全新的零碎个性和接口,APP 须要进行相干的适配。目前 mPaaS 已在 ≥10.1.68.38 版本的基线版中实现对 iOS15 beta(8) 版本的适配和测试工作。 mPaaS 作为根底库,曾经在 Xcode 12 构建 ipa 包下实现了 iOS 15 beta(8) 的适配和测试工作。如您的利用打算在苹果 App Store 上线,以后请 应用 Xcode 12 打包。Xcode 13 的相干工具链正在欠缺中。在工具链欠缺后,mPaaS 也会推出 Xcode 13 构建下适配 iOS 15 的版本。 降级 SDK/组件基于 Extension 插件降级应用 mPaaS Xcode Extension 插件降级 SDK/组件,您能够抉择以下两种形式: 更新产品集降级基线您须要依据本身状况抉择降级形式。如果您: 曾经应用 Extension 插件治理组件依赖,但以后应用的基线版本低于 10.1.68,可应用 降级基线 性能降级至 10.1.68 版本。阐明:以后应用的基线版本可在插件的 基线降级 中查看。曾经应用插件治理组件依赖,且以后应用的基线版本为 10.1.68,可应用 更新产品集 性能降级所应用到的模块。未应用插件治理组件依赖。可依照以下步骤进行降级: 装置 mPaaS Xcode Extension。应用 编辑模块 性能抉择 10.1.68 版本基线并增加所需模块。基于 CocoaPods 降级依照以下步骤,即可装置 10.1.68 版本的最新 SDK: ...

September 18, 2021 · 1 min · jiezi

关于ios:Alibaba-iOS-工程架构腐化治理实践

“ 业务开发遇到环境问题越来越多,重大影响开发效率,有些外表看似打包问题,背地却是工程架构的腐化。”背景近年来,iOS工程复杂度高的负面影响逐步裸露,很多同学都受到了iOS打包慢和打包简单的“残害”,业务开发效率受到很大影响。我记得已经有个同学跟我诉苦,他把几个模块打包后集成到主工程,这个过程中每个步骤都有打包失败,总共花了大半天工夫。 Alibaba.com是跨境B类电商业务,2012年开始开发iOS客户端。为了撑持业务倒退,2016年进行组件化革新,从繁多工程架构演变模块化架构。随着业务和无线技术的倒退,客户端曾经从小型模块化工程演变为一个巨无霸工程。团队一共建设了100多个自保护模块,包含业务模块、架构设施、Hybrid容器、Flutter容器、动态化技术、根底中间件等能力。外表上工程架构正在有序地演进,但外部曾经乱象丛生。模块关系凌乱,循环依赖和反向依赖行为越来越多。大量模块不合乎LLVM Module规范,spec文件不全、头文件援用不标准。因为工程不标准,Cocoapods无奈降级,只能应用1.2和1.5旧版本,技术上落后了3年以上。 为了彻底解决问题,进步业务开发体验,阿里巴巴ICBU端架构组对iOS工程架构进行全面地治理。我也写下一篇文章记录本人的思考,欢送有趣味的同学领导交换。 Steve Mcconnell 《Code Complete》:“软件的首要技术使命:治理复杂度。”架构腐化会产生哪些问题?问题一:模块打包复杂度高工程环境混淆2016年Alibaba客户端组件化做的并不彻底,很多模块只是模式上的拆散,实际上还存在反向依赖和循环依赖问题。到了2017年,团队想做Framework化,发现模块独自打包编译不过。于是,为了模块编译通过,咱们开发兼容脚本,将所有framwwork和头文件都增加到工程searchPath里,并且让模块间接读取同步主工程Profile里所有依赖。自从有了兼容逻辑,spec文件不写依赖形容也能编译得过,于是再也没人保护spec文件,跨模块的头文件援用也越写越乱。 环境不兼容&模块构建失败因为存在循环依赖、头文件不标准等问题,模块编译脚本加了许多workaround逻辑,兼容头文件索引。这导致模块Cocoapods环境无奈降级,始终停留在1.2版本。而随着中间件和社区swift技术越来越多,主工程Podfile用了cocoapod 1.5的新语法。环境开始不兼容。同时,模块解析主工程Podfile时,无奈辨认cocoapod 1.5的新语法,模块构建失败。 每年节约了90人日的开发资源模块打包失败后,开发须要剖析日志,排查打包失败起因,若剖析不进去则须要找架构组反对。一个模块打包失败,会始终卡住需要不能集成,会阻塞测试或其余开发工作。 依据开发反馈的状况,预计均匀一次模块打包失败要耗费2个小时的研发资源。据统计,Q1期间,模块打包失败总数高达200屡次,其中70%的打包失败是因为简单度过高导致的。每一次打包失败节约2个小时,相当于每年节约了90人日的研发资源。 Robert Martin 《Clean Architecture》:“不论你们多敬业,加多少班,在面对烂零碎时,你依然会举步维艰,因为你的大部分精力不是在应答开发需要,而是在应答凌乱。”问题二:主工程打包慢如果模块不标准,又须要援用swift中间件,无奈独立动态库,只能以源码模式集成到主工程。这导致主工程打包时须要编译大量源码,均匀打包工夫比手淘、优酷等工程慢12分钟。需要提测、集成、修复bug、排查问题时都须要进行主工程打包,打包慢会阻塞开发和测试的工作。某一次双周迭代打包了70次,节约了14个小时。 问题三:工程环境不稳固Cocoapods环境不能降级,只能应用1.2和1.5的旧版本。但旧版本环境没人保护,环境极其软弱,比方有人公布了一个不非法的spec,Pod Update就会挂掉。因为模块不标准,源码开发时会呈现各种莫名其妙的编译问题。业务开发和调试效率会很低,节约大量的工夫。 问题四:Swift开发举步维艰近几年swift遍及,iOS社区和团体swift中间件越来越多。然而,Swift模块严格遵守“LLVM Modules”标准,不容许循环依赖、内部依赖要显示申明、头文件援用要采纳尖括号,否则就会呈现“could not build module xxx”、“No such module”等谬误。高标准的要求下,咱们的工程开发引入Swift举步维艰。尽管咱们本人能够不应用Swift,但团体和三方的中间件Swift化的趋势是不可逆的。 近两年,Alibaba.com的工程引入许多Swift中间件,同时也自主研发了许多swift组件,这也彻底引爆了研发效率的问题。相干模块频繁打包异样。不标准问题盘根错节,常常解决完一个编译器谬误,又呈现另一个谬误,子子孙孙无奈穷尽。最初零碎开始呈现各种不可控危险。 此外咱们大部分模块都不合乎LLVM Modules标准。如果业务需要应用Swift或援用到Swift中间件,就要花大量工夫去解决适配问题。依据麻利迭代的数据,需要A打算10人日,理论耗费20人日,需要B打算6人日,理论耗费10人日。 复杂度的好转到肯定水平,肯定进入有诸多unknown unknown的水平问题五:历史代码清理艰难最近几年很多旧业务曾经下线或革新。但因为模块之间耦合重大,许多旧代码始终不敢删,这也导致包大小继续收缩。 架构腐化治理的艰难与策略影响范围广,治理难推动2020年,我在iOS技术栈发动了架构治理我的项目,动员各个业务线的iOS开发一起治理,却陷入了困局。一方面,业务开发没有投入资源。另一方面,许多业务模块之间调用关系凌乱,治理危险高,大家都不敢轻易动。 数据化剖析,自顶向下推动iOS工程的凌乱曾经重大影响了业务倒退,大家工夫都节约在解决编译打包问题上。各业务的iOS开发同学都被困扰,许多开始反馈因为打包困难严重影响开发效率。 为此,我开始全面梳理研发流程的数据。一方面,我统计了模块构建失败数据,主工程打包的耗时,而后再联合其余客户端的数据进行比照;另一方面,我对业务开发做访谈,从用户的角度理解资源节约的数据,补充研发平台中无奈统计到的环节。最初,胜利将工程凌乱对研发效率的负面影响量化为具体的数据。 有了数据分析后果,就有了推动的抓手,能够自顶向下推动架构治理。 解决方案纵观全局,理清模块依赖关系第一个难点是模块的关系不清晰。模块形容文件里依赖列表都是空的,模块之间的关系就像一团毛线。 模块的关系不清晰,治理我的项目就无奈拆解,老本也估算不进去。因而要先纵观全局,剖析整体的模块依赖关系。 我开发了一个工具进行剖析。首现查找模块的所有文件,应用正则匹配找到它import的内部头文件,失去内部援用的头文件汇合。而后搜寻主工程的Pods目录,匹配头文件所属的内部模块,最初聚合失去残缺的模块依赖树。 下一步是视觉化,视觉化当前能够更直观地查看模块关系的复杂度,不便制订治理打算。我应用了Dot language来形容模块关系,能够主动生成整个工程的依赖关系图,也能够生成某个特定模块的依赖关系图。 依赖倒置、分层治理第二个难点是治理的依赖条件简单。 模块治理胜利的规范是整个依赖树的所有模块都没有循环依赖,并且都合乎LLVM Module标准。比方治理业务模块A,模块A的依赖树里有一个模块C,模块C存在循环依赖或不合乎Module标准,A模块打包时就会报异样.而Cocoapod和XCode每次只报一个异样,不能剖析整个依赖树所有的问题。 咱们工程本人保护的模块有130多个,三方库和中间件模块200多个。业务模块除了本身依赖,还有许多间接依赖,依赖树非常复杂。这种状况下,间接治理业务模块复杂度极高,治理过程也会很凌乱。 上图的示例中,模块C、模块I、模块G是关系简单的核心模块。比方“模块I”间接依赖了30个内部模块,间接依赖100多个模块,它间接耦合关系有5个循环,间接耦合关系15+个循环。如果间接治理“模块I”,须要解耦15个循环关系,将100多个模块进行Module化革新。依照这样的思路治理,批改逻辑极其简单,很可能治理到一半就进行不上来。 为了解决这个困局,我对模块进行分层和分类。划分的根底逻辑有3个: 越是底层的模块依赖关系越简略;没有循环依赖的模块更容易治理;治理实现的模块能够被疏忽。依照这个思路,我先梳理分明模块所属的档次,而后自底层逐层向上治理。当底层模块都治理完,依赖多的模块累赘也会大大降低。当底层的循环依赖解耦实现,下层的模块就不必解决的间接循环依赖。 最初应用四象限分析法,将模块分为4个组,1根底模块无循环依赖、2根底模块有循环依赖、3业务模块无循环依赖、4业务模块有循环依赖,按程序治理每一组。 自动化修复第三个难点是代码改变量大。模块治理面临许多子问题,“模块spec文件的依赖形容不全”、“umbralla头文件不缺失”、“public头文件援用不标准”、“循环依赖解耦”。仅仅修复“模块spec文件的依赖形容不全”就很艰难。 补全依赖的办法是查找所有源文件的import形容“(import <xxxFramework/xxx.h)”,统计以来的所有framework。再基于framework名称反向查找所属的模块。另外有很多import格局不标准,有些是间接援用文件名(import “xxx.h”),有些是门路形式援用(import <xxx/xxx/xxx.h>),遇到这种不标准的援用,还须要全局搜寻能力找到属于哪个模块。举个例子,模块A的dependence形容是空的,但实际上它依赖了20几个模块。模块A有60多个源文件,每个源文件import援用均匀是10行,总共600行援用代码。如果人工剖析这600行代码,预计得花一天工夫。这还只是批改其中一个问题,还不包含“umbralla头文件不缺失”、“public头文件援用不标准”、“循环依赖解耦”。 因而,纯人工治理基本行不通,必须通过自动化的形式提高效率。于是我开发了一个架构治理引擎,能够用来剖析模块依赖关系,也能够修复spec依赖形容不全、主动生成umbralla头文件、批改不标准头文件援用等等。自动化的修复工具能够笼罩95%的代码改变量,开发只负责批改路由、服务API、代码迁徙、模块拆分合并等变动较大的逻辑改变。 架构治理引擎不仅能够做架构治理,它还能做为团队管理工具,比方剖析git仓库活跃度,批量设置CodeReview规定,记录研发过程的日志。 上面这段代码应用了ruby语言和cocoapods-core框架,次要性能是剖析模块import代码,修复模块的podspec的依赖。 require 'cocoapods'require 'cocoapods-core'require 'xcodeproj'def DependencesAnalyser.main(contextHelper, projectToolPath, moduleName, allModuleNames) # 1修复import格局 iOSProjectDir = contextHelper.projectDir podDir = contextHelper.podDir iOSProjectName = contextHelper.projectName # 读取source_files门路 sourceDir = contextHelper.sourceDir if sourceDir.nil? puts '[error]依赖修复失败,找不到正确的sourceDir' return nil end # 1 读取源文件目录下的所有.h和.m文件的门路 allheadPaths = getSourceHeaderPath(sourceDir) # 2 遍历所有源文件,读取文件的每一行,正则匹配出所有import的代码行 # 2.2 如果是import "" 或者 import <xx.h> 规定援用的,解析出依赖的头文件 importHeaders = parseHeaderNameFromQuotationImport(allheadPaths) # 2.1 如果是import <xx/xx.h> 规定援用的间接截断出framework名 dependences = parseFrameworkNameFromAngleBracketsImport(allheadPaths) # 3 如果是import "" 规定援用的,判断援用的头文件是否存在Pod目录下,如果存在记录所在Pod的Framework名 # 3.1 读取主工程Pod文件目录下所有依赖库的.h文件的门路 dependencesFromQuatationImport = findFrameNameFromQuatationImportHeader(podDir, importHeaders) dependences = dependences + dependencesFromQuatationImport filtedDependences = filterDepencences(dependences, projectToolPath, moduleName, allModuleNames) # 4 读取podspec,批改dependence后,输入新的podspec文件 modify_spec_file(filtedDependences, contextHelper) # 5 输入依赖关系文件 return filtedDependences end架构和业务单干治理第四个难点是解耦波及大量业务逻辑。很多代码是业务的分支逻辑,重构后很难测试,如果不全面验证很容易出线上故障。 ...

September 17, 2021 · 2 min · jiezi

关于ios:解码多种可能类型的两种技巧属性包装器

Swift 的属性包装器是语法糖, 他能够让代码更加的申明式 定义属性的时候,把规定写进去 属性包装器, 次要应用 wrappedValue, 有时候用到 projectedValue问题:存在这样的一个构造体: struct Figure: Decodable { var name: String var age: Int}后端传过来,一个 json, 要求 json 对应的内容,长这样, 可能解析进去 var dict: [String: Any] = ["name": "666", "age": 666]json 对应的内容,长这样, 也可解析进去 dict = ["name": 666, "age": "666"]问题,解码一个属性,他的数据可能有多种类型技巧一,应用属性包装器提供解码办法 static var losslessDecodableTypes:, 是一个解码办法的汇合 零碎提供的 LosslessStringConvertible 协定,能够让字符串,转值 public typealias LosslessStringCodable = LosslessStringConvertible & Codablepublic struct LosslessDefaultStrategy<Value: LosslessStringCodable>{ public static var losslessDecodableTypes: [(Decoder) -> LosslessStringCodable?] { @inline(__always) func decode<T: LosslessStringCodable>(_: T.Type) -> (Decoder) -> LosslessStringCodable? { return { try? T.init(from: $0) } } return [ decode(String.self), decode(Int.self), decode(Double.self), decode(Float.self) ] }}通过属性包装器, ...

September 15, 2021 · 3 min · jiezi

关于ios:iOS-端容器之-WKWebView-那些事

简介:本文次要是对于在端容器设计开发过程中,WKWebView 应用上遇到的一些问题和解决办法。 作者 | 驽良起源 | 阿里技术公众号 一 背景相熟 iOS\macOS Hybrid 混合开发的同学应该都有领会,WKWebView 尽管是苹果作为代替 UIWebView\WebView 而推出的"新"组件,但大部分开发者对它切实“爱不起来”。毕竟对于国内大部分利用开发者来说,在理论应用中 WKWebView 所谓的“劣势”未必能体现进去,但带来的“坑”却都着实都不浅。 目前社区或线上可查找的 WKWebView 相干材料,大多比拟古老且随声附和、复制粘贴类的居多。少部分实在实际和摸索的开发者,或者也因工夫或精力的起因,对问题和解决方案未能做具体的论述。导致目前线上 WKWebView 相干的材料数量不少、但品质不高;且有不少文章存在对问题的背景解释不清,解决方案不足无效验证等问题。 我从事端容器畛域开发多年,曾在生产环境方案设计上与 WKWebView "反抗"屡次。目前混合开发曾经是古代 App 标配,一方面是对这么长时间用法教训上的总结,另外一方面也心愿可能为还在抗争中的同学提供一些新视角或者解决思路,故筹备联合 WebKit 局部源码,将本人对这个组件的了解以及局部问题解决方案整顿分享一下。本文尝试阐明 3 件事件: WKWebView 应用中的典型问题有哪些为什么会呈现这些问题这些问题的解决办法有哪些二 根底回顾iOS 端网络设计和 WKWebView 设计特点咱们能够通过官网材料来查阅。但为了前面更好的阐明问题,上面咱们重点回顾下与文章后续内容相干的两个根本知识点: iOS 端网络设计与 Cookie 治理WKWebView 多过程模型1 iOS 网络设计与 Cookie 治理Cookie 治理是做混合开发过程中常常会波及到的局部,在利用开发中咱们晓得能够通过 NSHTTPCookie 和NSHTTPCookieStorage 来治理利用的 Cookie。但在零碎层面 Cookie 是如何治理的、如何与网络层各模块进行联动,这对咱们前面剖析WKWebView 中的 Cookie 问题有着至关重要的分割。 依据官网材料,咱们可知 iOS 平台下网络相干模块大略关系如下: 从上至下模块顺次为: WebKit:应用层,客户端 App 以及 WKWebView 处于这一层。 NSURL:能够了解为对底层 CF 接口的封装扩大层,NSURLConnection、NSURLSession 等处于这一层。 ...

September 14, 2021 · 5 min · jiezi

关于ios:iOS-屏幕旋转的实践解析

摘要:如何更灵便便捷的实现自定义屏幕旋转场景,本文带你揭秘!  文|即构 iOS 利用开发团队 屏幕旋转是在视频直播类 APP 中常见的场景,在即构科技之前公布的 Roomkit SDK 中也有屏幕追随手机主动旋转的场景。 在 Roomkit SDK 本身开发和客户接入的过程中咱们也会发现,实现屏幕旋转的需要往往没有那么顺利,常常会呈现无奈旋转、旋转后布局适配等问题。 本篇文章依据咱们以往的开发教训整顿了屏幕旋转实现的相干实际办法,解析在实现过程中遇到的常见问题。 一、疾速实现旋转iOS 屏幕旋转的实现波及到一堆枚举值和回调办法,对于没有做过旋转相干需要的开发来说,可能一上来就晕了,所以咱们先入手,让屏幕转起来吧。 实现旋转的形式次要有两种,追随手机感应旋转和手动旋转,接下来对这两种形式进行逐个介绍。 形式一:追随手机感应器旋转要实现主动追随手机旋转,首先要让以后的视图控制器实现以下三个办法: /// 是否主动旋转- (BOOL)shouldAutorotate { return YES;}/// 以后 VC反对的屏幕方向- (UIInterfaceOrientationMask)supportedInterfaceOrientations { return UIInterfaceOrientationMaskLandscapeRight | UIInterfaceOrientationMaskPortrait | UIInterfaceOrientationMaskLandscapeLeft;}/// 优先的屏幕方向- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation { return UIInterfaceOrientationPortrait;}这种办法须要留神以下几点: shouldAutorotate 返回 YES 示意追随零碎旋转,然而受 supportedInterfaceOrientations 办法的返回值影响,只反对追随手机传感器旋转到反对的方向。 preferredInterfaceOrientationForPresentation 须要返回 supportedInterfaceOrientations中反对的方向,不然会产生 'UIApplicationInvalidInterfaceOrientation'解体。 形式二:手动旋转这种形式在很多视频软件中都很常见,点击按钮后旋转至横屏。 这时须要在 shouldAutorotate 中返回 yes,而后再在此办法中 UIInterfaceOrientation 传入你须要旋转到的方向。留神这是公有办法,是否应用请自行斟酌。 - (void)changeVCToOrientation:(UIInterfaceOrientation)orientation { if ([[UIDevice currentDevice] respondsToSelector:@selector(setOrientation:)]) { SEL selector = NSSelectorFromString(@"setOrientation:"); NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:[UIDevice instanceMethodSignatureForSelector:selector]]; [invocation setSelector:selector]; [invocation setTarget:[UIDevice currentDevice]]; int val = orientation; [invocation setArgument:&val atIndex:2]; [invocation invoke]; }}场景利用主动旋转如果你的 iPhone 没有关闭系统屏幕旋转,你就能发现零碎相册 APP 的页面是能够跟着手机转动方向旋转的。 ...

September 10, 2021 · 3 min · jiezi

关于ios:iOS-端容器之WKWebView那些事

相熟 iOS/macOS Hybrid 混合开发的同学应该都有领会,WKWebView 尽管是苹果作为代替 UIWebView\WebView 而推出的"新"组件,但大部分开发者对它切实“爱不起来”。毕竟对于国内大部分利用开发者来说,在理论应用中 WKWebView 所谓的“劣势”未必能体现进去,但带来的“坑”却都着实都不浅。 目前社区或线上可查找的 WKWebView 相干材料,大多比拟古老且随声附和、复制粘贴类的居多。少部分实在实际和摸索的开发者,或者也因工夫或精力的起因,对问题和解决方案未能做具体的论述。导致目前线上 WKWebView 相干的材料数量不少、但品质不高;且有不少文章存在对问题的背景解释不清,解决方案不足无效验证等问题。 我从事端容器畛域开发多年,曾在生产环境方案设计上与 WKWebView "反抗"屡次。目前混合开发曾经是古代 App 标配,一方面是对这么长时间用法教训上的总结,另外一方面也心愿可能为还在抗争中的同学提供一些新视角或者解决思路,故筹备联合 WebKit 局部源码,将本人对这个组件的了解以及局部问题解决方案整顿分享一下。本文尝试阐明 3 件事件: WKWebView 应用中的典型问题有哪些?为什么会呈现这些问题?这些问题的解决办法有哪些?根底回顾iOS 端网络设计和 WKWebView 设计特点咱们能够通过官网材料来查阅。但为了前面更好的阐明问题,上面咱们重点回顾下与文章后续内容相干的两个根本知识点: iOS 端网络设计与 Cookie 治理WKWebView 多过程模型iOS 网络设计与 Cookie 治理Cookie 治理是做混合开发过程中常常会波及到的局部,在利用开发中咱们晓得能够通过 NSHTTPCookie 和 NSHTTPCookieStorage 来治理利用的 Cookie。但在零碎层面 Cookie 是如何治理的、如何与网络层各模块进行联动,这对咱们前面剖析 WKWebView 中的 Cookie 问题有着至关重要的分割。 依据官网材料,咱们可知 iOS 平台下网络相干模块大略关系如下: 从上至下模块顺次为: WebKit:应用层,客户端 App 以及 WKWebView 处于这一层;NSURL:能够了解为对底层 CF 接口的封装扩大层,NSURLConnection、NSURLSession 等处于这一层;CFNetwork:iOS 网络模块外围实现层,是网络层设计中最重要的局部。负责网络协议组装发送接管等次要工作,与 CoreFoundation 框架关系严密;BSD socket:基于底层硬件接口的 socket 服务。CFNetwork 是整个网络系统的外围模块,负责组装申请、解决响应等: ...

September 8, 2021 · 5 min · jiezi

关于ios:IOS应用崩溃复活

IOS利用解体始终是一个很苦恼的问题,而解体的同时又未获取bug起因,更令人苦恼。好在苹果自带的crash检测api,以及runloop能够让利用复活一次,不过第二次依旧会解体,然而还是一个很实用的小技巧。以下是IOS解体复活的类和应用办法 #import "CrashHandler.h"//Appdelagte中注册crash记录上报- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. [CrashHandler sharedInstance]; return YES;}//.h文件#import <Foundation/Foundation.h>@interface CrashHandler : NSObject{ BOOL ignore;}+ (instancetype)sharedInstance;@end//.m文件#import "CrashHandler.h"#import <UIKit/UIKit.h>#include <libkern/OSAtomic.h>#include <execinfo.h>NSString * const kSignalExceptionName = @"kSignalExceptionName";NSString * const kSignalKey = @"kSignalKey";NSString * const kCaughtExceptionStackInfoKey = @"kCaughtExceptionStackInfoKey";void HandleException(NSException *exception);void SignalHandler(int signal);@implementation CrashHandlerstatic CrashHandler *instance = nil;+ (instancetype)sharedInstance{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [[[self class] alloc] init]; }); return instance;}+ (instancetype)allocWithZone:(struct _NSZone *)zone{ static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ instance = [super allocWithZone:zone]; }); return instance;}- (instancetype)init{ self = [super init]; if (self) { [self setCatchExceptionHandler]; } return self;}- (void)setCatchExceptionHandler{ // 1.捕捉一些异样导致的解体 NSSetUncaughtExceptionHandler(&HandleException); // 2.捕捉非异常情况,通过signal传递进去的解体 signal(SIGABRT, SignalHandler); signal(SIGILL, SignalHandler); signal(SIGSEGV, SignalHandler); signal(SIGFPE, SignalHandler); signal(SIGBUS, SignalHandler); signal(SIGPIPE, SignalHandler);}+ (NSArray *)backtrace{ void* callstack[128]; int frames = backtrace(callstack, 128); char **strs = backtrace_symbols(callstack, frames); NSMutableArray *backtrace = [NSMutableArray arrayWithCapacity:frames]; for (int i = 0; i < frames; i++) { [backtrace addObject:[NSString stringWithUTF8String:strs[i]]]; } free(strs); return backtrace;}- (void)alertView:(UIAlertView *)anAlertView clickedButtonAtIndex:(NSInteger)anIndex{ if (anIndex == 0) { ignore = YES; } else if (anIndex == 1) { NSLog(@"起死回生"); }}- (void)handleException:(NSException *)exception{ NSString *message = [NSString stringWithFormat:@"解体起因如下:\n%@\n%@", [exception reason], [[exception userInfo] objectForKey:kCaughtExceptionStackInfoKey]]; NSLog(@"%@",message); UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"程序解体了" message:@"如果你能让程序起死回生,那你的决定是?" delegate:self cancelButtonTitle:@"崩就蹦吧" otherButtonTitles:@"起死回生", nil]; [alert show]; CFRunLoopRef runLoop = CFRunLoopGetCurrent(); CFArrayRef allModes = CFRunLoopCopyAllModes(runLoop); while (!ignore) { for (NSString *mode in (__bridge NSArray *)allModes) { CFRunLoopRunInMode((CFStringRef)mode, 0.001, false); } } CFRelease(allModes); NSSetUncaughtExceptionHandler(NULL); signal(SIGABRT, SIG_DFL); signal(SIGILL, SIG_DFL); signal(SIGSEGV, SIG_DFL); signal(SIGFPE, SIG_DFL); signal(SIGBUS, SIG_DFL); signal(SIGPIPE, SIG_DFL); if ([[exception name] isEqual:kSignalExceptionName]) { kill(getpid(), [[[exception userInfo] objectForKey:kSignalKey] intValue]); } else { [exception raise]; }}@endvoid HandleException(NSException *exception){ // 获取异样的堆栈信息 NSArray *callStack = [exception callStackSymbols]; NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; [userInfo setObject:callStack forKey:kCaughtExceptionStackInfoKey]; CrashHandler *crashObject = [CrashHandler sharedInstance]; NSException *customException = [NSException exceptionWithName:[exception name] reason:[exception reason] userInfo:userInfo]; [crashObject performSelectorOnMainThread:@selector(handleException:) withObject:customException waitUntilDone:YES];}void SignalHandler(int signal){ // 这种状况的解体信息,就另某他法来捕捉吧 NSArray *callStack = [CrashHandler backtrace]; NSLog(@"信号捕捉解体,堆栈信息:%@",callStack); CrashHandler *crashObject = [CrashHandler sharedInstance]; NSException *customException = [NSException exceptionWithName:kSignalExceptionName reason:[NSString stringWithFormat:NSLocalizedString(@"Signal %d was raised.", nil),signal] userInfo:@{kSignalKey:[NSNumber numberWithInt:signal]}]; [crashObject performSelectorOnMainThread:@selector(handleException:) withObject:customException waitUntilDone:YES];}

September 6, 2021 · 2 min · jiezi

关于ios:iOS-屏幕实时共享功能实践内附详细代码

很多人对屏幕共享的印象还只停留在 PC 端做 PPT 汇报的场景中,但事实上,明天的屏幕共享早已跨界出圈了。比方一个大家很相熟的场景 —— 游戏直播,主播就须要将本人的画面以“屏幕共享”的模式展现给观众,并且对实时性、流畅性的要求十分高。 对于很多手游主播来说,目前比拟常见的做法是,通过借助 PC 端的直达将手机游戏画面进行直播分享;而实际上,通过调用融云屏幕共享 SDK,间接在手机端就能够领有屏幕实时共享的能力。 本文就将次要围绕 iOS 屏幕共享问题展开讨论,一起理解 iOS ReplayKit 框架的倒退过程,各个阶段的性能演变,以及联合融云屏幕共享 SDK 实现相应性能的代码和思路。 01 ReplayKit 发展史 iOS 端屏幕录制 ReplayKit 是从 iOS9 开始呈现的。 iOS9 WWDC15 首次提供 ReplayKit 框架,它的初期呈现次要用于录制视频,存于相册。 iOS9 开始录制和进行录制两个 API 有很大的局限性: 只能获取系统生成好的 MP4 文件,且不能间接获取,须要先保留到相册,再从相册获取; 不能够获取源数据,也就是 pcm 和 yuv 数据; 给开发者的权限低,不能录制其余 APP,且退出后盾就不会录制了,只能录制以后 APP 画面。 可控行为在于: 进行录制可弹出一个视频预览窗口,能进行保留或勾销或分享该视频文件; 录制实现后能够进行查看、编辑,或者通过指定形式分享。 开始录制视频的 API 如下所示。 /*! Deprecated. Use startRecordingWithHandler: instead. @abstract Starts app recording with a completion handler. Note that before recording actually starts, the user may be prompted with UI to confirm recording. @param microphoneEnabled Determines whether the microphone input should be included in the recorded movie audio. @discussion handler Called after user interactions are complete. Will be passed an optional NSError in the RPRecordingErrorDomain domain if there was an issue starting the recording. */[[RPScreenRecorder sharedRecorder] startRecordingWithMicrophoneEnabled:YES handler:^(NSError * _Nullable error) { if (error) { //TODO..... }}];调用开始录屏的时候,零碎会弹出一个弹窗,须要用户进行确认后能力失常录制。进行录制视频的 API 如下所示。 ...

September 6, 2021 · 4 min · jiezi

关于ios:iOS-获取手机IP地址-Mac地址

iOS 获取手机IP地址 Mac地址pragma MARK - 获取Ip 地址-(NSString *)getIponeIP{ NSString *address = @"error";struct ifaddrs *interfaces = NULL;struct ifaddrs *temp_addr = NULL;int success = 0;// retrieve the current interfaces - returns 0 on successsuccess = getifaddrs(&interfaces);if (success == 0) { // Loop through linked list of interfaces temp_addr = interfaces; while(temp_addr != NULL) { if(temp_addr->ifa_addr->sa_family == AF_INET) { // Check if interface is en0 which is the wifi connection on the iPhone if([[NSString stringWithUTF8String:temp_addr->ifa_name] isEqualToString:@"en0"]) { // Get NSString from C String address = [NSString stringWithUTF8String:inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr)]; } } temp_addr = temp_addr->ifa_next; }}// Free memoryfreeifaddrs(interfaces);NSLog(@"-------ip %@", address);return address;} ...

September 2, 2021 · 1 min · jiezi

关于ios:iOS使用视听媒体框架AVFoundation实现照片拍摄

用零碎自带的视听媒体的框架,AVFoundation实现照片拍摄。相比UIKit框架(UIImagePickerController高度封装),AVFoundation框架让开发者有更大的施展空间。 首先看一下效果图:上面贴上外围控制器代码: #import "HWPhotoVC.h"#import <AVFoundation/AVFoundation.h> @interface HWPhotoVC () @property (nonatomic, strong) AVCaptureSession *captureSession;//负责输出和输出设备之间的数据传递@property (nonatomic, strong) AVCaptureDeviceInput *captureDeviceInput;//负责从AVCaptureDevice取得输出数据@property (nonatomic, strong) AVCaptureStillImageOutput *captureStillImageOutput;//照片输入流@property (nonatomic, strong) AVCaptureVideoPreviewLayer *captureVideoPreviewLayer;//相机拍摄预览图层@property (nonatomic, weak) UIView *containerView;//内容视图@property (nonatomic, weak) UIImageView *focusCursor;//聚焦按钮@property (nonatomic, weak) UIImageView *imgView;//拍摄照片 @end @implementation HWPhotoVC - (void)viewDidLoad { [super viewDidLoad]; self.navigationItem.title = @"拍照"; self.view.backgroundColor = [UIColor whiteColor]; //创立控件 [self creatControl];} - (void)viewWillAppear:(BOOL)animated{ [super viewWillAppear:animated]; //初始化信息 [self initPhotoInfo];} - (void)viewDidAppear:(BOOL)animated{ [super viewDidAppear:animated]; [self.captureSession startRunning];} - (void)viewDidDisappear:(BOOL)animated{ [super viewDidDisappear:animated]; [self.captureSession stopRunning];} - (void)creatControl{ CGFloat btnW = 150.f; CGFloat btnH = 40.f; CGFloat marginY = 20.f; CGFloat w = [UIScreen mainScreen].bounds.size.width; CGFloat h = [UIScreen mainScreen].bounds.size.height; //内容视图 CGFloat containerViewH = h - 64 - btnH - marginY * 3; UIView *containerView = [[UIView alloc] initWithFrame:CGRectMake(10, 64 + marginY, w - 20, containerViewH)]; containerView.backgroundColor = [UIColor whiteColor]; containerView.layer.borderWidth = 1.f; containerView.layer.borderColor = [[UIColor grayColor] CGColor]; [self.view addSubview:containerView]; _containerView = containerView; //摄像头切换按钮 CGFloat cameraSwitchBtnW = 50.f; CGFloat cameraSwitchBtnMargin = 10.f; UIButton *cameraSwitchBtn = [[UIButton alloc] initWithFrame:CGRectMake(containerView.bounds.size.width - cameraSwitchBtnW - cameraSwitchBtnMargin, 64 + marginY + cameraSwitchBtnMargin, cameraSwitchBtnW, cameraSwitchBtnW)]; [cameraSwitchBtn setImage:[UIImage imageNamed:@"camera_switch"] forState:UIControlStateNormal]; [cameraSwitchBtn addTarget:self action:@selector(cameraSwitchBtnOnClick) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:cameraSwitchBtn]; //聚焦图片 UIImageView *focusCursor = [[UIImageView alloc] initWithFrame:CGRectMake(50, 50, 75, 75)]; focusCursor.alpha = 0; focusCursor.image = [UIImage imageNamed:@"camera_focus_red"]; [containerView addSubview:focusCursor]; _focusCursor = focusCursor; //拍摄照片容器 UIImageView *imgView = [[UIImageView alloc] initWithFrame:containerView.frame]; imgView.hidden = YES; imgView.layer.borderWidth = 1.f; imgView.layer.borderColor = [[UIColor grayColor] CGColor]; imgView.contentMode = UIViewContentModeScaleAspectFill; imgView.clipsToBounds = YES; [self.view addSubview:imgView]; _imgView = imgView; //按钮 NSArray *titleArray = @[@"拍摄照片", @"从新拍摄"]; CGFloat btnY = CGRectGetMaxY(containerView.frame) + marginY; CGFloat margin = (w - btnW * titleArray.count) / (titleArray.count + 1); for (int i = 0; i < titleArray.count; i++) { CGFloat btnX = margin + (margin + btnW) * i; UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake(btnX, btnY, btnW, btnH)]; btn.tag = 1000 + i; [btn setTitle:titleArray[i] forState:UIControlStateNormal]; btn.backgroundColor = [UIColor orangeColor]; btn.layer.cornerRadius = 2.0f; btn.layer.masksToBounds = YES; if (i == 1) { btn.hidden = YES; } [btn addTarget:self action:@selector(btnOnClick:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:btn]; }} - (void)initPhotoInfo{ //初始化会话 _captureSession = [[AVCaptureSession alloc] init]; //设置分辨率 if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset1280x720]) { _captureSession.sessionPreset = AVCaptureSessionPreset1280x720; } //取得输出设施,获得后置摄像头 AVCaptureDevice *captureDevice = [self getCameraDeviceWithPosition:AVCaptureDevicePositionBack]; if (!captureDevice) { NSLog(@"获得后置摄像头时呈现问题"); return; } NSError *error = nil; //依据输出设施初始化设施输出对象,用于取得输出数据 _captureDeviceInput = [[AVCaptureDeviceInput alloc]initWithDevice:captureDevice error:&error]; if (error) { NSLog(@"获得设施输出对象时出错,谬误起因:%@", error.localizedDescription); return; } //初始化设施输入对象,用于取得输入数据 _captureStillImageOutput = [[AVCaptureStillImageOutput alloc] init]; NSDictionary *outputSettings = @{AVVideoCodecKey:AVVideoCodecJPEG}; //输入设置 [_captureStillImageOutput setOutputSettings:outputSettings]; //将设施输出增加到会话中 if ([_captureSession canAddInput:_captureDeviceInput]) { [_captureSession addInput:_captureDeviceInput]; } //将设施输入增加到会话中 if ([_captureSession canAddOutput:_captureStillImageOutput]) { [_captureSession addOutput:_captureStillImageOutput]; } //创立视频预览层,用于实时展现摄像头状态 _captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession]; //摄像头方向 AVCaptureConnection *captureConnection = [self.captureVideoPreviewLayer connection]; captureConnection.videoOrientation = AVCaptureVideoOrientationPortrait; CALayer *layer = _containerView.layer; layer.masksToBounds = YES; _captureVideoPreviewLayer.frame = layer.bounds; //填充模式 _captureVideoPreviewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; //将视频预览层增加到界面中 [layer insertSublayer:_captureVideoPreviewLayer below:self.focusCursor.layer]; [self addNotificationToCaptureDevice:captureDevice]; [self addGenstureRecognizer];} - (void)btnOnClick:(UIButton *)btn{ if (btn.tag == 1000) { //拍摄照片 [self photoBtnOnClick]; }else if (btn.tag == 1001) { //从新拍摄 [self resetPhoto]; }} #pragma mark 拍照- (void)photoBtnOnClick{ //依据设施输入取得连贯 AVCaptureConnection *captureConnection = [self.captureStillImageOutput connectionWithMediaType:AVMediaTypeVideo]; captureConnection.videoOrientation = AVCaptureVideoOrientationPortrait; //依据连贯获得设施输入的数据 [self.captureStillImageOutput captureStillImageAsynchronouslyFromConnection:captureConnection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) { if (imageDataSampleBuffer) { NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; UIImage *image = [UIImage imageWithData:imageData]; _imgView.image = image; _imgView.hidden = NO; } }]; UIButton *btn = (UIButton *)[self.view viewWithTag:1001]; btn.hidden = NO;} //从新拍摄- (void)resetPhoto{ _imgView.hidden = YES; UIButton *btn = (UIButton *)[self.view viewWithTag:1001]; btn.hidden = YES;} #pragma mark - 告诉//给输出设施增加告诉- (void)addNotificationToCaptureDevice:(AVCaptureDevice *)captureDevice{ //留神增加区域扭转捕捉告诉必须首先设置设施容许捕捉 [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) { captureDevice.subjectAreaChangeMonitoringEnabled = YES; }]; //捕捉区域产生扭转 [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(areaChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:captureDevice];} - (void)removeNotificationFromCaptureDevice:(AVCaptureDevice *)captureDevice{ [[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:captureDevice];} //移除所有告诉- (void)removeNotification{ [[NSNotificationCenter defaultCenter] removeObserver:self];} //设施连贯胜利- (void)deviceConnected:(NSNotification *)notification{ NSLog(@"设施已连贯...");} //设施连贯断开- (void)deviceDisconnected:(NSNotification *)notification{ NSLog(@"设施已断开.");} //捕捉区域扭转- (void)areaChange:(NSNotification *)notification{ NSLog(@"捕捉区域扭转...");} #pragma mark - 公有办法//获得指定地位的摄像头- (AVCaptureDevice *)getCameraDeviceWithPosition:(AVCaptureDevicePosition )position{ NSArray *cameras = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; for (AVCaptureDevice *camera in cameras) { if ([camera position] == position) { return camera; } } return nil;} #pragma mark 切换前后摄像头- (void)cameraSwitchBtnOnClick{ AVCaptureDevice *currentDevice = [self.captureDeviceInput device]; AVCaptureDevicePosition currentPosition = [currentDevice position]; [self removeNotificationFromCaptureDevice:currentDevice]; AVCaptureDevice *toChangeDevice; AVCaptureDevicePosition toChangePosition = AVCaptureDevicePositionFront; if (currentPosition == AVCaptureDevicePositionUnspecified || currentPosition == AVCaptureDevicePositionFront) { toChangePosition = AVCaptureDevicePositionBack; } toChangeDevice = [self getCameraDeviceWithPosition:toChangePosition]; [self addNotificationToCaptureDevice:toChangeDevice]; //取得要调整的设施输出对象 AVCaptureDeviceInput *toChangeDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:toChangeDevice error:nil]; //扭转会话的配置前肯定要先开启配置,配置实现后提交配置扭转 [self.captureSession beginConfiguration]; //移除原有输出对象 [self.captureSession removeInput:self.captureDeviceInput]; //增加新的输出对象 if ([self.captureSession canAddInput:toChangeDeviceInput]) { [self.captureSession addInput:toChangeDeviceInput]; self.captureDeviceInput = toChangeDeviceInput; } //提交会话配置 [self.captureSession commitConfiguration];} //扭转设施属性的对立操作方法- (void)changeDeviceProperty:(void (^)(AVCaptureDevice *))propertyChange{ AVCaptureDevice *captureDevice = [self.captureDeviceInput device]; NSError *error; //留神扭转设施属性前肯定要首先调用lockForConfiguration:调用完之后应用unlockForConfiguration办法解锁 if ([captureDevice lockForConfiguration:&error]) { propertyChange(captureDevice); [captureDevice unlockForConfiguration]; }else { NSLog(@"设置设施属性过程产生谬误,错误信息:%@", error.localizedDescription); }} //设置闪光灯模式- (void)setFlashMode:(AVCaptureFlashMode)flashMode{ [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) { if ([captureDevice isFlashModeSupported:flashMode]) { [captureDevice setFlashMode:flashMode]; } }];} //设置聚焦模式- (void)setFocusMode:(AVCaptureFocusMode)focusMode{ [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) { if ([captureDevice isFocusModeSupported:focusMode]) { [captureDevice setFocusMode:focusMode]; } }];} //设置曝光模式- (void)setExposureMode:(AVCaptureExposureMode)exposureMode{ [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) { if ([captureDevice isExposureModeSupported:exposureMode]) { [captureDevice setExposureMode:exposureMode]; } }];} //设置聚焦点- (void)focusWithMode:(AVCaptureFocusMode)focusMode exposureMode:(AVCaptureExposureMode)exposureMode atPoint:(CGPoint)point{ [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) { if ([captureDevice isFocusModeSupported:focusMode]) { [captureDevice setFocusMode:AVCaptureFocusModeAutoFocus]; } if ([captureDevice isFocusPointOfInterestSupported]) { [captureDevice setFocusPointOfInterest:point]; } if ([captureDevice isExposureModeSupported:exposureMode]) { [captureDevice setExposureMode:AVCaptureExposureModeAutoExpose]; } if ([captureDevice isExposurePointOfInterestSupported]) { [captureDevice setExposurePointOfInterest:point]; } }];} //增加点按手势,点按时聚焦- (void)addGenstureRecognizer{ [self.containerView addGestureRecognizer:[[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapScreen:)]];} - (void)tapScreen:(UITapGestureRecognizer *)tapGesture{ CGPoint point = [tapGesture locationInView:self.containerView]; //将UI坐标转化为摄像头坐标 CGPoint cameraPoint = [self.captureVideoPreviewLayer captureDevicePointOfInterestForPoint:point]; [self setFocusCursorWithPoint:point]; [self focusWithMode:AVCaptureFocusModeAutoFocus exposureMode:AVCaptureExposureModeAutoExpose atPoint:cameraPoint];} //设置聚焦光标地位- (void)setFocusCursorWithPoint:(CGPoint)point{ self.focusCursor.center = point; self.focusCursor.transform = CGAffineTransformMakeScale(1.5, 1.5); self.focusCursor.alpha = 1.0; [UIView animateWithDuration:1.0 animations:^{ self.focusCursor.transform = CGAffineTransformIdentity; } completion:^(BOOL finished) { self.focusCursor.alpha = 0; }];} - (void)dealloc{ [self removeNotification];} @endDemo下载链接 ...

August 30, 2021 · 4 min · jiezi

关于ios:iOS混淆探索

iOS审核现状目前Apple审核越来越智能化“动态剖析+动态分析”,详见揭秘苹果利用审核团队(史上最全版) 总结如下: 旧形式:动态批改(简略的全局批改名称早曾经不实用了)新策略:彻底混同+模仿人工混同成为支流马甲包的实质:阶段一减低反复率,例如根本的类名、属性名、办法名,字符串等阶段二缩小类似度(雷同元素的正态分布),属性名、办法名是否按类辨别(例如:雷同属性名在不同类中混同完是否扭转,以及不同办法名在不同的类中混同完其实能够雷同的)。阶段三扭转代码执行流程辨别工具优劣其实辨认一个工具的优劣,只需看看以下几点: 是否批改所有的属性、办法,及办法的所有参数名批改成员(属性、办法)名称,是否按类辨别,还是简略的全局替换带block的参数的办法,典型的网络申请 例如:+ (BOOL)post:(NSString )url parameters:(NSDictionary )parameters success:(HttpRequestResponse)success error:(HttpRequestResponse)error;办法名和属性名改后的名字的长短(例如:name、title等且保障不与零碎抵触,齐全摒弃简略的靠大量单词库堆砌以保障命名的唯一性的做法)批改布局(Frame、Masonry、SDAutoLayout)插入的是代码还是‘垃圾’(大量随机毫无关联的垃圾代码)。 例如:+ (void)init;- (void)reloadData;根本能改,做到的有几个呢?”工具比拟目前很多工具都是停留在部分‘名称’全局替换这一个根本的性能,以及插入毫无关联度的随机垃圾代码,而且这两年根本停更状态,即便有更新也是bug小保护,没有实质上的冲破。 有一款工具很不错【520coding/confuse】,这款工具是能辨认宏、辨别继承链等上下文关联内容,智能辨认不可批改局部,做到齐全混同。同时插入的代码通过封装网络申请、数据存储、创立自定义控件,以及文件之间应用MVC模式关联,彻底辞别‘垃圾’,实现以假乱真。继续更新中,详见更新日志,运行APP效果图,工具应用教程

August 27, 2021 · 1 min · jiezi

关于ios:从-350ms-到-80ms打造新零售场景下-iOS-短视频的极致丝滑体验

内容作为 App 产品新的促活点,受到了越来越多的器重与投入,短视频则是减少用户粘性、减少用户停留时长的一把利器。短视频的内容与体验间接关系到用户是否违心长时停留,盒马也提出全链路内容视频化的布局,以实现商品力表白的晋升。目前已有短视频场景包含:首页、搜寻、商品详情、达人秀、沉迷式视频、真香视频、盒区首页 feeds 流、话题、UGC 内容、话题合集落地页、社群、菜谱、盒拍一键剪、直播回放、weex 等。 作者|神捕 审校|泰一 本次优化的指标是将盒马 App 与支流短视频 App 体验对齐,如抖音、手淘等。优化具体的硬性指标有播放成功率、卡顿率、秒开率。另外,为了反馈用户观看短视频过程中的实在体验,盒马还新增了体感指标:首帧渲染时长。 优化成果比照https://www.youku.com/video/X... 以上视频测试基于 iPhone 6S,能够看到抖音在大多数状况下,在滑到下个视频后,能够立刻开始播放;而盒马优化前,滑到下个视频后,会先展现封面图,再持续播放,有个闪跳的过程。优化后的盒马,成果曾经与抖音成果靠近。 为了掂量优化前后与抖音的体验比照,目前采纳录屏数帧的形式,算出视频页面齐全展现到首帧渲染时刻的耗时,体感数据如下: 此外还有一些硬性指标的优化,后果如下: 优化计划在本次优化后期,调研了阿里团体内不少优良的计划,大多数都是接入了手淘播放器,内核基于开源的 ijkPlayer。但播放器层面自身门槛较高,且手淘已优化较好了,所以本次的优化方向次要集中在下层业务的预加载计划上。具体从以下几个方面动手: 对立视频播放代理与缓存视频的加载速度,很大水平上取决于从网络下载的耗时,减少视频缓存能够无效进步视频二次播放速度。为实现缓存机制,须要引入代理服务器,接手视频数据下载流程,如下: A. 优化前播放流程: B. 优化后播放流程: 业务层往播放器设置 videoUrl 前,先对原始 videoUrl 加密,替换成 127.0.0.1 的本地 proxyUrl, 将申请疏导到代理 webServer,此时调用 proxy 模块进行视频原始视频 url 的解析、缓存的读取或近程申请,最终再通过 server 返回数据给播放器。 视频播放减少两头代理也是业界常见伎俩,盒马依赖的手淘播放器也有现成的代理服务,但其代理性能放在另一个独立的 DW 库中,对盒马是冗余的,且目前 SDK 暂未反对独立的预下载接口,下层无奈做首播优化。所以目前盒马做了独立的代理层,以反对下层灵便的定制。 自建代理还有个益处是,一些业务并非应用对立手淘播放器的场景也能同时享受到缓存服务,比方一些 flutter 页面应用的零碎播放器。至多缓存的治理,目前设置了缓存区最大值的爱护,在每次 App 回到前台时,进行视频缓存的清理。 针对 m3u8 的代理与缓存除了常见的 mp4 视频外,日常还会遇到 m3u8 的视频,比方盒马中的直播回放视频。(视频链接) 该类视频与 mp4 不同,在申请 url 时并非间接返回视频流,而是先返回 playlist 文本,playlist 中才是可播放的各个视频片断,如下: ...

August 27, 2021 · 2 min · jiezi

关于ios:排查指南-两个案例学会从埋点排查-iOS-离线包

简介: 首次关上离线包白屏以及报错“-1009”等该如何解决呢? 离线包原理以一次启动离线包的流程为例,离线包的加载流程分为两种场景,第一种是离线包下载好的场景,流程如图1所示,第二种是离线包没下载好的场景,如图2所示: 图1:离线包加载支流 图2:离线包下载流程 咱们能够从埋点来跟踪离线包具体的加载流程*: 查看本地是否有离线包,本地有则执行第四步解压,解压之后再进行校验,校验通过加载本地离线包,如果本地曾经装置过,那就不须要解压间接走解压后的流程网络申请离线包信息,这一步和上一步是异步进行的,对应的埋点有 H5_APP_REQUEST比照申请回来的离线包信息,再决定是否下载离线包,对应的埋点有 H5_APP_DOWNLOAD解压离线包,对应的埋点有 H5_APP_UNZIP如果开启了离线包验签,校验离线包的合法性,对应的埋点有 H5_APP_VERIFY、H5_AL_SESSION_VERIFYTAR_FAIL加载本地离线包,对应的埋点有 H5_AL_SESSION_MAP_SUCCESS、H5_AL_SESSION_FALLBACK留神:fallback走线上须要等到离线包申请这个异步申请回调回来之后返回的 fallback + mainUrl 确定 Webview 关上的URL。 *参考资料:离线包日志埋点 案例1:首次关上离线包白屏STEP1:依照离线包加载流程剖析,首次关上离线包肯定是须要走线上的fallback,因为本地没有,走线上之前肯定须要先晓得离线包的线上地址也就是URL,所以须要查看日志剖析是否是申请离线包信息那一步出错了。 STEP2:剖析日志关上线上离线包的时候URL为空,在离线包申请还没有回调回来之前就关上离线包,所以呈现了白屏。 STEP3:查看代码 将创立的离线包控制器作为根视图,机会过早,所以导致了该问题。 STEP4:联合客户需要给出倡议,能够应用本地预制离线包解决首次过早关上离线包呈现白屏的问题。 案例2:关上预置离线包,报错(-1009)复现demo STEP1:断网状况下关上预制离线包失败显示网络无奈连贯阐明关上预制包失败了,所以走了线上,因为没有网络所以显示网络无奈连贯,问题出在本地预制的离线包上。 STEP2:依照离线包的加载流程剖析,在本地有预制包的状况下呈现走线上的状况别离有两种状况,离线包验证签名失败和加载本地离线包失败。 STEP3:日志剖析 察看到有验签失败的字样。 STEP4:查看代码客户端是否敞开了验签,默认是开启的,如果没有敞开,那么客户端须要设置对应的公钥,或者敞开验签。 STEP5:敞开验签再试一遍,持续剖析日志: H5_AL_SESSION_FALLBACK加载本地离线包失败,最终走的线上,察看解压离线包胜利没有问题,问题出在加载离线包那一步,日志中查找到H5_APP_EXCEP离线包异样埋点,是读取数据时候失败了。 STEP6:问题有可能呈现在该离线包下面,所提供一个失常的离线包给客户做成本地预制离线包,断网关上验证,没有问题,问题就出在该离线包上。 STEP7:解开预制的离线包,察看离线包是否门路字符总长度是否超过了限度导致读取数据失败。 JS文件名称过长,导致总的字符长度超过了限度,须要客户批改离线包*。 思考和总结通过下面两个案例的介绍,咱们能够清晰的看到案例一最终呈现问题的起因是申请离线包信息这个申请没有回调回来,客户就关上离线包时没有获取到URL,问题呈现在了申请离线包那一步了,而案例二最终定位到加载本地包失败那一步。 理解了离线包的具体加载流程,再联合 nebula 容器自动化埋点日志,就能够具体定位问题到离线包加载的哪一步了。 本文作者:阿里云 mPaaS TMA 团队(杨强 荣阳) 原文链接本文为阿里云原创内容,未经容许不得转载。

August 23, 2021 · 1 min · jiezi

关于ios:iOS开发面试只需知道这些技术基本通关网络篇

一、HTTP 协定HTTP 协定:超文本传输协定 是一种具体规定了浏览器和万维网(WWW = World Wide Web)服务器之间相互通信的规定,通过因特网传送 万维网文档的数据传送协定。HTTP 是基于 TCP 的应用层协定 (OSI 网络七层协定从上到下别离是 应用层、表示层、会话层 、传输层、网络层 、数据链路层、物理层) * 申请/响应报文 连贯建设流程* HTTP 的特点 A、申请报文和响应报文 1、申请报文 如下: Host:指明了该对象所在的主机 Connection:Keep-Alive 首部行用来表明该浏览器通知服务器应用继续连贯 Content-Type: x-www-form-urlencoded 首部行用来表明 HTTP 会将申请参数用 key1=val1&key2=val2 的方 式进行组织,并放到申请实体外面 User-agent:首部行用来指明用户代理,即向服务器发送申请的浏览器类型 Accept-lauguage:首部行示意用户想得到该对象的法语版本(如果服务器中有这样的对象的话),否则, 服务器应发送它的默认版本 2、响应报文 如下: 状态码及其相应的短语批示了申请的后果。 一些常见的状态码和对应的短语: 200 OK:申请胜利,信息在返回的响应报文中301 Moved Permanently:申请的对象曾经被永恒转移了,新的 URL 定义在响应报文中的 Location:首部行中。客户软件将主动获取新的 URL400 Bad Request:一个通用过错代码,批示该申请不能被服务器了解404 Not Found:被申请的文件不在服务器上505 HTTP Version Not Supported:服务器不反对申请报文应用的 HTTP 协定版本<4 结尾的状态码通常是客户端的问题,5 结尾的则通常是服务端的问题> Connection:close 首部行通知客户,发送完报文后将敞开 TCP 连贯。 Date:指的不是对象创立或最初批改的工夫,而是服务器从文件系统中检索到该对象,插入到响应报文, 并发送该响应报文的工夫。 Server: 首部行批示该报文是由一台 Apache Web 服务器产生的,相似于 HTTP 申请报文里的 User-agent Content-Length:首部行批示了被发送对象中的字节数Content-Type:首部行批示了实体体中的对象是 HTML 文本 二、HTTP 的申请形式GET、POST、PUT、DELETE、HEAD、OPTIONS 1、GET 和POST形式的区别 从语法角度来看,最直观的区别就是 GET 的申请参数个别以?宰割拼接到 URL 前面,POST 申请参数在 Body 外面GET 参数长度限度为 2048 个字符,POST 个别是没限度的GET 申请因为参数袒露在 URL 中, 是不平安的,POST 申请则是绝对平安之所以说是绝对平安,是因为,如果 POST 尽管参数非明文,但如果被抓包,GET 和 POST 一样都是不平安的。(HTTPS 该用还是得用) ...

August 20, 2021 · 6 min · jiezi

关于ios:iOS-App注入SDK调试

前言本文仅作为技术分享,对于一些iOS SDK开发以及保护所遇到的场景问题进行解决,例如: 客户想提前通晓线上App集成咱们SDK后,是否会有SDK兼容性问题,例如Crash,符号抵触客户线上App集成了咱们SDK,呈现了问题,如何进行排查咱们想测试SDK在某一款App中是否性能失常对于这些问题,一般来说咱们无奈拿到App的源码,想要解决这些场景,就须要拿到客户App文件并注入代码,接下来咱们从 iOS越狱、frida砸壳、MonkeyDev来讲述如何实现。 iOS 越狱为什么须要越狱?因为失常状况下,咱们无奈从手机中获取到App的包文件,只能通过越狱机 动静砸壳 取得ipa包,应用目前支流的 unc0ver 进行越狱。 unc0ver对于 iOS 的越狱,这里应用的是 unc0ver ,最新版本反对 iOS 11 - iOS 14.3 版本的非完满越狱,这里采纳应用 iphone 5S, iOS 12.4.9 为例,进行 非完满越狱 越狱有分为“完满越狱”和“不完满越狱”。完满越狱简略地说就是越狱很彻底,破解了操作系统的读写权限,完满越狱实现当前能够自在应用,开关机,下载等。称为“完满越狱”。而不完满越狱,则示意iPhone或iPad不能像越狱之前一样随时能够关机,关机重启后越狱生效,须要再进行越狱操作。对于 unc0ver ,咱们应用 Xcode + iOS App Signer 形式进行装置 unc0ver App 通过上述步骤生成的 unc0ver ipa 是合乎苹果要求的,你也能够通过 i4助手(爱思助手) 进行快捷装置到手机中。 关上 unc0ver,点击 Jailbreak 进行越狱,期间弹出 REBEL 不要管它,叉掉,持续。提醒你重启就重启,该容许的容许,而后持续关上 unc0ver 持续,直到 unc0ver 实现越狱,越狱好后,手机界面会多出Cydia和Substitude,同时关上 unc0ver 显示 Re-Jailbreak 。 配置 Cydia点击 Cydia->软件源->编辑->增加 增加源 build.frida.re ,apt.cydiami.com,并进行更新。搜寻 SSH ,抉择 OpenSSH 进行装置搜寻 frida ,因为是 5S,咱们抉择 Frida for pre-A12 devices搜寻 AFC ,装置 AFC2 iOS12系统文件拜访至此,越狱实现,能够拜访系统文件了。 ...

August 19, 2021 · 2 min · jiezi

关于ios:北京一卡通APP-iOS研发手册

北京一卡通APP iOS研发手册前言一、我的项目架构 我的项目依照代码的组织构造和调用关系,能够分为四层,别离是视图层、业务层、根底模块和数据拜访层。其中视图层负责页面展现和与用户交互(如用户的点击事件、划动手势等),业务层则对应具体的业务,例如充值模块、用户信息、乘车码、多扣票款等,根底模块蕴含了我的项目运行各个性能最根本的能力和组件,比方网络模块负责业务的网络申请,平安模块负责报文的加解密和签名验签,存储模块负责本地的数据长久化等等,数据拜访层是对我的项目所用到的所有信息的获取形式的形象和封装,包含从接口获取数据,从本地资源文件、本地缓存以及数据库等获取数据。 上面别离对各个模块做下介绍: 1、视图层2、业务层3、根底模块4、数据拜访层二、我的项目目录构造1、工程目录构造工程目录构造如下: 我的项目采纳了cocoapods的集成形式,目录构造次要分为Base、Common、Macro、Main、Resources、Sources、Supporting Files、Vendors、Pods。 其中, Base目录下是我的项目用到的根底ViewController的封装,蕴含加载WebView的,加载原生页面的,曾经他们的独特基类。Common目录蕴含了我的项目用到的公共代码。Macro是对我的项目罕用的宏的汇总。Main是我的项目的主代码目录。Resources是我的项目的资源文件,蕴含图片、预置离线包等。Sources是程序启动相干的源文件。Supporting Files蕴含了main.m也就是程序的入口文件,还有info.plist程序的配置文件,还有启动图等等。Vendors是手动导入的第三方库。Pods目录下是通过pod导入的第三方库。2、mPaas目录构造mPaaS目录构造如下: └── MPaaS ├── mpaas_sdk.config ├── Targets | └── mPaaSDemo(工程 Target 名称) | ├── mPaaSDemo-mPaaS-Headers.h | ├── mPaaSDemo-Prefix.pch | ├── APMobileFramework | ├── mPaas | ├── meta.config | └── yw_1222.jpg ├── Resources └── Frameworks其中, mpaas_sdk.config:以后工程增加的模块信息,包含版本、增加工夫、资源文件等,由 mPaaS 插件主动保护,不得手动批改。mPaaSDemo-mPaaS-Headers.h:以后工程依赖的 mPaaS 模块的头文件,由 mPaaS 插件主动保护,不得手动批改。mPaaSDemo-Prefix.pch:以后工程 pch 文件的援用,会主动将 mPaaSdemo-mPaaS-Headers.h 退出 mPaaS 模块的头文件。APMobileFramework:mpaas 框架的生命周期治理的 category 文件。mPaas:MPaaSInterface 的 category 文件。meta.config:从 mPaaS 控制台下载的云端元数据。yw_1222.jpg:通过元数据中的 base64code 字段生成的无线保镖验签图片,在挪动网关验签时应用。如不须要挪动网关性能,可删除此图片。Resources & Frameworks:mPaaS 模块的资源文件和二进制文件目录,是以后工程所有 Targets 应用的 mPaaS 模块的并集,由 mPaaS 插件主动保护,不得手动批改。三、开发流程标准1、需要评审 产品在明确需要之后,通过邮件收回需要文档,而后招集大家一起进行需要评审。参加需要评审的人个别蕴含负责该项目标产品经理,已及相干测试人员,负责开发的前后端开发人员,局部重要我的项目领导也会参加评审。 ...

August 17, 2021 · 3 min · jiezi

关于ios:iOS开发面试只需知道这些技术基本通关设计模式篇

一、编程中的六大设计准则?1.繁多职责准则艰深地讲就是一个类只做一件事  CALayer:动画和视图的显示。 UIView:只负责事件传递、事件响应。 2.开闭准则对批改敞开,对扩大凋谢。要思考到后续的扩展性,而不是在原有的根底上来回批改 3.接口隔离准则应用多个专门的协定、而不是一个宏大臃肿的协定  UITableviewDelegate UITableViewDataSource 4.依赖倒置准则形象不应该依赖于具体实现、具体实现能够依赖于形象。调用接口感觉不到外部是如何操作的 5.里氏替换准则父类能够被子类无缝替换,且原有的性能不受任何影响例如 KVO 6.迪米特法令一个对象该当对其余对象尽可能少的理解,实现高聚合、低耦合 二、如何设计一个图片缓存框架?能够模拟SDWebImage来实现。 形成 Manager 内存缓存 磁盘缓存 网络下载 Code Manager 图片解码 图片解压缩 图片的存储是以图片的单向hash值为Key 内存设计须要思考的问题 存储的 Size因为内存的空间无限,咱们针对不同尺寸的图片,给出不同的计划  10K以下的 50个 100Kb以下的 20个 100kb以上的 10个 淘汰的策略 内存的淘汰策略采取LRU(最近起码应用算法) 触发淘汰策略的机会有三种  1.定期检查(不倡议,耗性能) 2.进步查看触发频率(肯定要留神开销)…… 1.前后台切换的时候…… 2.每次读写的时候 磁盘设计须要思考的问题  存储形式 大小限度(有固定的大小) 移除策略(能够设置为 7天或者 15天) 网络设计须要思考的问题  图片申请的最大并发量 申请超时策略 申请优先级 图片解码 利用策略模式,针对jpg、png、gif等不同的图片格式进行解码 图片解码的机会  在子线程图片刚下载完时 在子线程刚从磁盘读取完时 防止在主线程解压缩、解码,防止卡顿 三、如何设计一个时长统计框架?首先作为一个开发者,有一个学习的气氛跟一个交换圈子特地重要,这是一个我的iOS开发公众号:编程大鑫,不论你是小白还是大牛都欢送入驻 ,让咱们一起提高,独特倒退!(群内会收费提供一些群主珍藏的收费学习书籍材料以及整顿好的几百道面试题和答案文档!)记录器  页面式记录器 流式记录器 自定义式 记录管理者 ...

August 16, 2021 · 1 min · jiezi

关于ios:iOS开发面试只需知道这些技术基本通关内存管理篇

一、在  Obj-C中,如何检测内存透露?你晓得哪些形式?目前我晓得的形式有以下几种 · Memory Leaks · Alloctions · Analyse · Debug Memory Graph · MLeaksFinder 泄露的内存次要有以下两种: · Laek  Memory这种是遗记   Release操作所泄露的内存。 · Abandon  Memory这种是循环援用,无奈开释掉的内存。 下面所说的五种形式,其实前四种都比拟麻烦,须要一直地调试运行,第五种是腾讯浏览团队出品,成果好一些 二、在MRC下如何重写属性的Setter和Getter_.mdsetter getter 重写dealloc 三、循环援用循环援用的本质:多个对象相互之间有强援用,不能开释让零碎回收。如何解决循环援用? 1、防止产生循环援用,通常是将strong援用改为weak援用。比方在润饰属性时用weak在block内调用对象办法时,应用其弱援用,这里能够应用两个宏 还能够应用__block来润饰变量在MRC下,__block不会减少其援用计数,防止了循环援用在ARC下,__block润饰对象会被强援用,无奈防止循环援用,须要手动解除。 2、在适合机会去手动断开循环援用。通常咱们应用第一种。 (1)、代理(delegate)循环援用属于互相循环援用 delegate是  iOS中开发中比拟常遇到的循环援用,个别在申明  delegate的时候都要应用弱援用   weak,或者assign,当然怎么抉择应用 assign还是 weak,MRC的话只能用  assign,在 ARC的状况下最好应用  weak,因为weak润饰的变量在开释后主动指向  nil,避免野指针存在 (2)、NSTimer循环援用属于互相循环应用 在控制器内,创立 NSTimer作为其属性,因为定时器创立后也会强援用该控制器对象,那么该对象和定时器就互相循环援用了。 如何解决呢? 这里咱们能够应用手动断开循环援用:如果是不反复定时器,在回调办法里将定时器 invalidate并置为 nil即可。如果是反复定时器,在适合的地位将其 invalidate并置为 nil即可 (3)、block循环援用 一个简略的例子: 因为block会对block中的对象进行持有操作,就相当于持有了其中的对象,而如果此时block中的对象又持有了该block,则会造成循环援用。解决方案就是应用__weak润饰self即可 并不是所有block都会造成循环援用。只有被强援用了的block才会产生循环援用而比方`dispatch_async(dispatch_get_main_queue(),^{}),[UIViewanimateWithDuration:1animations:^{}]`这些零碎办法等或者block并不是其属性而是长期变量,即栈block 还有一种场景,在block执行开始时self对象还未被开释,而执行过程中,self被开释了,因为是用weak润饰的,那么weakSelf也被开释了,此时在block里拜访weakSelf时,就可能会产生谬误(向nil对象发消息并不会解体,但也没任何成果)。 对于这种场景,应该在block中对对象应用__strong润饰,使得在block期间对对象持有,block执行完结后,解除其持有。 四、说一下什么是悬垂指针?什么是野指针?首先作为一个开发者,有一个学习的气氛跟一个交换圈子特地重要,这是一个我的iOS开发公众号:编程大鑫,不论你是小白还是大牛都欢送入驻 ,让咱们一起提高,独特倒退!(群内会收费提供一些群主珍藏的收费学习书籍材料以及整顿好的几百道面试题和答案文档!)悬垂指针指针指向的内存曾经被开释了,然而指针还存在,这就是一个悬垂指针或者说迷途指针 野指针没有进行初始化的指针,其实都是野指针 五、说一下对Strong,Weak,assign,copy,__unsafe_unretain,__autoreleasing关键字的了解Strong Strong修饰符示意指向并持有该对象,其润饰对象的援用计数会加1。该对象只有援用计数不为0就不会被销毁。当然能够通过将变量强制赋值nil来进行销毁。 Weak weak修饰符指向然而并不持有该对象,援用计数也不会加1。在Runtime中对该属性进行了相干操作,无需解决,能够主动销毁。weak用来润饰对象,多用于防止循环援用的中央。weak不能够润饰根本数据类型。 ...

August 14, 2021 · 2 min · jiezi

关于ios:珠江风光带最近算法面试-20200814-怎么写错

1, 最大栈 答案: 随同栈法,还能够给每个元素,增加一个随同属性,记录最大值 我的错误想法:1, 维持最大值,那应用优先队列吧 2, 绝对给每个元素,记录最大值 我打算应用,hash map, 记录每个元素对应的最大值 a, 如果栈外面的元素,都是独特的,简略的 KV 就能够记录,每个元素对应的最大值b, 如果栈外面的元素,能够存在反复的,元素的值,对应一张表 这张表,对应索引值,和最大值 进栈和出栈,都要保护这张表 2, 反转单链表 ( 还没问我,反转双向链表 ) 我感觉的要点: 保留指针援用,批改 node 的 next 指针的指向3, 二分查找 我感觉的疏漏点: left 边界 + 1, right 边界 - 14, 青蛙跳格子 答案: 斐波那契数列我的失误:a1 = 1 a2 = 2 { A, 1 + 1 ;B, 2 } a,第一次失误a3 = a1 * 2 + a2 a2 到 a3, 只有一种办法 a1 到 a2, 有 2 种办法 , 那就 X 2 ...

August 14, 2021 · 1 min · jiezi

关于ios:一篇走心的iOS代码规范

前言对于代码标准的重要性这里不做过多解释,能看到这篇文章阐明你曾经开始器重代码标准了(代码标准看起来是在限度你的自在和施展,其实它是在间接的帮忙你变得更优良。)。  适当的代码标准和规范绝不是毁灭代码内容的创造性、优雅性,而是限度适度个性化,以一种广泛认可的对立形式一起做事,进而进步工作效率,升高沟通老本。代码的字里行间流淌着的是软件和程序员的血液,品质的晋升是尽可能少踩坑、杜绝踩反复的坑,切实晋升零碎稳定性,码出品质 依据束缚力度,临时把标准约定为2个等级,别离是 必须 和 倡议。 (一)命名标准1. 通用命名标准Tips:所有的命名都应该遵循3个根本准则,即“清晰性”、“一致性”、“不要自我指涉”。 [必须] 清晰性:好的命名应该是能自我形容的。 正例: removeObject:、[string stringByReplacingOccurrencesOfString:@"1" withString:@"2"] 反例: remove:(不分明,要删除什么?)、string.replace("1", "2")(是将"1"替换成"2"还是将"2"替换成"1"?是将第1个"1"替换成"2"还是将所有的"1"都替换成"2")[必须] 一致性:命名应该和上下文乃至全局放弃一致性,雷同类型或者具备雷同作用的变量的命名形式应该雷同或相似。 正例:NSDictionary、NSArray、NSSet这几个汇合类都是用count来示意数量而不是一个用count其它的用amount或其余单词,这体现了命名的一致性。@property (readonly) NSUInteger count;[必须] 禁止自我指涉:命名不要自我指涉。告诉、掩码常量等除外(通常指那些能够进行按位运算的枚举值)。 正例:NSString反例:NSStringObject[必须] 杜绝适度缩写,严禁借鉴缩写(例如把button缩写为btn);国内通用缩写名称除外(例如ATM、GPS)。Tips: 你明确这个缩写的意思不代表其他人也肯定会明确,你的代码可能会被任何人浏览,而浏览的人来自不同的中央承受不同的教育不同的文化,所有倡议个别不要乱应用缩写,只应用那些国内通用缩写。如果为了缩写创立一个缩写对照表只会减少代码浏览复杂度。 正例: destinationSelection、setBackgroundColor 反例: destSel、setBgColor[必须] 杜绝无意义的拼音,国内通用名称或者地名人名除外(例如alibaba、taobao、hangzhou)。 反例:DaZhePromotion(打折)[必须] 命名要尽可能的清晰并简洁,如果两者不能兼得,则以清晰为主。 正例:insertObject:atIndex:反例:insert:at:(不清晰,插入什么?at代表什么?)[必须] 代码和正文中都要防止应用任何语言的种族歧视性词语。 正例:secondary反例:slave[必须] 类名、协定名、函数名、常量名、枚举名等一些全局命名须要增加前缀,前缀须要大于2个字符且全副大写。 Tips: 零碎保留任意两个字符作为前缀的使用权,包含但不限于NS、UI、CG、CF、CA、WK、MK、CI、NC;前缀若等于2个字符能够思考增加_。正例:ZT_LoginViewController反例:ZTLoginViewController[必须] 类名、协定名、函数名、常量名、枚举名等一些全局命名遵循首字母大写的驼峰命名形式,首个单词是HTTP这种非凡词除外。[必须] 办法名、属性名等一些非全局命名遵循首字母小写的驼峰命名形式命名,首个单词是HTTP这种非凡词除外。[必须] 成员变量须要以_结尾。 正例:NSString *_nameString;[倡议] 在给常量或变量命名时,尽量将示意类型的名词放在词尾,以晋升辨识度。 正例:nameLabel、nameString反例:name(name是字符串还是什么?)[倡议] 如果模块、接口、类、办法应用了模式,在命名时尽量体现出具体模式。 正例:OrderFactory、LoginProxy[倡议] 部分长期变量命名能够加上标识符作为前缀。 正例:t_label、t_string(t在这里示意temp)2. 类命名标准首先作为一个开发者,有一个学习的气氛跟一个交换圈子特地重要,这是一个我的iOS开发交换群:130 595 548,不论你是小白还是大牛都欢送入驻 ,让咱们一起提高,独特倒退!(群内会收费提供一些群主珍藏的收费学习书籍材料以及整顿好的几百道面试题和答案文档!)[必须] 类名命名格调由"前缀+类的名称+类的类型"3个局部组成,前缀必须大于2个字符且全副大写(如果等于2个字符能够增加_);类的名称遵循首字母大写驼峰式命名,类的名称要能表白出该类的性能;类的类型必须应用全称,严禁应用缩写(例如vc代替viewController,cell代替TableViewCell),命名形式和名称命名一样首字母大写。 正例:WXYZ_LoginViewControler WXYZ_示意前缀,Login示意该类跟登录相干,ViewController示意该类是一个视图控制器而不是View。3. 办法命名标准[必须] 所有办法名称禁止以new开始。[必须] 所有办法名称禁止应用_开始。 Tips: 零碎会应用_结尾命名一些零碎公有办法[必须] 外部公有办法须要减少前缀,前缀须要放弃唯一性(例如p_)。 Tips: 给公有办法加前缀有2个益处: 1. 减少辨识度,进步代码可读性。2. 防止本人的办法无意间笼罩了零碎/框架同名的公有办法。[必须] 如果办法返回接收者的某个属性值,那么请间接应用属性名作为办法名。 ...

August 13, 2021 · 3 min · jiezi

关于ios:iOS开发面试只需知道这些技术基本通关UI篇

一、UIView 与 CALayer繁多职责准则 UIView 为 CALayer 提供内容,以及负责解决触摸等事件,参加响应链 CALayer 负责显示内容 contents 二、事件传递与视图响应链 : 如果事件始终传递到 UIAppliction 还是没解决,那就会疏忽掉 三、图像显示原理1.CPU:输入位图 2.GPU :图层渲染,纹理合成 3.把后果放到帧缓冲区(frame buffer)中 4.再由视频控制器依据 vsync 信号在指定工夫之前去提取帧缓冲区的屏幕显示内容 5.显示到屏幕上 CPU 工作 1.Layout: UI 布局,文本计算 2.Display: 绘制 3.Prepare: 图片解码 4.Commit:提交位图 GPU 渲染管线(OpenGL) 顶点着色,图元拆卸,光栅化,片段着色,片段解决 四、UI 卡顿掉帧起因iOS 设施的硬件时钟会收回 Vsync(垂直同步信号),而后 App 的 CPU 会去计算屏幕要显示的内容,之后将计算好的内容提交到 GPU 去渲染。随后,GPU 将渲染后果提交到帧缓冲区,等到下一个 VSync 到来时将缓冲区的帧显示到屏幕上。也就是说,一帧的显示是由 CPU 和 GPU 独特决定的。 一般来说,页面滑动晦涩是 60fps,也就是 1s 有 60 帧更新,即每隔 16.7ms 就要产生一帧画面,而如果 CPU 和 GPU 加起来的解决工夫超过了 16.7ms,就会造成掉帧甚至卡顿。 五、滑动优化计划CPU: ...

August 12, 2021 · 1 min · jiezi

关于ios:苹果iPhone白屏死机如何修复

你的iPhone或iPad是否忽然白屏死机?试试以下5种修复办法。 iPhone白屏死机的起因iPhone呈现白屏的起因有很多,最常见的起因如下: 电池耗尽:如果你的iPhone没电了,它可能会卡在白屏上。 软件更新失败:当您尝试更新iPhone的iOS零碎,但因为网络不稳固或电池电量有余导致更新失败时,你可能会遇到白屏。 越狱失败:如果你正在尝试越狱iOS设施,但越狱过程因为一些未知起因中断,白屏状况更为常见。 硬件问题:另一个常见的白屏起因是iPhone的某些硬件呈现故障或被损坏,从而导致设施卡在白屏上无奈开机。 无论iPhone白屏死机的起因是什么,请尝试以下步骤来修复它。 办法一、三指导击有时,你的iPhone可能不是白屏死机,只是你不小心关上了屏幕放大性能。如果是这样,你能够尝试放大屏幕从而失常应用设施。 要使放大倍率恢复正常,请将三个手指并拢,而后双击屏幕将设施复原到失常视图。你能够进入设置 > 辅助性能 > 缩放点击敞开放大。 办法二、强制重启iPhone通常,修复任何iPhone问题的最佳办法是重新启动iPhone。如果你的iPhone白屏无奈响应点击,你能够尝试强制重启。 对于iPhone 6及更旧型号:同时按下主页键和电源键,直到看到苹果标记。 对于iPhone 7和7 Plus:同时按下电源按钮和音量升高按钮,当你在屏幕上看到苹果标记时松开按钮。 对于iPhone 8及更新机型:疾速按下并松开音量增大按钮,而后疾速按下并松开音量减小按钮。最初,按住侧边按钮直到屏幕上呈现苹果标记。 办法三、应用主页 + 音量增大 + 电源键如果硬强制重启不起作用,那么还有另一种按钮组合能够帮忙修复iPhone白屏死机问题: 同时按住主页按钮、音量增大按钮和电源(睡眠/唤醒)按钮。 请始终按住直到屏幕敞开。 持续按住这些按钮,直到呈现苹果标记。 当苹果标记呈现时,您能够松开按钮,让iPhone像平常一样启动。 显然,这种办法仅实用带主页按钮的 iPhone 机型。 办法四、尝试恢复模式并从备份中复原如果以上办法都不起作用,您能够尝试将iPhone置于恢复模式。恢复模式将让您重新安装 iOS并将备份数据恢复到设施。 关上iTunes并通过USB数据线将你的iPhone连贯到电脑。 而后,你须要将iPhone置于恢复模式。不同设施的步骤略有不同。(您能够参考强制重启的步骤。) 将iPhone置于恢复模式后,iTunes将检测您的iPhone处于恢复模式。你能够单击复原按钮将iPhone复原到出厂设置。 办法五、应用三方工具修复iPhone 白屏死机问题如果恢复模式也不起作用,倡议你试试三方工具,例如丰科iOS零碎修复工具。这款软件能够轻松修复各种iOS零碎相干问题,包含iPhone白屏死机、黑屏、不停重启、卡在恢复模式、更新失败、无奈开机等等。它的操作非常简单,不须要任何专业知识,本人在家就能够修复iPhone白屏死机问题。 以上就是5种修复iPhone白屏死机的办法。如果你尝试了所有办法然而问题依然存在,则可能是硬件问题导致的白屏。对于硬件损坏问题,如果你的设施仍在保修期内,你能够去附件的苹果商店进行收费培修。

August 6, 2021 · 1 min · jiezi

关于ios:iOS开发面试只需知道这些技术基本通关RunLoop篇

1.为什么 NSTimer 有时候不好使?因为创立的 NSTimer默认是被退出到了 defaultMode,所以当 Runloop的 Mode 变 化时,以后的 NSTimer 就不会工作了。 2.AFNetworking 中如何使用 Runloop?RunLoop 启动前外部必须要有至多一个Timer/Observer/Source ,所以AFNetworking 在[runLoop run] 之前先创立了一个新的NSMachPort 增加进去了。 通常状况下,调用者须要持有这个 NSMachPort (mach_port) 并在内部线程通过这个 port 发送音讯到loop 内;但此处增加port 只是为了让RunLoop 不至于退出,并没有用于理论的发送音讯。 当须要这个后盾线程执行工作时, AFNetworking 通过调用 [NSObject performSelector:onThread:..] 将这个工作扔到了后盾线程的 RunLoop 3.autoreleasePool在何时被开释?App 启动后,苹果在主线程RunLoop 里注册了两个Observer 其回调都是 _wrapRunLoopWithAutoreleasePoolHandler() 。 第一个 Observer监督的事件是 Entry (行将进入 Loop ),其回调内会调用 _objc_autoreleasePoolPush() 创立主动开释池。其order 是-2147483647 ,优先 级最高,保障创立开释池产生在其余所有回调之前。 第二个 Observer监督了两个事件: BeforeWaiting (筹备进入休眠) 时调用 objc_autoreleasePoolPop() 和objc_autoreleasePoolPush() 开释旧的池并创立新池; Exit (行将退出 Loop )时调用 _objc_autoreleasePoolPop() 来开释主动开释 池。这个 Observer的 order是 2147483647 ,优先级最低,保障其开释池子产生在其余所有回调之后。 在主线程执行的代码,通常是写在诸如事件回调、 Timer 回调内的。这些回调会被 RunLoop 创立好的AutoreleasePool 环绕着,所以不会呈现内存透露,开发者也不用显示创立 Pool 了。 4.PerformSelector:afterDelay:这个办法在子线程中是否起作用?为什么?怎么解决?不起作用,子线程默认没有 Runloop,也就没有 Timer 。 解决的方法是能够应用 GCD来实现: Dispatch_after ...

August 5, 2021 · 2 min · jiezi

关于ios:iOS底层学习KVC

1.KVC协定定义键值编码是由NSKeyValueCoding非正式协定启用的一种机制,对象采纳该机制来提供对其属性的间接拜访。当对象合乎键值编码时,其属性可通过字符串参数通过简洁、对立的消息传递接口进行寻址。这种间接拜访机制补充了实例变量及其相干拜访器办法提供的间接拜访。 本文收录:掘金【gufs镜像】《iOS底层学习——KVC》 KVC在Objective-C中的定义 KVC的定义都是对NSObject的扩大来实现的(Objective-C中有个显式的NSKeyValueCoding类别名-分类)。查看setValueForKey办法,发现其在Foundation外面,而Foundation框架是不开源的,只能在苹果官网文档查找。见下图: 2.KVC提供的API办法咱们能够学习解读苹果的官网文档,对KVC有更深的了解。 Key-Value Coding Programming Guide 苹果对一些容器类比方NSArray或者NSSet等,KVC有着非凡的实现。 罕用办法 对于所有继承了NSObject的类型,也就是简直所有的Objective-C对象都能应用KVC,上面是KVC最为重要的四个办法: - (nullable id)valueForKey:(NSString *)key;                          // 间接通过Key来取值 - (void)setValue:(nullable id)value forKey:(NSString *)key;          // 通过Key来设值 - (nullable id)valueForKeyPath:(NSString *)keyPath;                  // 通过KeyPath来取值 - (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;  // 通过KeyPath来设值非凡办法 当然NSKeyValueCoding类别中还有其余的一些办法,这些办法在碰到非凡状况或者有非凡需要还是会用到的。 // 默认返回YES,示意如果没有找到Set办法的话,会依照_key,_iskey,key,iskey的顺序搜索成员,设置成NO就不这样搜寻+ (BOOL)accessInstanceVariablesDirectly;// KVC提供属性值正确性验证的API,它能够用来查看set的值是否正确、为不正确的值做一个替换值或者回绝设置新值并返回谬误起因。- (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;// 这是汇合操作的API,外面还有一系列这样的API,如果属性是一个NSMutableArray,那么能够用这个办法来返回。- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;// 如果Key不存在,且没有KVC无奈搜寻到任何和Key无关的字段或者属性,则会调用这个办法,默认是抛出异样。- (nullable id)valueForUndefinedKey:(NSString *)key;// 和上一个办法一样,但这个办法是设值。- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;// 如果你在SetValue办法时面给Value传nil,则会调用这个办法- (void)setNilValueForKey:(NSString *)key;// 输出一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典。- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys; 构造体解决 KVC在进行构造体解决时,须要用到NSValue,设值时,将构造体封装成NSValue,进行键值设值;取值同样返回NSValue,而后依照构造体格式进行解析,见上面代码: // 构造体 ThreeFloats floats = {1.,2.,3.}; // 封装成NSValue NSValue *value     = [NSValue valueWithBytes:&floats objCType:@encode(ThreeFloats)]; // 设值 [person setValue:value forKey:@"threeFloats"]; // 取值 NSValue *value1    = [person valueForKey:@"threeFloats"]; // 构造体解析 ThreeFloats th; [value1 getValue:&th]; NSLog(@"%f-%f-%f",th.x,th.y,th.z);字典解决(模型转换) ...

August 4, 2021 · 6 min · jiezi

关于ios:iOS-15-Beta-4-更新有哪些新功能

iOS 15又迎来了一次更新,当初随着iOS 15的更新,离iOS15正式版也越来越近,苹果官网在此次的更新阐明中,列出了 beta 4 的一些已知问题,以及修复了哪些问题。那么此次更新有哪些值得关注的内容呢? Safari 更加棘手便捷相比于 iPadOS 上的 Safari,iOS 上的 Safari 在前两个 Beta 版本中更加难用,好在 Apple 在 Beta 4 上略微扳回了一局。 最重要的一点,Apple 终于在 iOS 的 Safari 上也将「从新载入」按钮加了回来,再也不必下拉整个网页或者去二级菜单找这个高频应用的按钮了。另外,共享按钮也间接放到了导航栏上,不再须要去二级菜单里关上。 在滑动网页的一刻,导航栏就会主动放大到底部。而在 iOS 15 Beta 4 中,咱们点击网页上的任意地位,导航栏也会主动放大到底部,再次点击任意地位,导航栏又会恢复原状。 其它值得关注的更新当初能够间接在联系人查看界面抉择不与通讯录联系人共享专一状态,在联系人界面敞开这个选项后,对方就无奈看到我的实时专一状态。新增 iPhone 12 系列对 MagSafe 外接电池的反对快捷指令 App 新增了一个「Return to Home Screen」动作,能够实现主动跳转到主屏幕的成果。桌面小组件在编辑叠放的状况下,「智能轮换」按钮更换了新的图标。设置中的告诉选项更换了新的图标,同时新增了屏幕共享时容许告诉的开关。天气 App 中的星期几从新改回了周几,修复了之前显示不全的 UI 谬误。

August 2, 2021 · 1 min · jiezi

关于ios:iOS面试题攻略分析

以下是回顾之前上、中、下三篇底层面试题的补充,附上答案。 俗话说得好,底层不牢,地动山摇。 这些答案只是给大家一些参考,大家能够再联合本人了解进行答复,有须要的敌人们上面来一起看看吧。 本文收录:公众号【iOS进阶宝典《iOS底层面试干货分享(补充)》】 iOS开发中的加密形式iOS加密相干算法框架:CommonCrypto。 1:对称加密: DES、3DES、AES 加密和解密应用同一个密钥。加密解密过程:明文->密钥加密->密文,密文->密钥解密->明文。长处:算法公开、计算量少、加密速度快、加密效率高、适宜大批量数据加密;毛病:单方应用雷同的密钥,密钥传输的过程不平安,易被破解,因而为了窃密其密钥须要常常更换。AES:AES又称高级加密规范,是下一代的加密算法规范,反对128、192、256位密钥的加密,加密和解密的密钥都是同一个。iOS个别应用ECB模式,16字节128位密钥。 AES算法次要包含三个方面:轮变动、圈数和密钥扩大。 长处:高性能、高效率、灵便易用、安全级别高。毛病:加密与解密的密钥雷同,所以前后端利用AES进行加密的话,如何平安保留密钥就成了一个问题。DES:数据加密规范,DES算法的入口参数有三个:Key、Data、Mode。 其中Key为7个字节共56位,是DES算法的工作密钥;Data为8个字节64位,是要被加密或被解密的数据;Mode为DES的工作形式,有两种:加密、解密。毛病:与AES相比,安全性较低。3DES:3DES是DES加密算法的一种模式,它应用3条64位的密钥对数据进行三次加密。是DES向AES过渡的加密算法,是DES的一个更平安的变形。它以DES为根本模块,通过组合分组办法设计出分组加密算法。 2.非对称加密:RSA加密 非对称加密算法须要成对呈现的两个密钥,公开密钥(publickey) 和公有密钥(privatekey) 。加密解密过程:对于一个私钥,有且只有一个与之对应的公钥。生成者负责生成私钥和公钥,并保留私钥,公开公钥。公钥加密,私钥解密;或者私钥数字签名,公钥验证。公钥和私钥是成对的,它们相互解密。 特点: 1).对信息窃密,避免中间人攻打:将明文通过接管人的公钥加密,传输给接管人,因为只有接管人领有对应的私钥,他人不可能领有或者不可能通过公钥推算出私钥,所以传输过程中无奈被中间人截获。只有领有私钥的接管人才能浏览。此办法通常用于替换对称密钥。 2). 身份验证和避免篡改:权限狗用本人的私钥加密一段受权明文,并将受权明文和加密后的密文,以及公钥一并发送进去,接管方只须要通过公钥将密文解密后与受权明文比照是否统一,就能够判断明文在中途是否被篡改过。此办法用于数字签名。 长处:加密强度小,加密工夫长,罕用于数字签名和加密密钥、安全性十分高、解决了对称加密保留密钥的平安问题。毛病:加密解密速度远慢于对称加密,不适宜大批量数据加密。3. 哈希算法加密:MD5加密、.SHA加密、HMAC加密 哈希算法加密是通过哈希算法对数据加密,加密后的后果不可逆,即加密后不能再解密。特点:不可逆、算法公开、雷同数据加密后果统一。作用:信息摘要,信息“指纹”,用来做数据辨认的。如:用户明码加密、文件校验、数字签名、鉴权协定。MD5加密:对不同的数据加密的后果都是定长的32位字符。 .SHA加密:平安哈希算法,次要实用于数字签名规范(DSS)外面定义的数字签名算法(DSA)。对于长度小于2^64位的音讯,SHA1会产生一个160位的音讯摘要。当接管到音讯的时候,这个音讯摘要能够用来验证数据的完整性。在传输的过程中,数据很可能会发生变化,那么这时候就会产生不同的音讯摘要。当然除了SHA1还有SHA256以及SHA512等。 HMAC加密:给定一个密钥,对明文加密,做两次“散列”,失去的后果还是32位字符串。 4. Base64加密 一种编码方式,严格意义上来说不算加密算法。其作用就是将二进制数据编码成文本,不便网络传输。用 base64 编码之后,数据长度会变大,减少了大概 1/3,然而益处是编码后的数据能够间接在邮件和网页中显示;尽管 base64 能够作为加密,然而 base64 可能逆运算,十分不平安!base64 编码有个十分显著的特点,开端有个 ‘=’ 号。原理:1). 将所有字符转化为ASCII码;2). 将ASCII码转化为8位二进制;3). 将二进制三位一组有余补0,共24位,再拆分成6位一组共四组;4). 对立在6位二进制前补两个0到八位;5). 将补0后的二进制转为十进制;6). 最初从Base64编码表获取十进制对应的Base64编码。App平安,数字签名,App签名,重签名因为利用实际上是一个加壳的ipa文件,然而有可能被砸壳甚至越狱手机下载的ipa包间接就是脱壳的,能够间接反编译,所以不要在plist文件、我的项目中的动态文件中存储要害的信息。所以敏感信息对称加密存储或者就存储到keychain里。而且加密密钥也要定期更换。 数字签名是通过HASH算法和RSA加密来实现的。 咱们将明文数据加上通过RSA加密的数据HASH值 一起传输给对方,对方能够解密拿出HASH值来进行验证。这个通过RSA加密HASH值数据,咱们称之为数字签名。 App签名 1.在Mac开发机器上生成一对公钥和私钥,这里称为公钥L,私钥L(L:Local)。2.苹果本人有固定的一对公钥和私钥,私钥在苹果后盾,公钥在每个iOS设施上。这里称为公钥A,私钥A(A:Apple)。3.把开发机器上的公钥L传到苹果后盾,用苹果后盾的私钥A去签名公钥L。失去一个蕴含公钥L以及其签名数据证书。4.在苹果后盾申请AppID,配置好设施ID列表和APP可应用的权限,再加上第③步的证书,组成的数据用私钥A签名,把数据和签名一起组成一个Provisioning Profile形容文件,下载到本地Mac开发机器。5.在开发时,编译完一个APP后,用本地的私钥L对这个APP进行签名,同时把第④步失去的Provisioning Profile形容文件打包进APP里,文件名为embedded.mobileprovision,把 APP装置到手机上。6.在装置时,iOS零碎获得证书,通过零碎内置的公钥A,去验证embedded.mobileprovision的数字签名是否正确,外面的证书签名也会再验一遍。7.确保了embedded.mobileprovision里的数据都是苹果受权的当前,就能够取出外面的数据,做各种验证,包含用公钥 L 验证APP签名,验证设施 ID 是否在 ID 列表上,AppID 是否对应得上,权限开关是否跟 APP 里的 Entitlements 对应等。OC数据类型 ① 根本数据类型 C语言根本数据类型(如short、int、float等)在OC中都不是对象,只是肯定字节的内存空间用于存储数值,他们都不具备对象的个性,没有属性办法能够被调用。OC中的根本数据类型:NSInteger(相当于long型整数)、NSUInteger(相当于unsigned long型整数)、CGFloat(在64位零碎相当于double,32位零碎相当于float)等。他们并不是类,只是用typedef对根本数据类型进行了重定义,他们仍然只是根本数据类型。枚举类型:其本质是无符号整数。BOOL类型:是宏定义,OC底层是应用signed char来代表BOOL。② 指针数据类型 指针数据类型包含: 类class、id。 ...

July 31, 2021 · 1 min · jiezi

关于ios:面试了12名开发者后总结了62道-iOS面试题建议收藏收藏再收藏

前言:每年三四月份都是招聘高峰期,也就是咱们说的金三银四,很多想换工作的职场人士都会抉择在此时换一份工作,毕竟一年之计在于春,对于公司和集体而言都是一个新的开始。 往年受疫情的影响,各行各业都举步维艰,然而做为iOS面试官的我也在精心筹备的为公司招进优良的iOS开发,期间收到了很多简历,也口试了不少开发者,上一周咱们曾经发了3个offer,所以先发制人,咱们曾经招满了人的职位,仍旧陆陆续续也还有很多的简历投向咱们。后面一段时间给公司面试了10个iOS开发,本人总结了62道面试题,在此,我分享给大家,心愿大家在之后要找工作的敌人,我的这篇文章能给你有所帮忙。 本文分为两大部分:(1-12题为详解题)(13-62为待解题)一、如何绘制UIView?绘制一个UIView最灵便的办法就是由它本人实现绘制。实际上你不是绘制一个UIView,而是子类化一个UIView并赋予绘制本人的能力。 当一个UIView须要执行绘制操作时,drawRect:办法就会被调用,笼罩此办法让你取得绘图操作的机会。当drawRect办法被调用,以后图形的上下文也被设置为属于视图的图形上下文,你能够应用Core Graphic或者UIKit提供的办法将图形画在该上下文中。 二、什么是MVVM?次要目标是什么?长处有哪些?MVVM即 Model-View-ViewModel 1.View次要用于界面出现,与用户输出设施进行交互、 2.ViewModel是MVVM架构中最重要的局部,ViewModel中蕴含属性,办法,事件,属性验证等逻辑,负责View与Model之间的通信 3.Model就是咱们常说的数据模型,用于数据的结构,数据的驱动,次要提供根底实体的属性。MVVM次要目标是拆散视图和模型 MVVM长处:低耦合,可重用性,独立开发,可测试 三、get申请与post申请的区别1.get是向服务器发索取数据的一种申请,而post是向服务器提交数据的一种申请 2.get没有申请体,post有申请体 3.get申请的数据会裸露在地址栏中,而post申请不会,所以post申请的安全性比get申请号 4.get申请对url长度有限度,而post申请对url长度实践上是不会收限度的,然而实际上各个服务器会规定对post提交数据大小进行限度。 四、谈谈你对多线程开发的了解?ios中有几种实现多线程的办法?益处:1.应用多线程能够把程序中占据工夫长的工作放到后盾去解决,如图片,视频的下载; 2.施展多核处理器的劣势,并发执行让零碎运行的更快,更晦涩,用户体验更好; 毛病:1.大量的线程升高代码的可读性; 2.更多的线程须要更多的内存空间; 3当多个线程对同一个资源呈现抢夺的时候要留神线程平安的问题。 ios有3种多线程编程的技术:1.NSThread,2.NSOperationQueue,3.gcd; 五、XMPP工作原理;xmpp零碎特点原理: 1.所有从一个client到另一个client的jabber音讯和数据都要通过xmpp server 2.client链接到server 3.server利用本地目录零碎的证书对其认证 4.server查找,连贯并进行互相认证 5.client间进行交互 特点:1)客户机/服务器通信模式;2)分布式网络;3)简略的客户端;4)XML的数据格式 答案:因为答案太多,我做了一个PDF文档,因为简书不能上传文件,,因为文章无限,须要这些文档的, 点击 材料收录自取吧 六、地图的定位是怎么实现的?1.导入了CoreLocation.framework 2.ios8当前,如果须要应用定位性能,就须要申请用户受权,在首次运行时会弹框提醒 3.通过本机自带的gps获取地位信息(即经纬度) 七、苹果内购实现流程程序通过bundle存储的plist文件失去产品标识符的列表。 程序向App Store发送申请,失去产品的信息。 App Store返回产品信息。 程序把返回的产品信息显示给用户(App的store界面) 用户抉择某个产品 程序向App Store发送领取申请 App Store解决领取申请并返回交易实现信息。 App获取信息并提供内容给用户。 八、支付宝,微信等相干类型的sdk的集成1.在支付宝开发平台创立利用并获取APPID 2.配置密钥 3.集成并配置SDK 4.调用接口(如交易查问接口,交易退款接口) 九、 gcd产生死锁的起因及解锁的办法产生死锁的必要条件:1.互斥条件,2.申请与放弃条件,3.不剥夺条件,4.循环期待条件。 解决办法:采纳异步执行block。 十、生成二维码的步骤1.应用CIFilter滤镜类生成二维码 2.对生成的二维码进行加工,使其更清晰 3.自定义二维码背景色、填充色 4.自定义定位角标 5.在二维码核心插入小图片 十一、在应用XMPP的时候有没有什么艰难发送附件(图片,语音,文档...)时比拟麻烦 XMPP框架没有提供发送附件的性能,须要本人实现 实现办法,把文件上传到文件服务器,上传胜利后获取文件保留门路,再把附件的门路发送给好友十二、是否应用过环信,简略的说下环信的实现原理环信是一个即时通讯的服务提供商 环信应用的是XMPP协定,它是再XMPP的根底上进行二次开发,对服务器Openfire和客户端进行性能模型的增加和客户端SDK的封装,环信的实质还是应用XMPP,基于Socket的网络通信 环信外部实现了数据缓存,会把聊天记录增加到数据库,把附件(如音频文件,图片文件)下载到本地,使程序员更多工夫是花到用户体验体验上。 待解题根底:1、如何令本人所写的对象具备拷贝性能? 2、说说你了解weak属性? 3、题目:Swift mutating关键字的应用? 4、UIView和CALayer是什么关系? ...

July 30, 2021 · 1 min · jiezi

关于ios:iOS底层面试题下篇

7月,iOS求职跳槽的绝对较少,能在这个时间段求职的,不是被迫,就是对本人的技术很自信;针对7月,特地总结了第三份iOS常见大厂面试题(下); iOS面试题分为 上、中、下三局部,不便大家观看; 请先本人答一答! 话不多说;间接上题本文收录:公众号【iOS进阶宝典《iOS底层面试题(下篇)》】 13. 如何用Charles抓HTTPS的包?其中原理和流程是什么?流程: 首先在手机上安装Charles证书在代理设置中开启Enable SSL Proxying之后增加须要抓取服务端的地址原理: Charles作为中间人,对客户端伪装成服务端,对服务端伪装成客户端。简略来说: 截获客户端的HTTPS申请,伪装成中间人客户端去向服务端发送HTTPS申请承受服务端返回,用本人的证书伪装成中间人服务端向客户端发送数据内容。具体流程如下图:扯一扯HTTPS单向认证、双向认证、抓包原理、反抓包策略 14. 什么是中间人攻打?如何防止?中间人攻打就是截获到客户端的申请以及服务器的响应,比方Charles抓取HTTPS的包就属于中间人攻打。 防止的形式:客户端能够预埋证书在本地,而后进行证书的比拟是否是匹配的 15. 理解编译的过程么?分为哪几个步骤?1:预编译:次要解决以“#”开始的预编译指令。 2:编译: 词法剖析:将字符序列宰割成一系列的记号。语法分析:依据产生的记号进行语法分析生成语法树。语义剖析:剖析语法树的语义,进行类型的匹配、转换、标识等。两头代码生成:源码级优化器将语法树转换成中间代码,而后进行源码级优化,比方把 1+2 优化为 3。中间代码使得编译器被分为前端和后端,不同的平台能够利用不同的编译器后端将中间代码转换为机器代码,实现跨平台。指标代码生成:尔后的过程属于编译器后端,代码生成器将中间代码转换成指标代码(汇编代码),其后指标代码优化器对指标代码进行优化,比方调整寻址形式、应用位移代替乘法、删除多余指令、调整指令程序等。3:汇编:汇编器将汇编代码转变成机器指令。 动态链接:链接器将各个曾经编译成机器指令的指标文件链接起来,通过重定位过后输入一个可执行文件。装载:装载可执行文件、装载其依赖的共享对象。动静链接:动静链接器将可执行文件和共享对象中须要重定位的地位进行修改。最初,过程的控制权转交给程序入口,程序终于运行起来了。 16. 动态链接理解么?动态库和动静库的区别?动态链接是指将多个指标文件合并为一个可执行文件,直观感觉就是将所有指标文件的段合并。须要留神的是可执行文件与指标文件的构造基本一致,不同的是是否“可执行”。 动态库:链接时残缺地拷贝至可执行文件中,被屡次应用就有多份冗余拷贝。动静库:链接时不复制,程序运行时由零碎动静加载到内存,供程序调用,零碎只加载一次,多个程序共用,节俭内存。17. App网络层有哪些优化策略?优化DNS解析和缓存对传输的数据进行压缩,缩小传输的数据应用缓存伎俩缩小申请的发动次数应用策略来缩小申请的发动次数,比方在上一个申请未着地之前,不进行新的申请防止网络抖动,提供重发机制18:[self class] 与 [super class]@implementation Son : Father(id)init { self = [super init]; if (self) { NSLog(@"%@", NSStringFromClass([self class])); NSLog(@"%@", NSStringFromClass([super class])); } return self; } @endself和super的区别: self 是类的一个暗藏参数,每个办法的实现的第一个参数即为self。super并不是暗藏参数,它实际上只是一个”编译器标示符”,它负责通知编译器,当调用办法时,去调用父类的办法,而不是本类中的办法。在调用[super class]的时候,runtime会去调用objc_msgSendSuper办法,而不是objc_msgSend OBJC_EXPORT void objc_msgSendSuper(void /* struct objc_super *super, SEL op, ... */ )/// Specifies the superclass of an instance.struct objc_super {/// Specifies an instance of a class.__unsafe_unretained id receiver;/// Specifies the particular superclass of the instance to message. # if !defined(__cplusplus) && !__OBJC2__/* For compatibility with old objc-runtime.h header */__unsafe_unretained Class class;# else__unsafe_unretained Class super_class;# endif/* super_class is the first class to search */}在objc_msgSendSuper办法中,第一个参数是一个objc_super的构造体,这个构造体外面有两个变量,一个是接管音讯的receiver,一个是以后类的父类super_class。 ...

July 28, 2021 · 6 min · jiezi

关于ios:iOS性能优化RunLoop卡顿检测

卡顿次要体现为主线程卡死,不响应用户动作或者响应很慢,这种体验很差,会让用户对产品的认可度急速下滑,如果不及时优化,最终会导致用户散失。 那么,哪些状况会导致主线程卡顿呢?大体有如下几个方面: 很简单的 UI 、图文混排的绘制量很大;主线程进行网络同步申请;主线程上做大量的 IO 操作;运算量过大,CPU 继续高占用;死锁和奴才线程抢锁。检测计划为了优化卡顿,咱们须要精确的晓得哪里产生了卡顿,而后能力有针对性的进行优化,所以在开始优化之前咱们须要去监控卡顿产生的中央。那么问题来了,怎么监控卡顿? 检测 FPS 变动幅度是一种计划,然而并不举荐,起因我援用[戴铭]()大佬在[如何利用 RunLoop 原理去监控卡顿?]()一文中的形容:”FPS 是一秒显示的帧数,也就是一秒内画面变动数量。如果依照动画片来说,动画片的 FPS 就是 24,是达不到 60 满帧的。也就是说,对于动画片来说,24 帧时尽管没有 60 帧时晦涩,但也曾经是连贯的了,所以并不能说 24 帧时就算是卡住了。“ 另一种举荐的计划就是 RunLoop。为什么Runloop能够做到卡顿监控?咱们晓得程序中的工作都是在线程中执行,而线程依赖于 RunLoop,并且RunLoop总是在相应的状态下执行工作,执行实现当前会切换到下一个状态,如果在一个状态下执行工夫过长导致无奈进入下一个状态就能够认为产生了卡顿,所以能够依据主线程 RunLoop 的状态变化检测工作执行工夫是否太长。至于多长时间算作卡顿能够根据本人的须要来设置,个别状况下能够设置1秒钟作为阀值。 RunLoop 的状态如下: typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) { kCFRunLoopEntry = (1UL << 0), // 进入Runloop kCFRunLoopBeforeTimers = (1UL << 1), // 解决Timer事件 kCFRunLoopBeforeSources = (1UL << 2), // 解决Source事件 kCFRunLoopBeforeWaiting = (1UL << 5), // 进入休眠 kCFRunLoopAfterWaiting = (1UL << 6), // 唤醒 kCFRunLoopExit = (1UL << 7), // 退出Runloop kCFRunLoopAllActivities = 0x0FFFFFFFU // 所有状态};RunLoop 的执行流程: ...

July 28, 2021 · 2 min · jiezi

关于ios:八天让iOS开发者上手Flutter一

flutter当初是越来越火了,当初作为一个iOS开发,如果你不会flutter都如同不算个正常人似的?而且当初的flutter状况,有点像2012年那会儿刚刚衰亡的iOS,Android开发一样,会点皮毛UI就能够晋升不少身价...这些年过去,有有数的前端跨平台框架衰亡。却只有flutter一家独秀,阐明它还是有两把刷子的。明天这篇文章内容是基于Mac和Android Studio根底来开发flutter的,如果你还没有配置好开发环境,能够在网上搜寻,或者间接到官网装置。这篇文章次要用来记录我学习flutter的过程,如果你也对flutter感兴趣能够跟着一起练习。 配置好Flutter环境之后,开始创立咱们的第一个Flutter工程 创立第一个Flutter工程关上iTerm2,cd到~/AndroidStudioProjects目录,输出以下命令,没有iTerms的应用Mac零碎自带的Terminal也行。flutter create flutter_demo这里须要留神,AndroidStudio项目名称不能应用大写字母,这里举荐应用小写字母加下划线给工程命名。 关上对应的目录,能够看到新建了一个flutter_demo目录 接下来,cd到flutter_demo目录,在终端输出flutter run命令,它就会运行我的项目,如果你电脑连贯了真机,就会主动运行到真机上,没有真机会去寻找模拟器并运行,模拟器也没有,就会关上一个Chrome网页运行我的项目(flutter我的项目目前能够运行在iOS,Android,web上)。我这里连上了iPhone真机,运行我的项目会报一个BUILD FAILED的谬误: 起因是flutter_demo我的项目生成的iOS我的项目默认的bundle identifier咱们用不了,去iOS我的项目外面批改一下就好了 这里留神咱们收费的开发者证书,在iPhone上最多装置3个开发中的APP,多了就装置不了,删掉之前的APP就好了,再次运行flutter run 能够看到这里给出了flutter运行的一些要害命令,Hot reload热重载,这个个性对咱们开发UI时还是比原生的体验好不少的,它不必咱们从新运行我的项目就能看到UI的一些扭转。Hot restart热重启,意思不必退出APP,就间接从新运行了。此时真机上就关上了咱们的第一个flutter工程的APP HelloFlutter下面是通过命令创立一个flutter我的项目,当然在理论开发过程我,咱们个别不会这么操作。应用Android Studio来创立flutter我的项目。没有这个选项的同学,在Android Studio的插件外面抉择flutter并装置就有了,如果提醒还须要装置Dart就一块装置了,flutter应用的是Dart语言。iOS开发者没必要被这个新语言给吓到了,古代的语言根本都差不了太多,敲着敲着就相熟了 点击后会呈现以下界面,目前咱们抉择Flutter App就好了 下一个界面会让咱们设置工程名称,工程地位,工程形容,工程组织,Android语言,iOS语言等等...我这里设置工程名称为hello_flutter,其余的默认抉择就好了...也能够依据你本人的须要抉择 点击Finish之后就能够看到残缺的工程目录了,flutter工程的主入口,跟咱们iOS我的项目一样有一个main.m文件,flutter的是main.dart文件,能够看到这个文件外面曾经有不少初始的代码了,明天是咱们第一次接触flutter我的项目,就不要这里的代码,全副删掉,咱们从第一行代码开始本人敲进去 导入material.dart头文件(相当于iOS中UIKit)写一个main()函数作为主入口调用runAPP()函数Center类是用来布局的类,示意一个地位,child属性示意他有的子控件的意思。Text类就是咱们文本类,有点儿咱们iOS的UILabel的意思,Text类的第一个参数就是具体的文本,省略了参数名,第二个参数textDirection示意文本显示方向,咱们习惯的从左至右就是TextDirection.ltr,left to right。像一些阿拉伯语言,希伯来语的文字就是从右到左显示的,我这里试了一下hello world的方向并没有变动,可能还须要其余设置吧...首先作为一个开发者,有一个学习的气氛跟一个交换圈子特地重要,这是一个我的iOS开发公众号:编程大鑫,不论你是小白还是大牛都欢送入驻 ,让咱们一起提高,独特倒退!(群内会收费提供一些群主珍藏的收费学习书籍材料以及整顿好的几百道面试题和答案文档!)运行之后iPhone显示如下: 自定义Widgetflutter外面的Widget类叫作小部件,是flutter外面常常用到的,它分为有状态的Stateful和Stateless无状态的。其中无状态的比较简单,咱们先自定义一个类CustomWidget继承自StatelessWidget。咱们自定义的Widget想要显示到屏幕上须要实现一个build的函数,零碎会调用这个函数来渲染咱们想要显示到屏幕上的内容 这个时候,如何将咱们的hello flutter显示到屏幕呢,能够看到runApp函数外面有一个Center类,咱们CustomWidget类的build办法也是返回的一个Center类,所以能够间接将咱们CustomWidget初始化给runApp作参数 有些时候,咱们发现hot reload无奈更新界面,能够应用hot restart,如果hot restart还是无奈更新界面,那就须要从新运行一下就能够了。此时咱们发现main()函数外面就只有一句调用runApp()代码,在Dart语言中,函数定义如果只有一句代码,那么能够省略成如下箭头模式 设置文字款式style按住command再用鼠标左键点击Text类,就会跳到一个text.dart文件,会看到一个this.style属性,再次按住command点击,会来到style的申明局部: 这里的final示意不可变,常量的意思,相似于Swift外面的let。能够看到style是一个TextStyle类型,查看TextStyle类,会发现外面很多的属性,比方color,backgroundColor,fontSize,fontWeight...这些都是很相熟的属性,接下来咱们设置一下hello flutter的一些文字款式 应用Android Studio快捷键command + \查看界面 Material App在flutter提供的头文件material.dart中,提供了一个疾速构建APP的类型MaterialApp,咱们能够应用它来疾速构建一个APP的根底框架。咱们先新建一个App类来写咱们的代码 而后咱们在App的build办法中,返回一个MaterialApp类,如果MaterialApp不传入任何参数的话,运行后会发现APP整个屏幕变成红色,并且显示了一行文字,意思是出错了之类的,阐明咱们的MaterialApp应该是须要传入一个必要的参数的。 没错就像咱们iOS的APP同样须要一个rootViewController一样,MaterialApp函数须要一个home参数,home参数能够传一个Widget类,如果传入咱们刚刚写的CustomWidget类,运行后发现有了一点不一样的中央 右上角有一个debug的图标,hello flutter上面也呈现了两条横线。 flutter还提供了一个Scaffold的类,这个类翻译过去叫作脚手架,有点像是咱们iOS中的一些根底控制器(比方UITabBarController,UINavigationController)的封装。咱们来应用一下这个类,这个Scaffold类有一个appBar的属性,这个属性就跟咱们的UINavigationController的UINavigationBar一样,appBar是一个AppBar类型,它的title属性能够传入一个Widget,咱们传入一个Text类试试看。Scaffold类除了appBar属性,还有一个body属性示意的内容,把这个body设置为咱们刚刚的CustomWidget,看看是什么成果,代码如下: APP上显示成果: 这个时候,是不是发现像那么回事了 MaterialApp还有一个theme的属性,这个属性用了配置app的主题,设置一下主题颜色代码如下: APP上显示成果: 初探ListView在摸索ListView之前,咱们先把模型实现一下,咱们这里展现的一组对于汽车的图片和名字,就定义一个Car类,咱们新建一个car文件用来寄存咱们的模型代码,代码如下: 再定义一个数组,用来寄存一组汽车模型,我这里放了一组网络图片,你能够间接应用,也能够本人在网上找几张图片,填入模型数组中 final List<Car> cars = [ Car( name: '保时捷918 Spyder', imageUrl: 'https://upload-images.jianshu.io/upload_images/2990730-7d8be6ebc4c7c95b.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240', ), Car( name: '兰博基尼Aventador', imageUrl: 'https://upload-images.jianshu.io/upload_images/2990730-e3bfd824f30afaac?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240', ), Car( name: '法拉利Enzo', imageUrl: 'https://upload-images.jianshu.io/upload_images/2990730-a1d64cf5da2d9d99?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240', ), Car( name: 'Zenvo ST1', imageUrl: 'https://upload-images.jianshu.io/upload_images/2990730-bf883b46690f93ce?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240', ), Car( name: '迈凯伦F1', imageUrl: 'https://upload-images.jianshu.io/upload_images/2990730-5a7b5550a19b8342?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240', ), Car( name: '萨林S7', imageUrl: 'https://upload-images.jianshu.io/upload_images/2990730-2e128d18144ad5b8?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240', ), Car( name: '科尼赛克CCR', imageUrl: 'https://upload-images.jianshu.io/upload_images/2990730-01ced8f6f95219ec?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240', ), Car( name: '布加迪Chiron', imageUrl: 'https://upload-images.jianshu.io/upload_images/2990730-7fc8359eb61adac0?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240', ), Car( name: '轩尼诗Venom GT', imageUrl: 'https://upload-images.jianshu.io/upload_images/2990730-d332bf510d61bbc2.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240', ), Car( name: '西贝尔Tuatara', imageUrl: 'https://upload-images.jianshu.io/upload_images/2990730-3dd9a70b25ae6bc9?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240', )];而后回到main.dart文件新建一个Home类,用来寄存咱们ListView相干代码,和Xcode一样Android Studio同样有代码块性能,间接输出stl就会呈现提醒,回车就会生成StatelessWidget类相干代码。咱们将Scaffold相干的代码挪到Home中来。 ...

July 26, 2021 · 1 min · jiezi

关于ios:iOS底层面试题上篇

7月,iOS求职跳槽的绝对较少,能在这个时间段求职的,不是被迫,就是对本人的技术很自信;针对7月,特地总结了一份iOS常见大厂面试题(上); iOS面试题分为 上、中、下三局部,不便大家观看; 请先本人答一答! 话不多说;间接上题本文收录:公众号【iOS进阶宝典《iOS底层面试题(上篇)》】 1:谈谈你对KVC的了解KVC能够通过key间接拜访对象的属性,或者给对象的属性赋值,这样能够在运行时动静的拜访或批改对象的属性 2:iOS我的项目中援用多个第三方库引发抵触的解决办法可能有很多小伙伴还不太分明,动动态库的开发,这里举荐一篇博客:iOS-制作.a动态库SDK和应用.a动态库 如果咱们存在三方库抵触就会保留:duplicate symbol _OBJC_IVAR_$_xxxx in: 目前奏效最快的就是把**.framework**选中,**taggert Membership**的对勾勾销掉,就编译没有问题了,然而后续的其余问题可能还会呈现 我想说的是像这种开源的使用率很高的源代码本不应该蕴含在lib库中,就算是你要蕴含那也要改个名字是吧。不过没方法当初人家既然蕴含,咱们就只有想方法拆散了 mkdir armv7:创立长期文件夹lipo libALMovie.a -thin armv7 -output armv7/armv7.a:取出armv7平台的包ar -t armv7/armv7.a:查看库中所蕴含的文件列表cd armv7 && ar xv armv7.a:解压出object file(即.o后缀文件)rm ALButton.o:找到抵触的包,删除掉(此步能够屡次操作)cd … && ar rcs armv7.a armv7/*.o:从新打包object file多平台的SDK的话,须要屡次操作第4步。操作实现后,合并多个平台的文件为一个.a文件:lipo -create armv7.a arm64.a -output new.a将批改好的文件, 拖拽到原文件夹下,替换原文件即可。3:GCD实现多读单写比方在内存中保护一份数据,有多处中央可能会同时操作这块数据,怎么能保障数据安全?这道题目总结失去要满足以下三点: 1.读写互斥2.写写互斥3.读读并发@implementation KCPerson- (instancetype)init{ if (self = [super init]) { _concurrentQueue = dispatch_queue_create("com.kc_person.syncQueue", DISPATCH_QUEUE_CONCURRENT); _dic = [NSMutableDictionary dictionary]; } return self;}- (void)kc_setSafeObject:(id)object forKey:(NSString *)key{ key = [key copy]; dispatch_barrier_async(_concurrentQueue, ^{ [_dic setObject:object key:key]; });}- (id)kc_safeObjectForKey::(NSString *)key{ __block NSString *temp; dispatch_sync(_concurrentQueue, ^{ temp =[_dic objectForKey:key]; }); return temp;}@end首先咱们要维系一个GCD 队列,最好不必全局队列,毕竟大家都晓得全局队列遇到栅栏函数是有坑点的,这里就不剖析了!因为思考性能 死锁 梗塞的因素不思考串行队列,用的是自定义的并发队列!_concurrentQueue = dispatch_queue_create("com.kc_person.syncQueue", DISPATCH_QUEUE_CONCURRENT);首先咱们来看看读操作:kc_safeObjectForKey咱们思考到多线程影响是不能用异步函数的!阐明:线程2 获取:name 线程3 获取 age如果因为异步并发,导致凌乱 原本读的是name 后果读到了age咱们容许多个工作同时进去! 然而读操作须要同步返回,所以咱们抉择:同步函数 (读读并发)咱们再来看看写操作,在写操作的时候对key进行了copy, 对于此处的解释,插入一段来自参考文献的援用:函数调用者能够自在传递一个NSMutableString的key,并且可能在函数返回后批改它。因而咱们必须对传入的字符串应用copy操作以确保函数可能正确地工作。如果传入的字符串不是可变的(也就是失常的NSString类型),调用copy基本上是个空操作。这里咱们抉择dispatch_barrier_async, 为什么是栅栏函数而不是异步函数或者同步函数,上面剖析:栅栏函数工作:之前所有的工作执行结束,并且在它前面的工作开始之前,期间不会有其余的工作执行,这样比拟好的促使 写操作一个接一个写 (写写互斥),不会乱!为什么不是异步函数?应该很容易剖析,毕竟会产生凌乱!为什么不必同步函数?如果读写都操作了,那么用同步函数,就有可能存在:我写须要期待读操作回来能力执行,显然这里是不合理!4:讲一下atomic的实现机制;为什么不能保障相对的线程平安(最好能够联合场景来说)?A: atomic的实现机制 ...

July 26, 2021 · 1 min · jiezi

关于ios:带你手把手撸一个网易云音乐首页下篇

前言Hello, 大家好,明天筹备和大家持续分享如何利用 Swift 来实现一个网易云音乐的首页;上篇文章公布当前,我播种了不少小伙伴的关注与点赞,同时也失去了一些十分有用的倡议,在这里再次感激大家的认可, 你们的激励与倡议是我技术输入路上最大的能源。 MVVM好了,回到正题,在我的项目中咱们应用了 MVVM 模式,在上一篇文章中,咱们讲完了 Model 和 ViewModel, 那接下来就开始讲 View 吧!如果有小伙伴是从这篇文章进入的,无妨先从我的上一篇文章看起,这样看下来能力保障你思路的连贯性。 View回到咱们的我的项目工程中来,筹备构建咱们的表视图。 首先,在咱们的首页视图控制器 DiscoveryViewController 中创立存储属性 HomeViewModel 并初始化它。在咱们理论开发过程中,数据申请的操作必不可少,必须要先将数据提供给 ViewModel,而后在数据更新时从新 Reload TableView。 // 首页发现 viewModel fileprivate var homeViewModel = HomeViewModel()接下来,咱们来配置 tableViewDataSource: // Mark UITableViewDataSource override func numberOfSections(in tableView: UITableView) -> Int { if homeViewModel.sections.isEmpty { return 0 } return homeViewModel.sections.count } override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{ return homeViewModel.sections[section].rowCount }当初咱们就能够开始构建 UI 了。依据网易云音乐的款式,咱们须要创立 12 种不同类型的 Cell, 每种 Cell 对应一种 ViewModelItems。 ...

July 22, 2021 · 8 min · jiezi

关于ios:带你手把手撸一个网易云音乐首页上篇

前言Hello,大家好,近期我始终在学习用 Swift 编码,因为之前很多我的项目我都是用 OC 实现的,所以导致我当初对 Swift 还是处于一个学习的阶段中。为了进步本人的学习效率,每次我都会为本人定下一个短期的指标,就那这次来说吧,为了放慢本人上手 Swift, 我为本人定下了的指标就是实现一个 Swift 版本的网易云音乐 App。不晓得大家在学习一门新语言的时候,是如何进步学习效率的?无妨在评论区与大家交换一下。 调研剖析先剖析一下 iOS 端网易云音乐 App 的首页,如图所示: 看完后,首先摆在我眼前的第一个艰难就是我该如何去获取这些数据!我的第一个想法当然就是去 GitHub 上找有没有开源的 API,不找不晓得,一找果然很称心,原来早就有大佬提供了网易云音乐的 API: 其中就有“首页发现” 和 “首页-发现-圆形图标入口列表” 的 API, 无需咱们进行多个接口的调用以及数据源的拼接,就可一获取首页的全副数据啦!在剖析返回的 JSON 数据格式的时候,还给大佬提了个issue,大佬也很快的回复了,再次膜拜一下大佬。 { "code": 200, "data": { "cursor": null, "blocks": [ { "blockCode": "HOMEPAGE_BANNER", "showType": "BANNER", "extInfo": { "banners": [ { "adLocation": null, "monitorImpress": null, "bannerId": "1622653251261138", "extMonitor": null, "pid": null, "pic": "http://p1.music.126.net/gWmqDS3Os7FWFkJ3s8Wotw==/109951166052270907.jpg", "program": null, "video": null, "adurlV2": null, "adDispatchJson": null, "dynamicVideoData": null, "monitorType": null, "adid": null, "titleColor": "red", "requestId": "", "exclusive": false, "scm": "1.music-homepage.homepage_banner_force.banner.2941964.-1777659412.null", "event": null, "alg": null, "song": { ......}数据源的问题解决了,接下来就是该解决如何将数据可视化了,从网易云音乐首页展现的成果剖析来看,整体的视图反对高低滚动,其中单个 Cell 的视图反对横向滚动,所以这里采纳 UITableView 嵌套 UICollectionView 的形式应该来说再适合不过了。 ...

July 21, 2021 · 12 min · jiezi

关于ios:Swift-55-新特性

Swift 5.5 内置于 Xcode 13,尽管版本号只减少了 0.1,看似是一个小版本升级,但却带来了十分多的新内容,其中最大的更新是引入了全新的并发编程形式。 本文收录:http://www.cocoachina.com/art... 条件编译反对表达式SwiftUI 在跨平台时会应用到条件 Modifier,之前的解决方案是本人写一套判断体系, Swift 5.5 当前,原生反对条件编译表达式,跨平台更加不便。 struct ContentView: View { var body: some View { Text("SwiftUI") #if os(iOS) .foregroundColor(.blue) #elseif os(macOS) .foregroundColor(.green) #else .foregroundColor(.pink) #endif }}CGFloat与Double反对隐式转换let number1: CGFloat = 12.34let number2: Double = 56.78let result = number1 + number2 // result为Double类型复制代码上面的代码在 Swift 5.5 之前会报错,因为scale为 Double 类型,而 SwiftUI 中须要绑定 CGFloat 类型。 struct ContentView: View { @State private var scale = 1.0 // Double类型 var body: some View { VStack { Image(systemName: "heart") .scaleEffect(scale) // 隐式转换为CGFloat Slider(value: $scale, in: 0 ... 1) } }}泛型上下文中反对动态成员查找(static member lookup)这个新个性使得 SwiftUI 中的局部语法更加简洁好用。 ...

July 21, 2021 · 2 min · jiezi

关于ios:论证iOS安全性为什么需要审核

一、前言最近,Epic Games vs Apple 的诉讼大战十分的强烈精彩,报料的内幕消息也非常劲爆!满足了一波炎炎夏日的吃瓜大众,当然作为技术人员,咱们除了关注瓜甜不甜,还要剖析这瓜为什么甜?Epic Games 邀请了一位专家证人,针对“iOS安全性”这个问题进行开展答辩,即:苹果能够让 iOS 零碎,在利用散发和第三方拜访等方面更像 macOS,也不会在安全性方面受到影响。 二、注释2.1 答辩者针对这个辩题:“iOS 本能够和 macOS 一样凋谢,不安受全性影响”(iOS could be like macOS without security drawbacks),咱们先来看看答辩者,Epic Games 的专家证人,哈佛学大计算机科学传授 James Mickens,这是何许人也? 大家对 James Mickens 传授可能不太理解,没有关系!咱们能够通过维基百科 一起来看看:James W. Mickens 是美国计算机科学家,是哈佛大学约翰·A·保尔森工程与应用科学学院的 Gordon McKay 计算机科学传授。他的钻研重点是分布式系统,例如大规模服务以及使它们更平安的办法。他对将机器学习作为解决最突出的计算问题的样板解决方案持批评态度。另外,八卦一下,“Gordon McKay” 这个头衔:戈登·麦凯(Gordon McKay)是一位富裕的商人,他向哈佛捐献了一大笔钱,这笔钱被存入了一个信托基金。该基金的资金用于领取哈佛的40个不同的传授职位。领有戈登·麦凯授予的椅子的人——即受雇于哈佛大学传授的人,其职位由戈登·麦凯设立的信托基金赞助——将领有“戈登·麦凯传授”的头衔。援用起源:What is a 'Gordon McKay Professor'? - Quora 针对答辩者 James Mickens 传授的介绍,大家能够晓得,他关注的畛域是计算机和平安方面,应该会有本人的一些独到的见解,所以,就让咱们走进这位大神的答辩吧! 2.2 论点咱们理解了作者的背景材料后,回到明天的正题,来看看这场答辩的论点: 论断摘要:iPhone 的平安保障次要由 iPhone 的操作系统(iOS)执行有证据表明,利用审核(App Review)的流程在强制额定的平安属性方面做的很弱,这些属性不能独自由操作系统强制执行(笔者注:这里的意思是指,苹果的审核其实对安全性方面审查很弱鸡!?)iOS 和 macOS 很像,曾经可能装置不是通过苹果利用商店(App Store)散发的应用程序如果苹果容许 iPhone 用户抉择第三方利用散发渠道,那么这些用户也不会蒙受安全性显着升高的体验针对这些点论,咱们不要焦急辩解,接下来,先听听传授是怎么开展答辩啊~ 2.3 论据:如何在 iPhone 上施行安全措施? 从图中能够看到,在 iPhone 上的平安防护分了三层:设施内部平安(OFF-DEVICE SECURITY):利用发分。(Can be performed by third parties(能够由第三方执行))设施外部平安(ON-DEVICE SECURIY):操作系统。(Independent of app distribution method(独立于应用程序散发办法))设施外部平安(OFF-DEVICE SECURITY):硬件设施内部平安(OFF-DEVICE SECURITY),分为:App Review(利用审核)Developer Identification(开发者身份辨认)Code Signing(代码签名)这些形式,绝对于 iOS 设施上的安全性机制提供的最低限度安全性(如果有的话)(Provides minimal (if any) security benefits relative to what iOS on-device security mechanisms provide)。 ...

July 20, 2021 · 3 min · jiezi

关于ios:2021年最全iOS-面试题汇总清晰易懂

本文收录:简书【超全!iOS 面试题汇总(清晰易懂) 】 1. Object-c的类能够多重继承么?能够实现多个接口么?重写一个类的形式用继承好还是分类好?为什么?Object-c: 不可多重继承可实现多个接口Category类别: 个别状况用分类好为什么分类好?: 用Category去重写类的办法,仅对本Category无效,不会影响其余类与原有类的关系。2. #import 跟#include 又什么区别,@class呢, #import 跟 #import””又什么区别?#import: Objective-C导入头文件的关键字#include: C/C++导入头文件的关键字#import 跟 #include区别: 应用#import头文件会主动只导入一次,不会反复导入,相当于#include和#pragma once;@class: 编译器某个类的申明,当执行时,才去查看类的实现文件,能够解决头文件的互相蕴含;#import 跟 #import””区别: #import: 蕴含零碎的头文件#import””: 蕴含用户头文件3. 属性readwrite,readonly,assign,retain,copy,nonatomic 各是什么作用,在那种状况下用?readwrite: 可读可写个性(须要生成getter办法和setter办法时)readonly: 只读个性(只会生成getter办法 不会生成setter办法 ;不心愿属性在类外扭转)assign: 是赋值个性(setter办法将传入参数赋值给实例变量;仅设置变量时)retain: 持有个性(setter办法将传入参数先保留,再赋值,传入参数的retaincount会+1)copy: 赋值个性(setter办法将传入对象复制一份;须要齐全一份新的变量时)nonatomic: 非原子操作(决定编译器生成的setter getter是否是原子操作,atomic示意多线程平安,个别应用nonatomic)4.写一个setter办法用于实现@property (nonatomic,retain)NSString name,写一个setter办法用于实现@property(nonatomic,copy)NSString name-?(void)?setName:(NSString*)?str{[str?retain];[name?release];name?=?str;}-?(void)setName:(NSString?*)str{id?t?=?[str?copy];[name?release];name?=?t;}5.对于语句NSString*obj = [[NSData alloc] init]; obj在编译时和运行时别离时什么类型的对象?编译时: NSString的类型运行时: NSData类型的对象常见的object-c的数据类型有那些, 和C的根本数据类型有什么区别?如:NSInteger和intobject-c常见数据类型: NSStringNSNumberNSArrayNSMutableArrayNSData...C语言的根本数据类型: int(肯定字节的内存空间,用于寄存数值)NSInteger根本数据类型: 不是NSNumber的子类不是NSObject的子类是Int或者Long的别名(NSInteger的定义typedef long NSInteger)区别: NSInteger会依据零碎是32位还是64位来决定是自身是int还是Long7.id 申明的对象有什么个性?Id 申明的对象个性: 运行时(能够指向任意类型的objcetive-c的对象)8.Objective-C如何对内存治理的,说说你的认识和解决办法?Objective-C的内存治理次要有三种形式: ARC(主动内存计数) (Garbage Collection)主动内存计数:这种形式和java相似,在你的程序的执行过程中。始终有一个高人在背地精确地帮你拾掇垃圾,你不必思考它什么时候开始工作,怎么工作。你只须要明确,我申请了一段内存空间,当我不再应用从而这段内存成为垃圾的时候,我就彻底的把它忘记掉,反正那个高人会帮我拾掇垃圾。遗憾的是,那个高人须要耗费肯定的资源,在携带设施外面,资源是紧俏商品所以iPhone不反对这个性能。所以“Garbage Collection”不是本入门指南的范畴,对“Garbage Collection”外部机制感兴趣的同学能够参考一些其余的材料,不过说老实话“Garbage Collection”不大适宜适初学者钻研。计划: 通过alloc – initial形式创立的, 创立后援用计数+1, 尔后每retain一次援用计数+1, 那么在程序中做相应次数的release就好了.手动内存计数 (Reference Counted)手动内存计数:就是说,从一段内存被申请之后,就存在一个变量用于保留这段内存被应用的次数,咱们临时把它称为计数器,当计数器变为0的时候,那么就是开释这段内存的时候。比如说,当在程序A外面一段内存被胜利申请实现之后,那么这个计数器就从0变成1(咱们把这个过程叫做alloc),而后程序B也须要应用这个内存,那么计数器就从1变成了2(咱们把这个过程叫做retain)。紧接着程序A不再须要这段内存了,那么程序A就把这个计数器减1(咱们把这个过程叫做release);程序B也不再须要这段内存的时候,那么也把计数器减1(这个过程还是release)。当零碎(也就是Foundation)发现这个计数器变 成员了0,那么就会调用内存回收程序把这段内存回收(咱们把这个过程叫做dealloc)。顺便提一句,如果没有Foundation,那么保护计数器,开释内存等等工作须要你手工来实现。计划: ...

July 19, 2021 · 5 min · jiezi

关于ios:关于ios13升级到ios14企业APP出现无法安装解决方案

申明:此计划实用于app ios13 下载OK,然而ios14 下载同样资源就提醒装置失败!在iOS14更新完了之后咱们公司app 呈现了无奈装置的问题, 同一个plist文件,13能装置,14就提醒无奈装置,今天就开始推ios14了,所以就显得很急,上面记录下咱们的解决方案:咱们没有是用apple store形式下载,咱们用的plist文件的形式下载, 在网上也百度了很多,看到一个这样的帖子 在iOS14上苹果对于本身提供的解决方案中ats的要求更加严格,之前咱们通过itms协定装置利用时只有plist文件是https即可,14之后要求ipa链接应用的也必须是https才行,否则将呈现无奈装置的问题。我就在这开始排查,发现咱们的协定确实全是https的不过还是装置不了,我就间接把itms协定指向的地址copy到谷歌浏览器间接进行的拜访(新版的,版本太旧发现不了问题),发现咱们协定尽管是https的,然而谷歌报了安全隐患 咱们公司装置不了的起因就在这了,找运维把TLS 1.2 这个改了,ios14 就能失常下载了,起初也理解下了这个TLS 1.0和TLS 1.1的HTTPS 网站方面问题,发现2018 年,在秋季TLS 1. 3 版本公布之后,苹果、谷歌、Mozilla和微软四大浏览器制造商于 2018 年 10 月联结发表打算在 2020 年初勾销对TLS 1. 0 和TLS 1. 1 的反对。有趣味的能够去理解下 有想要支付收费材料的能够进裙或者加好友支付,这里有一个iOS交换圈:点击进入) 能够来理解,分享BAT,阿里面试题、面试教训,探讨技术,裙里材料间接下载就行, 大家一起交流学习!有想要的面试材料或者其余材料也能够找我,欢送征询!

July 19, 2021 · 1 min · jiezi

关于ios:iOS底层面试题分享附带iOS工程师规划定位

为什么会有面试跳槽呈现? 面试题收录:https://juejin.cn/post/698317... 面试题介绍 题目是检测大家的技术水平最好的办法 敲响警钟,心愿大家可能意识本身有余、及时查漏补缺 1、选择题一、选择题⚠️ 有单选有多选哦⚠️ 在LP64下,一个指针的有多少个字节A: 4 B: 8 C: 16 D: 64一个实例对象的内存构造存在哪些元素 A:成员变量 B: supClass C: cache_t D: bit 上面sizeof(struct3) 大小等于 struct LGStruct1 { char b; int c; double a; short d;}struct1;struct LGStruct2 { double a; int b; char c; short d;}struct2;struct LGStruct3 { double a; int b; char c; struct LGStruct1 str1; short d; int e; struct LGStruct2 str2;}struct3;A: 48 B: 56 C: 64 D: 72 下列代码: re1 re2 re3 re4 re5 re6 re7 re8输入后果 ...

July 15, 2021 · 2 min · jiezi

关于ios:如何在-iPhone-上制作小部件

学习如何从第三方应用程序制作可自定义的小部件和小部件。能够在任何装有 iOS 14 或更高版本的 iPhone 上执行此操作。 如何在 iPhone 上制作小部件 要制作小部件,首先从利用商店下载第三方利用,例如 Widgetsmith。 在主屏幕上,点击并按住直到您在左上角看到一个加号。点击此增加小部件。 如何制作小部件 在这些步骤中,咱们将应用应用程序Widgetsmith创立一个小部件。您能够从 App Store 下载此应用程序。 下载 Widgetsmith 后,关上应用程序。 点击增加(大小)小工具以制作您抉择的大小的小工具。 点击增加的小部件,而后点击默认小部件框。 通过抉择款式、字体和色彩来编辑您的小部件。 实现编辑后,点击左上角的后退箭头,而后点击保留。 退出应用程序并转到您的主屏幕,而后点击并按住直到您在左上角看到一个加号图标。 当初搜寻 Widgetsmith 或在目录中点击它。 抉择想要增加的尺寸小部件,而后点击增加小部件。而后点击主屏幕上的实现。 要将小部件更改为创立的小部件,请点住小部件,而后抉择“编辑小部件”。 从列表中抉择心愿在主屏幕上显示的小部件。 你如何在 iPhone 上自定义小部件? 依据您应用的应用程序,自定义小部件可能因每个应用程序而异。 在 App Store 中,搜寻“可自定义的小部件”,找到能够制作小部件而后在 iPhone 主屏幕上应用的应用程序。浏览该应用程序的阐明,理解能够通过该应用程序自定义哪些类型的小部件。 还能够应用 Apple 在 iOS 14 更新中引入的快捷方式应用程序来制作快捷方式小部件。这些小部件无需关上应用程序即可在应用程序中执行工作。

July 12, 2021 · 1 min · jiezi

关于ios:极光笔记iOS-15推送新特性初探

前言北京工夫2021年6月8日凌晨1点,苹果召开了WWDC 21大会。在会上公布了新版的iOS 15零碎,iOS的主题是Focus, connect, and explore。 有关注的同学应该发现了本次主题其中提到的Focus正是在iOS 15当中新增的对于告诉的变动。本篇文章所分享的就是iOS 15中新增的推送个性。 Focus(专一模式)其实在iOS 15之前也有专一模式,iOS 15的专一模式,其实是以后版本勿扰模式的演进产品。 能看到第一局部就是具体的模式,默认的有集体,勿扰模式,工作,睡眠。其实四种没什么区别就是用名字作为辨别,在不同工夫抉择不同的模式,来给本人带来更好的告诉应用体验。咱们还能够手动增加专一模式,设置专一模式的名字,图标,以及对应的配置。 咱们能够设置在所有设施中共享专一模式,也能够设置哪些App可能拜访用户的专一状态,该性能目前仅凋谢给苹果本人的App,目前笔者还没有发现有代码和设置可能拜访该性能。 电话成为了惟一一个能够独自在专一模式上进行全局设置的App,能够在专一模式关上时指定可能接管的电话。 咱们点击“集体”进入具体的专一模式,能看到有多个配置。咱们能够为某些通讯录成员和App设置一个不受专一模式影响的白名单。 还能够设置是否关上时效性告诉(Time Sensitive)接管性能,时效性告诉也是iOS 15中提供的一个新的告诉个性,咱们会在后续的文章中提到。 设置共享专一状态,和刚刚那个全局的设置能够拜访专一模式的性能相似,就是作用域不一样了,然而还是和刚刚的问题一样,目前没发现在哪里可能获取到专一模式的状态,揣测苹果会在后续的版本中更新(另一种可能是应用getNotificationSettingsWithCompletionHandler接口进行获取,只是获取到的不是专一模式,这个官网中央文档形容的确有点含糊,还不能齐全确认) Interruption level(中断级别)在iOS 15及更高版本中,人们能够通过指定的音讯派发工夫和设置专一模式对告诉行为进行更加细粒度的调整。派发告诉打算容许用户抉择是立刻接管告诉,还是在他们抉择的时间段内应用摘要派发告诉。专一模式帮忙人们在他们定义的时间段内过滤告诉,例如睡眠、工作、浏览或驾驶等流动。 人们能够在专一模式中为抉择的联系人和应用程序设置白名单以承受告诉。 例如,在以工作为核心的环境中,人们可能心愿立刻收到来自共事、家庭成员和与工作相干的应用程序的音讯。人们可能还心愿在开启专一模式期间接管所有对工夫敏感的告诉。对工夫敏感的告诉蕴含人们心愿立刻取得的根本信息。 须要留神的是即便专一模式可能会提早告诉的派发,告诉自身也会在达到时立刻可用。 为应用程序能够发送的每个告诉指定零碎定义的中断级别。零碎应用中断级别帮忙确定何时派发告诉;当通信告诉达到时,零碎应用发送方的配置确定何时派发告诉。 零碎为非通信告诉定义了四个中断级别: •Passive(被动的)。人们能够在空闲时查看信息,比方餐厅举荐。•Active(流动,默认设置)。当信息达到时,人们可能心愿晓得它,比方他们最喜爱的球队的分数更新。•Time Sensitive(工夫敏感)。间接影响用户并须要他们立刻关注的信息,如帐户平安问题或快递信息。•Critical(重要)。间接影响用户并要求其立刻关注的无关集体衰弱和公共安全的紧急信息。要害告诉十分常见,通常来自政府和公共机构或医疗保健应用程序。应用该中断级别须要申请对应的权限。 四种级别对应的能力如上图。被动和沉闷是一样的,工夫敏感的级别可能笼罩定时推送性能和专一模式,重要级别的告诉甚至可能屏蔽电话和静音设置。 在这个新个性上咱们能看到一些苹果历史以来的设计思路,苹果心愿开发者可能精确设置每个告诉的紧急水平来建设信赖。 用户有几种办法来调整他们从你的应用程序接管告诉的形式,例如:敞开所有告诉。因而在调配中断级别时,必须尽可能事实。我想你不会心愿用户感觉你应用了一个高级别的告诉去打断他们的工作,然而信息确是一个低级别的信息,这很可能会导致用户敞开你App的告诉权限。 当你的应用程序第一次收到工夫敏感的告诉时,零碎会形容这种告诉是如何工作的,如果用户不批准这些信息须要立刻关注,零碎会提供一种敞开告诉的办法。 切勿应用工夫敏感的中断级别发送营销告诉。用户可能曾经批准从你的应用程序接管营销告诉,然而这样的告诉不应该冲破专一模式或预约的告诉派发设置。 对于中断级别这段有很大一部分是翻译的苹果原文,有趣味的同学能够看一下。 笔者尝试全链路的去验证下不同中断级别的体验,然而iOS 15刚刚公布,处于晚期阶段,在《生成一个近程告诉》文档和《发送告诉申请到APNs》文档中,临时没有找到相干材料,因而无奈实测。 于是我转换了一个思路,尽管API没有更新,然而代码可能曾经更新了,于是我更新了Xcode 13.0 beta版本并查看对应的框架API。 咱们能够在<UserNotifications/UserNotifications.h>框架中找到最新的iOS 15相干的代码,在<UserNotifications/UNNotificationContent.h>中咱们能看到新的对于中断级别的枚举。 咱们看英文形容,在这里能看到被动和沉闷中断级别的区别。被动的中断级别不会亮屏和播放推送声音,并且只会退出到告诉列表(应该说的是告诉核心)中,而沉闷的也就是默认的,会立即被展现并亮屏,播放推送声音。 除此之外,还有对应的新增的属性。 interruptionLevel应该很好了解,就是该推送的中断级别。除此之外还能看到一个属性叫做relevanceScore相干分数,相干分数的高下会影响在告诉核心中的排序,这个在WWDC中有一嘴带过,然而在苹果告诉导读文档中却没有提到,这个属性应该在APNs的API也可能设置才对。 不想当初就下载Xcode beta版本,然而又想理解最新的API的在官网的iOS文档中也可能看到。 Xcode越来越大了 定时推送摘要最初在说一下这个定时推送摘要,后面有常常说到一个依据理论派发推送告诉的就是这个。 因为官网APNs API没更新的限度,笔者还没有齐全搞清楚定时推送摘要的具体逻辑。咱们先看一下在iOS 15中的设置局部。 在告诉界面减少了一个定时推送摘要的入口,咱们关上这个性能,而后依据工夫设置一天推送几次摘要,咱们须要抉择具体的App适应这个配置,默认是全敞开的。比如说我设置了一天4次派发告诉摘要,那么在发送告诉的时候应该不会立刻提醒,而是等到摘要的工夫才会显示。 然而理论景象是这样的,我发送了一条告诉,立刻就收到了,而后比如说我在下午5点发的音讯,音讯被放到了一个新的分类叫做早晨的推送摘要中和预期不太一样,揣测可能是因为默认音讯类型是流动导致的,可能须要发送被动类型的音讯能力触发这个性能。 对于摘要这一块,还有比拟多的不确定的货色须要摸索。 那么到这里,对于iOS 15上的告诉新个性的初探就完结了,笔者在写这篇文章的时候还是感觉目前iOS 15仍处于一个Beta版本的晚期阶段,查阅文档发现的局部性能都还处于未齐全放开的阶段,依照苹果的习惯在公布GM版本之前应该还有有一些调整,所以该文章中的内容是有被改变的可能性的,请大家还是以最新的iOS 15上能看到的成果为准。 感激各位浏览。文章编写于2021年6月21日,iOS 15第一个Beta版本。 ...

July 11, 2021 · 1 min · jiezi

关于ios:iOS如何提升首先得知自己的处境欢迎评论留言

聊聊行情?为什么总有人在乎旁人的认识而疏忽本人的初衷?尽管iOS开发市场说不上好但也绝不算坏,想没想过那些煽风点火说iOS不行的人在做什么?真的转行从头开始?错、大错特错!在劝退你的同时他们会默默的学习巩固本身位置,当然不激励也不拥护他人入iOS,但如果要做,切勿抱有偷懒心理,该学的都得学。(不要诽谤行业不行,只是你能力和它不对等,仅此而已!) 聊聊学习: 对于学习,个别iOS开发想到的学习,会是技术,往年有什么新技术,学习了什么新技术,谋求“新技术”,而不是专一iOS深度学习。 为什么会有面试跳槽呈现? 倡议:对于底层原理方面的一些倡议,最好能结合实际我的项目,应用你学到的底层常识,解决了什么问题,这样更能感动面试官。对于组件化计划,很多公司都会问,所以,不管你面哪家公司,都要对这部分有一个粗浅的理解,最好能理论应用过,并且做出优化对于算法,这个就是下功夫了,多刷LeetCode如果你iOS做了几年,不晓得应该往那方向进阶。如果你想在技术深度上持续有所晋升,如果你想升职加薪,如果你想取得称心的Offer 那无妨花个几分钟的工夫,看看这篇对于iOS进阶的参考文章! 一、大厂招聘的中高级iOS开发要求iOS高级工程师的技术要求 精通 Objective-C语言根底精通 UIKit等Cocoa Framework相熟 网络通信机制以及罕用数据传输协定具备 支流开源框架的应用教训 必备技能(全副都会的状况下查看下一项)Xcode的应用 第三方库的灵便应用AFN MJRefresh各种网站的应用如何判断是否能够升阶是否理解AFNetworking 的实现原理 是否理解SDAutolayout/Masonry 一种布局库的原理是否可能解决根本的iOS解体起因/无奈编译起因/无奈上架起因?是否领有了肯定的工作效率,稳固的工作效率.(而不是说,下面派了一个活下来,忙都忙不完,天天加班,还一堆bug)是否可能解决第三方库引起的解体.是否能够很好的融入工作环境,实现每一阶段的工作指标,而不会让本人疲惫不堪.论断iOS中级开发说白了,就是你学会了根本的UI界面搭建,上架,积淀一段时间,你感觉本人还适宜这门行业,还适宜,还能承受 这个所谓的iOS开发工程师的行业.你就能够说是一名中级iOS开发. 这个积淀工夫 大概在1年的理论工作中,就能够实现.如果你感觉这门行业不适宜你,请认真联合本身状况,是否转另一门计算机语言,还是彻底转行.iOS中级工程师的技术要求 扎实的 编程、数据结构、算法根底深刻了解 语言机制、内存治理、网络、多线程等精通 罕用设计模式、框架、架构良好的 剖析、解决问题 的能力 必备技能(全副都会的状况下查看下一项)利用的内存解决 利用的推送解决利用的模块化/单元测试利用的第三方集成/集中化治理/稳固迭代浏览弱小的第三方源码/领有疾速上手新的第三方库的能力.可能承受各种新性能的开发(这里是指,即便你没有做过,然而你依然能够凭借着学习,解决任何业务需要:例如:蓝牙.AR.摄像头.硬件交互.等)分明明确数据的传递形式,利用与后盾如何替换数据,替换数据的过程,后果,格局.多线程的灵便应用.各种并发事件的解决/以及界面的合理性/晦涩度设计模式的灵便应用.iOS高级工程师的技术要求 解决 研发过程中的 关键问题 和 技术难题调优 设施流量、性能、电量等较强 的软件设计能力对iOS外部原理有 深刻理解 必备技能利用的组件化/架构分层 数据结构,操作系统,计算机网络都有本人的理解和认知Shell脚本/python/Ruby/JS 至多会一种.二、为什么要一直晋升本人欠缺 iOS常识技术体系晋升本人 技术深度职场的 职级降职丰富的 薪酬称心的 Offer 三、本身的缺点 如果这些问题是阻止你升职加薪,跳槽大厂的妨碍。 那么我确信能够帮你冲破瓶颈!第一步-技术点视频 从底层常识到技术亮点,从简历模板到面试口述,每天花一点工夫来学习,晋升或者不会很快,但不学习不口头就肯定会被淘汰!第二步-BAT面试材料 视频面试材料获取形式增加助理VX:yaoxikeaim || QQ:2684207472增加时请备注:iOS技术晋升视频 || BAT面试材料; (PS:请勿外传,仅限集体学习应用)还用很多内容,就不具体展现了,都在群文件中能够自行下载 心愿获取到的你;能好好利用,晋升本人!材料获取形式:点击增加咱们的技术交换圈 管理处收费支付全套iOS材料点击-间接退出: 技术交换群 喜爱的小伙伴记得点赞喔~珍藏等于白嫖,点赞才是真情( ´・・` )查看原文

July 7, 2021 · 1 min · jiezi

关于ios:iOS工程师如何恍然大悟

聊聊行情?为什么总有人在乎旁人的认识而疏忽本人的初衷? 尽管iOS开发市场说不上好但也绝不算坏,想没想过那些煽风点火说iOS不行的人在做什么? 真的转行从头开始? 错、大错特错! 在劝退你的同时他们会默默的学习巩固本身位置,当然不激励也不拥护他人入iOS,但如果要做,切勿抱有偷懒心理,该学的都得学。(不要诽谤行业不行,只是你能力和它不对等,仅此而已!) 本文收录:iOS进阶宝典<iOS工程师如何豁然开朗?>上篇文章讲述: iOS不行?还是集体能力有问题? 晓得为何而学,才算取得学习最强劲最长久的能源。 谈谈工作:    因主职是iOS工程师,对于iOS开发的工作,兴许大多数人都认为是加班!而我认为是写代码!    不论写什么语言的代码,语言就是工具,解决问题才是重点,如何利用更好的工具,更佳的计划来解决问题,这才是我想要的工作!心愿大家也一样,工作不只是加班,还有诗和远方! 谈谈学习:    对于学习,个别iOS开发想到的学习,会是技术,往年有什么新技术,学习了什么新技术,谋求“新技术”,而不是专一iOS深度学习。 上面总结出的iOS开发职业倒退线路,分享给大家。 谈谈面试跳槽:    做开发的,职位降职门路根本很清晰,所以必须把握好跳槽涨薪的每一次机会。 跟一些大厂招聘者交换,失去的反馈是:公司招不到适合的iOS开发,求职的iOS开发者拿不到想去公司的 offer,单方各自焦急。 为什么会呈现这样的状况? 好iOS开发 ≠ 高薪iOS开发。 很多平时技术能力不错的iOS开发,到了面试的时候就不晓得怎么说, 逻辑思路全都是乱的,平时张嘴就来的知识点,面试的时候答得一塌糊涂。会某个技术 ≠ 把握某个技术。 目前很多iOS面试官都是刨根问底的,狠抓一个问题问个不停,很多技术人感觉本人会用了某个技术,就说本人能够熟练掌握,后果一深刻底层逻辑,就齐全不会了。筹备面试常识 ≠ 面试官考查常识。 很多iOS开发邻近面试开始搞突击,零零散散地看面试常识、底层常识,技术框架,后果面试官基本没问。问的知识点都让人猝不及防。面试这件事,肯定不能漫不经心,如果你做不到把握零碎的技术常识体系,那我倡议你肯定要关注罕用框架背地的"底层原理和源码"。 在面试的时候,用对技术的深度思考驯服面试官,能力稳拿offer,谈得高薪。 说起来很简略,做起来却很难 (少数iOS开发的心声): iOS开发原本业务就很忙,哪有工夫分心去探索底层原理,而且最新的底层技术材料还很零散,想深刻探索底层,都无从动手! 文末举荐:iOS热门文集&视频解析① Swift② iOS底层技术③ iOS逆向防护④ iOS面试合集⑤ 大厂面试题+底层技术+逆向安防+Swift

July 7, 2021 · 1 min · jiezi

关于ios:iOS不行还是个人能力有限

平时工作之余,我也会偶然看下QQ交换群外面的聊天信息,最近发现群里的很多iOSer都在探讨iOS不如从前,自嘲iOS岗位没人要。 有人吐槽说 iOS不行了,内卷重大拿不到高薪资也有人说不是 iOS不行,而是咱们本人限度了本人的技术倒退, 收录注释:iOS进阶宝典<iOS不行?还是集体能力无限?>小了!格局小了啊!当初可远远不光是iOS开发不行了啊。 那么在意他人的认识干嘛?是金子总会发光,不要总拿回避做你的挡箭牌! 咱们来看看大家如何评估近年iOS行情? 答案是高精尖人才任何一个行业中的大牛都是缺的。不论怎么样,如果你是一名iOS开发工程师,我还是倡议你多学学底层进阶,不论是从换工作的角度,还是从集体倒退的角度。不信的话,你去招聘网站iOS高级工程师的待遇,那个不会骗人。 那么当初iOS高级开发都在问什么? 这个话题,大略是少数iOS开发,在面试前,探讨最多的一个了,都想理解最新的面试状况,做更足的筹备,以下是小编收集总结的技术点+**面试题分类;看看你都把握了吗? 重点总结-四大分类: iOS底层原理性能优化以及架构多线程、网络数据结构算法iOS底层原理(必问): iOS开发必备能力,也是大厂面试疾速筛选人才形式之一。 对象底层原理指针与内存的一些相干面试Weak 弱援用Block 的原理AutoreleasePool 原理Runloop 的原理Runtime相干、音讯转发原理....组件化常问例题: 1\. 什么状况应用weak关键字,相比assign有什么不同?性能优化以及架构能力: 目前大厂对于这一块,非常重视; ①性能优化方面:tableView的优化 -> 界面卡顿原理 -> app 性能剖析 -> 我的项目优化②架构方面:设计模式、解耦伎俩、组件化....常问例题: 1\. 造成tableView卡顿的起因有哪些?多线程、网络能力: iOS中高级开发,都应该理解,并且相熟的知识点; 多线程的原理线程池GCD锁相干原理网络设计网络框架的了解开发过程中一些需要联合多线程或者网络设计!常问例题: 1. 过程与线程?数据结构算法能力占比比拟大: 通常个别大公司都会有一些口试:尽管不在外围岗位对于数据结构算法要求不是十分严格,然而也会有一些惯例的数据结构和算法的题 排序数据结构设计复杂度探讨一些脑筋急转弯的算法题......常问例题: 1\. 链表和数组的区别是什么?插入和查问的工夫复杂度别离是多少?那如何成为成为那10%的高级开发者呢?尽管都说iOS开发上手容易,一行代码,一个笔记本,然而真正的能应用 iOS开发进行高级我的项目的编写,以及跳槽拿到高薪,就没有那么容易了。因为大部分人在iOS开发行业中,都遇到过这么几个的窘境: 想涨薪?想跳槽?请心里别吐槽; 小编 都晓得,都晓得; 是否想过为什么你不是那10%的高级开发?他人为什么能高薪? 在这用句老话: 不要只看到他人的胜利,要看到他人背地的艰苦iOS开发市场说不上好但也绝不算坏,技术能力够面试也是多多,不激励也不拥护他人入iOS,但如果要做,切勿抱有愉懒心理,该学的都得学。 往期举荐1 iOS工程师底层进阶面试视频举荐2 2021全新iOS学习方向3 iOS岗位招聘规范水涨船高,iOS程序员示意面试太难了 舒适提醒关注iOS进阶宝典回复 “面试题” 支付 大厂面试算法材料

July 5, 2021 · 1 min · jiezi

关于ios:iOS弹窗优先级调度器FGPopupScheduler

GitHub 地址:FGPopupScheduler 反对 cocopods,应用简便,效率不错的根底组件。 前言前些天测试反馈当新用户刚关上APP的时候,因为弹窗过多,再加上还有半透明的疏导层,常常会呈现弹窗相互笼罩,甚至阻断失常流程的状况。而须要解决这类问题,不单单要理分明弹窗之间的依赖关系,还须要解决弹窗自身呈现的条件。并且在每次有新的弹窗退出时都须要查看之前弹窗的逻辑。每一步都要消耗开发资源。 所以咱们的目标就是为了解决,如何拆分各个弹窗间的依赖关系,并在失当地时刻顺次显示弹窗。 需要剖析首先是弹窗自身的需要 弹窗显示弹窗暗藏弹窗显示须要满足的条件而后是对于弹窗与弹窗 弹窗的优先级弹窗是否会受到已显示弹窗的影响弹窗显示有一个特色,就是同一个时刻只会显示一个弹窗,并且能够是一个接一个显示。如果采纳采纳队列来治理的话,天经地义地就须要额定解决插入、删除、清空、遍历等行为。 这一套流程下来貌似就解决了,但实际上当把所有弹窗的对立交给一个调度器来治理的话,咱们必须要思考在什么机会显示/暗藏这些弹窗才是更加正当的。 当然,FGPopupScheduler 就能帮忙解决下面这些琐碎的事件,而且不止于此。 实现剖析思考到弹窗自身的多样性,甚至可能不是View。所以采纳协定将弹窗的逻辑形象解决放到<FGPopupView>中,只有恪守了协定将能作为就能被调度器对立治理。 @protocol FGPopupView <NSObject>@optional/* FGPopupSchedulerStrategyQueue会依据 -showPopupView: 来监听显示逻辑,如果含有动画请实现-showPopupViewWithAnimation:办法 */- (void)showPopupView;/* FGPopupSchedulerStrategyQueue会依据 -dismissPopupView: 来监听暗藏逻辑,如果含有动画请实现-showPopupViewWithAnimation:办法 */- (void)dismissPopupView;/* FGPopupSchedulerStrategyQueue会依据 -showPopupViewWithAnimation: 来监听显示逻辑 */- (void)showPopupViewWithAnimation:(FGPopupViewAnimationBlock)block;/* FGPopupSchedulerStrategyQueue会依据 -dismissPopupView: 来监听暗藏逻辑,如果含有动画请实现-dismissPopupViewWithAnimation:办法 */- (void)dismissPopupViewWithAnimation:(FGPopupViewAnimationBlock)block;/** FGPopupSchedulerStrategyQueue会依据-canRegisterFirstPopupView判断,当队列程序轮到它的时候是否可能成为响应的第一个优先级PopupView。默认为YES */- (BOOL)canRegisterFirstPopupViewResponder;@end对于弹窗显示的程序和优先级,实际操作中还会波及到中途插入或者移除的操作,数据结构更相似于链表,所以这里采纳了C++的STL规范库:list。 具体的策略如下 typedef NS_ENUM(NSUInteger, FGPopupSchedulerStrategy) { FGPopupSchedulerStrategyFIFO = 1 << 0, //先进先出 FGPopupSchedulerStrategyLIFO = 1 << 1, //后进先出 FGPopupSchedulerStrategyPriority = 1 << 2 //优先级调度};实际上使用者还能够联合 FGPopupSchedulerStrategyPriority | FGPopupSchedulerStrategyFIFO 一起应用,来解决当抉择优先级策略时,如何决定同一优先级弹窗的排序。 通过hitTest来解决弹窗显示条件的需要,如果依据以后的命中的弹窗没有通过hitTest,则会依据抉择的调度器策略,在以后的list中获取下一个弹窗进行测试。 - (PopupElement *)hitTestFirstPopupResponder{ list<PopupElement*>::iterator itor = _list.begin(); PopupElement *element; do { PopupElement *temp = *itor; id<FGPopupView> data = temp.data; __block BOOL canRegisterFirstPopupViewResponder = YES; if ([data respondsToSelector:@selector(canRegisterFirstPopupViewResponder)]) { dispatch_sync_main_safe(^(){ canRegisterFirstPopupViewResponder = [data canRegisterFirstPopupViewResponder]; }); } if (canRegisterFirstPopupViewResponder) { element = temp; break; } itor++; } while (itor!=_list.end()); return element;}因为通过FGPopupScheduler来对立治理所以的弹窗,所以弹窗下面时候触发就须要组件本人来解决。这个笔者一共思考了3个触发状况 ...

July 3, 2021 · 1 min · jiezi

关于ios:打造一套客户端功能最全的-APM-监控系统

APM 是 Application Performance Monitoring 的缩写,监督和管理软件应用程序的性能和可用性。利用性能治理对一个利用的继续稳固运行至关重要。所以这篇文章就从一个 iOS App 的性能治理的纬度谈谈如何准确监控以及数据如何上报等技术点App 的性能问题是影响用户体验的重要因素之一。性能问题次要蕴含:Crash、网络申请谬误或者超时、UI 响应速度慢、主线程卡顿、CPU 和内存使用率高、耗电量大等等。大多数的问题起因在于开发者谬误地应用了线程锁、零碎函数、编程标准问题、数据结构等等。解决问题的关键在于尽早的发现和定位问题。 本篇文章着重总结了 APM 的起因以及如何收集数据。APM 数据收集后联合数据上报机制,依照肯定策略上传数据到服务端。服务端生产这些信息并产出报告。请联合姊妹篇, 总结了如何打造一款灵便可配置、功能强大的数据上报组件。 一、卡顿监控卡顿问题,就是在主线程上无奈响应用户交互的问题。影响着用户的间接体验,所以针对 App 的卡顿监控是 APM 外面重要的一环。 FPS(frame per second)每秒钟的帧刷新次数,iPhone 手机以 60 为最佳,iPad 某些型号是 120,也是作为卡顿监控的一项参考参数,为什么说是参考参数?因为它不精确。先说说怎么获取到 FPS。CADisplayLink 是一个零碎定时器,会以帧刷新频率一样的速率来刷新视图。 [CADisplayLink displayLinkWithTarget:self selector:@selector(###:)]。至于为什么不准咱们来看看上面的示例代码 _displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(p_displayLinkTick:)];[_displayLink setPaused:YES];[_displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];代码所示,CADisplayLink 对象是被增加到指定的 RunLoop 的某个 Mode 下。所以还是 CPU 层面的操作,卡顿的体验是整个图像渲染的后果:CPU + GPU。请持续往下看 1. 屏幕绘制原理 讲讲老式的 CRT 显示器的原理。 CRT 电子枪依照下面形式,从上到下一行行扫描,扫面实现后显示器就出现一帧画面,随后电子枪回到初始地位持续下一次扫描。为了把显示器的显示过程和零碎的视频控制器进行同步,显示器(或者其余硬件)会用硬件时钟产生一系列的定时信号。当电子枪换到新的一行,筹备进行扫描时,显示器会收回一个程度同步信号(horizonal synchronization),简称 HSync;当一帧画面绘制实现后,电子枪复原到原位,筹备画下一帧前,显示器会收回一个垂直同步信号(Vertical synchronization),简称 VSync。显示器通常以固定的频率进行刷新,这个固定的刷新频率就是 VSync 信号产生的频率。尽管当初的显示器根本都是液晶显示屏,然而原理放弃不变。 通常,屏幕上一张画面的显示是由 CPU、GPU 和显示器是依照上图的形式协同工作的。CPU 依据工程师写的代码计算好须要事实的内容(比方视图创立、布局计算、图片解码、文本绘制等),而后把计算结果提交到 GPU,GPU 负责图层合成、纹理渲染,随后 GPU 将渲染后果提交到帧缓冲区。随后视频控制器会依照 VSync 信号逐行读取帧缓冲区的数据,通过数模转换传递给显示器显示。 ...

July 2, 2021 · 80 min · jiezi

关于ios:苹果发布iOS-15-Beta-2测试版新增功能修复Bug该更新吗

苹果在上周向开发者推送了iOS 15 beta 2和iPadOS 15 beta 2,这是自本月早些时候在WWDC 2021大会上首次公布以来的第一次更新。上面咱们就来看看这次的更新有哪些新的内容。 不适用于某些设施依据苹果开发者网站上的iPadOS 15 beta 2公布阐明,这次的版本不能装置在9.7英寸iPad Pro (WiFi + 蜂窝网络版本)。起因不明,但可能是苹果发现了一些重大的问题,因而临时为受影响的iPad型号跳过这个版本。 新的地图图标苹果在2021年WWDC大会上走漏了其地图利用的新图标,但它并没有蕴含在iOS 15 beta 1中。据曾经降级的果粉反馈,iOS 15 beta 2的地图图标曾经更换。还在利用内显示了动画的驾驶方向。 Memoji表情苹果本月早些时候还提到,Memojis将迎来全新外观,包含自定义设置服装、表情色彩等选项。这些选项当初能够在iOS 15 beta 2中应用。 天气利用新增欢送屏幕降级iOS 15 beta 2后,当你第一次启动天气利用时,你会看到一个欢送屏幕,强调其新性能和新告诉。 iPad上的疾速笔记在iPadOS 15测试版1中曾经有了疾速记事性能。当初在测试版2中,用户能够从右下角轻扫来触发这个性能。 SharePlay性能SharePlay是一项新性能,能够让用户在FaceTime通话中分享歌曲、视频,甚至是共享屏幕。这项性能当初能够在iOS 15 beta 2中应用。 浏览器苹果为Safari地址栏带回了刷新按钮,但它只在应用鼠标或触控板时显示进去。 除了新增一些性能,iOS 15 beta 2测试版还修复了许多Bug,例如:应用“还原镜像”装置iOS 15测试版时,Finder没有响应;iCloud Private Relay无奈失常工作的问题;微信朋友圈不能公布视频;负一屏无奈失常显示;性能汉化等等。 尽管这个更新版本比iOS 15 beta 1要稳固了不少,然而许多问题依然存在。咱们依然不倡议大家不要自觉降级,防止影响设施失常应用。

June 30, 2021 · 1 min · jiezi

关于ios:Swift知识介绍

本教程是IOS/Swift常识的总结,实用于通过对Objictive C编程的使用并须要理解基于iOS程序的iPhone和iPad的程序员。做一个有bigger的’攻城狮‘,有尊严的工作,高兴的工作,享受工作。本文收录:Swift常识介绍 对于Swift 苹果公司于WWDC2014(Apple Worldwide Developers Conference. June 2-6, San Francisco)公布新的编程语言--Swift。对于软件用户、游戏玩家,大家始终都在提倡用户体验。其实软件开发者本人也是用户,是各种开发工具的使用者,也会喜爱用户体验做得好的工具软件。这次苹果想开发者所想,提供了一个能够玩转swift的游乐场--Playground,它为开发着提供了不便、提供了乐趣。本篇次要简略列举几点,而后介绍Swift入门操作。 Swift是什么 Swift是用来写iOS和OS X程序的编程语言。Swift汲取了C和Objective-C的长处,且更加弱小易用。Swift能够应用现有的Cocoa和Cocoa Touch框架。Swift兼具编译语言的高性能(Performance)和脚本语言的交互性(Interactive)。Swift有什么特点 属性(Property)、可空值(Nullable type)、泛型(Generic Type)语法,源自C#。格局格调:句末能够没有分号,判断条件不须要括号,同Go格调。以后实例应用self援用语法、列表/字典申明语法,同Python格调。区间申明语法(如:1..3:前闭后开[1,2],1...3:前闭后闭[1,2,3]),同Haskell格调。协定(protocol)和扩大(extension),源自Objective-C。枚举(enum)类型能够领有成员或办法,很像Java。类(class)和构造(struct)的概念,和C#类似。用什么IDE开发Swift Xcode6开始反对Swift语言。Xcode6提供了Playground界面,能够边开发边看到执行成果。Swift 能够干什么 1 .疾速练习swift 不须要编译、不须要点击执行,编写代码后间接看成果,比脚本语言还不便,开发者能够通过Playgroud疾速得进行语法试验、API调用,等等。 2.可视化程序逻辑 Playground不仅提供了动态变量即时查看,而且能展现随工夫变动的值。 如图,通过右上角的两个按钮,能够切换Playground的两种编辑试图: Standard Editor 即时显示变量值。Assistant Editor 在时间轴上显示变量值,或者自定义显示。Assistant模式对于开发者测验程序逻辑将有重要帮忙: 不再须要逐渐断点调试。不再须要输入日志查看。不仅能显示数值曲线,还能显示图形图像。3.自定义显示 开发者能够依据须要扩大动静展现接口,以本人的形式展现程序。如WWDC2014上演示的内容: Playground有什么毛病    1.Playground临时不反对界面交互。    即无奈在Playground中玩你开发的游戏。   2.Playground不是模拟器不能执行app程序。 环境筹备 Mac OS版本 Mac零碎版本 >= 10.9.3, 我的开发环境是MacOS 10.10.1 Xcode6 Xcode版本 >= 6.0, 我的开发环境是Xcode 6.1.1 | 一.创立工程 | 装置胜利后开始咱们的新的Swift之旅吧。首先,咱们来创立一个Swift语言的工程。和原来创立工程一样,只须要在语言选择时抉择Swift即可。 Swift排在了语言选项的第一项,可见苹果对它的器重水平,当前预计会成为默认选项的。 工程创立后,你会发现和以前的Hello World没什么变动。 说好的Playground呢?你会发现在右下角有这么一个文件类型Playground,晓得要干什么了吧? 其次,增加Playground文件. 间接从右下角拖动到工程中File-》New-》File...,抉择Playground两头: 代码编辑区域。 ...

June 29, 2021 · 1 min · jiezi

关于ios:Core-Text-雕虫小技-建立指示行

本文应用 Core Text 实现这个成果,滚动文本,两头那一行变红 Core Text 实际 +:文字得心应手摆放 前文等,曾经实现了, 应用 CoreText, 能够自定义的管制每一行的地位 思路滚动的时候,应用一个计时器,不停的重绘,setNeedsDisplay() 找出两头的那一行,变红 其它行,维持原样 实现父视图, 滚动视图 // 滚动视图class ReadScrollV: UIScrollView { // 滚动视图,搁置一个文本绘制视图 fileprivate lazy var ccc = TxtViewCustom() var timer: Timer? func setup(){ let t: TimeInterval = 0.1 timer = Timer.scheduledTimer(timeInterval: t , target: self, selector: #selector(ReadScrollV.loops), userInfo: nil, repeats: true) timer?.fire() if timer != nil{ RunLoop.main.add( timer! , forMode: RunLoop.Mode.common) } } @objc func loops(){ if isDragging || isTracking{ // 滚动的时候,重绘 ccc.criteria = contentOffset.y + TxtCustomConst.kLnTop ccc.setNeedsDisplay() } }}子视图,文本绘制 ...

June 29, 2021 · 3 min · jiezi

关于ios:iOS面试残篇辟邪剑谱

GCD怎么用的?本文收录:https://juejin.cn/post/6976878024566243335 1.串行队列,同步操作,不会新建线程,操作程序执行;串行队列,异步操作,会新建线程,操作程序进行,应用场景: 既不影响主线程,又须要程序执行的操作; 2.并行队列,同步操作,不会新建县城,操作程序执行; 并行队列,异步操作,会新建线程,操作无序进行,队列前如果有其余工作,会期待其余工作执行结束再执行; 全局队列是零碎的,间接get就能够用UI的更新工作必须在主线程进行, 全局队列异步操作,会新建对个子线程,操作无序执行,如果队列前有其余工作,会期待其余工作执行结束在调用; 全局队列同步操作,不会新建线程,程序执行队列所有的操作都是主线程程序执行,没有异步概念,主队列增加的同步操作永远不会执行,会死锁 单例模式allocwithzone是对象分配内存空间时,最终会调用的办法,重写该办法,保障只会调配一块内存dispatch_once是线程平安的,保障块代码中的内容只会执行一次串行队列增加的同步操作会死锁,然而会执行嵌套同步操作之前的代码; 并行队列增加的同步操作不会死锁都在主线程执行; 全局队列增加的同步操作不会死锁。 同步操作 最次要的目标,阻塞并行队列工作的执行,只有以后的同步工作执行结束之后,后边的工作才会执行,利用: 用户登录 队列和线程的区别:队列: 是治理线程的,相当于线程池,能治理线程什么时候执行。 队列分为串行队列和并行队列串行队列: 队列中的线程按程序执行(不会同时执行) 并行队列: 队列中的线程会并发执行,可能会有一个疑难,队列不是先进先出吗,如果前面的工作执行完了,怎么进来的了。这里须要强调下,工作执行结束了,不肯定出队列。只有后面的工作执行完了,才会出队列,也就是说你即便执行结束了,也必须等后面的工作执行结束出队列,才能够进来。 主线程队列和GCD创立的队列也是有区别的。主线程队列和GCD创立的队列是不同的。在GCD中创立的队列优先级没有主队列高,所以在GCD中的串行队列开启同步工作外面没有嵌套工作是不会阻塞主线程,只有一种可能导致死锁,就是串行队列里,嵌套开启工作,有可能会导致死锁。主线程队列中不能开启同步,会阻塞主线程。只能开启异步工作,开启异步工作也不会开启新的线程,只是升高异步工作的优先级,让cpu闲暇的时候才去调用。而同步工作,会抢占主线程的资源,会造成死锁。线程:外面有十分多的工作(同步,异步)同步与异步的区别:同步工作优先级高,在线程中有执行程序,不会开启新的线程。 异步工作优先级低,在线程中执行没有程序,看cpu闲不闲。 在主队列中不会开启新的线程,其余队列会开启新的线程。 主线程队列留神:  上面代码执行程序 1111 2222主队列异步<NSThread: 0x8e12690>{name = (null), num = 1}在主队列开启异步工作,不会开启新的线程而是仍然在主线程中执行代码块中的代码。为什么不会阻塞线程?主队列开启异步工作,尽管不会开启新的线程,然而他会把异步工作升高优先级,等闲着的时候,就会在主线程上执行异步工作。在主队列开启同步工作,为什么会阻塞线程?在主队列开启同步工作,因为主队列是串行队列,外面的线程是有程序的,先执行完一个线程才执行下一个线程,而主队列始终就只有一个主线程,主线程是不会执行结束的,因为他是有限循环的,除非敞开应用程序。因而在主线程开启一个同步工作,同步工作会想抢占执行的资源,而主线程工作始终在执行某些操作,不肯撒手。两个的优先级都很高,最终导致死锁,阻塞线程了。- (void)main_queue_deadlock{    dispatch_queue_t q = dispatch_get_main_queue();        NSLog(@"1111");        dispatch_async(q, ^{        NSLog(@"主队列异步 %@", [NSThread currentThread]);    });        NSLog(@"2222");        // 上面会造成线程死锁    //    dispatch_sync(q, ^{    //        NSLog(@"主队列同步 %@", [NSThread currentThread]);    //    }); }并行队列里开启同步工作是有执行程序的,只有异步才没有程序;串行队列开启异步工作,是有程序的串行队列开启异步工作后嵌套同步工作造成死锁 - (void)serial_queue_deadlock2 {     dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL);             dispatch_async(q, ^{         NSLog(@"异步工作 %@", [NSThread currentThread]);         // 上面开启同步造成死锁:因为串行队列中线程是有执行程序的,须要等下面开启的异步工作执行结束,才会执行上面开启的同步工作。而下面的异步工作还没执行完,要到上面的大括号才算执行结束,而上面的同步工作曾经在抢占资源了,就会产生死锁。         dispatch_sync(q, ^{             NSLog(@"同步工作 %@", [NSThread currentThread]);         });     });串行队列开启同步工作后嵌套同步工作造成死锁- (void)serial_queue_deadlock1 {     dispatch_queue_t q = dispatch_queue_create("cn.itcast.gcddemo", DISPATCH_QUEUE_SERIAL);         dispatch_sync(q, ^{         NSLog(@"同步工作 %@", [NSThread currentThread]);         // 上面开启同步造成死锁:因为串行队列中线程是有执行程序的,须要等下面开启的同步工作执行结束,才会执行上面开启的同步工作。而下面的同步工作还没执行完,要到上面的大括号才算执行结束,而上面的同步工作曾经在抢占资源了,就会产生死锁。         dispatch_sync(q, ^{             NSLog(@"同步工作 %@", [NSThread currentThread]);         });             });     NSLog(@"同步工作 %@", [NSThread currentThread]); } 串行队列开启同步工作后嵌套异步工作不造成死锁网络:PUT办法PUT 1) 文件大小无限度2) 能够覆盖文件 ...

June 25, 2021 · 3 min · jiezi

关于ios:如何通过5道题全面考察技术候选人

资深 iOS 开发工程师教你5 道题全面考查候选人hello 大家好,本期是咱们伯乐相“码”专栏第三期节目,明天给大家分享的是一位7年资深的IOS开发工程师如何简略通过5道题来全面考查候选人,话不多说让我来看看吧 https://www.bilibili.com/vide... 感激大家关注也欢送大家继续和咱们专栏节目进行交换互动! https://www.showmebug.com

June 24, 2021 · 1 min · jiezi

关于ios:Moya-书写简化思路-2-enum-的-task

应用 Moya 做 iOS 的网络申请, 我的项目中有一百多个网络申请办法,就建设对应的 enum 条目 其中 task 的填写,个别 case 下,再这样 enum NetHud{ case modify_content(R_create_content) // ...}extension NetHud{ public var task: Task { case .modify_content(dat): return .requestJSONEncodable(dat) // ... // 重复缮写 }}应用 Mirror, 革新enum NetHud{ case modify_content(R_create_content) // ...}extension NetHud{ var obj: Encodable?{ let mirror = Mirror(reflecting: self) if let val = mirror.children.first?.value as? Encodable{ return val } else{ return nil } } public var task: Task { default: if let dat = obj{ return .requestJSONEncodable(dat) } else{ // 不会走, // 省略书写 return .requestPlain } } }}

June 24, 2021 · 1 min · jiezi

关于ios:Moya-书写简化思路-enum

应用 Moya 做 iOS 的网络申请, 我的项目中有一百多个网络申请办法,就建设对应的 enum 条目 其中 path 的填写,个别 case 下,再缮写一遍 "/" + String( 具体的 case )长这样 public enum Xxx { case zen case userProfile(String) case userRepositories(String) // ... // 省略一百条 +}extension Xxx: TargetType { public var baseURL: URL { return URL(string: "https://api.xxx.com")! } public var path: String { switch self { case .zen: return "/zen" case .userProfile(let name): return "/userProfile" case .userRepositories(let name): return "/userRepositories" // ... // 省略一百条 + } } // ... // 还有好几项, header 、 task }本文通过 Mirror 个性,优化 path 的书写这种状况下 ...

June 23, 2021 · 1 min · jiezi