ios开发的框架,ios开发架构设计

iOS开发之CoreLocaiton框架使用(指南针)

1.准备一张指南针的图片(下面图片可以使用)

网站的建设创新互联公司专注网站定制,经验丰富,不做模板,主营网站定制开发.小程序定制开发,H5页面制作!给你焕然一新的设计体验!已为酒楼设计等企业提供专业服务。

2.导入CoreLocation框架以及对应的主头文件 并且设置代理

3.懒加载创建CLLocationManager对象并设置代理

4. 调用方法, 开始获取设备朝向   

5. 在对应的代理方法中获取设备朝向信息

刚刚,阿里开源 iOS 协程开发框架 coobjc!

阿里妹导读:刚刚,阿里巴巴正式对外开源了基于 Apache 2.0 协议的协程开发框架 coobjc,开发者们可以在 Github 上自主下载。

coobjc是为iOS平台打造的开源协程开发框架,支持Objective-C和Swift,同时提供了cokit库为Foundation和UIKit中的部分API提供了 协程 化支持,本文将为大家详细介绍coobjc的设计理念及核心优势。

从2008年第一个iOS版本发布至今的11年时间里,iOS的异步编程方式发展缓慢。

基于 Block 的异步编程回调是目前 iOS 使用最广泛的异步编程方式,iOS 系统提供的 GCD 库让异步开发变得很简单方便,但是基于这种编程方式的缺点也有很多,主要有以下几点:

针对多线程以及尤其引发的各种崩溃和性能问题,我们制定了很多编程规范、进行了各种新人培训,尝试降低问题发生的概率,但是问题依然很严峻,多线程引发的问题占比并没有明显的下降,异步编程本来就是很复杂的事情,单靠规范和培训是难以从根本上解决问题的,需要有更加好的编程方式来解决。

上述问题在很多系统和语言开发中都可能会碰到,解决问题的标准方式就是使用协程,C#、Kotlin、Python、Javascript 等热门语言均支持协程极其相关语法,使用这些语言的开发者可以很方便的使用协程及相关功能进行异步编程。

2017 年的 C++ 标准开始支持协程,Swift5 中也包含了协程相关的标准,从现在的发展趋势看基于协程的全新的异步编程方式,是我们解决现有异步编程问题的有效的方式,但是苹果基本已经不会升级 Objective-C 了,因此使用Objective-C的开发者是无法使用官方的协程能力的,而最新 Swift 的发布和推广也还需要时日,为了让广大iOS开发者能快速享受到协程带来的编程方式上的改变,手机淘宝架构团队基于长期对系统底层库和汇编的研究,通过汇编和C语言实现了支持 Objective-C 和 Swift 协程的完美解决方案 —— coobjc。

核心能力

内置系统扩展库

coobjc设计

最底层是协程内核,包含了栈切换的管理、协程调度器的实现、协程间通信channel的实现等。

中间层是基于协程的操作符的包装,目前支持async/await、Generator、Actor等编程模型。

最上层是对系统库的协程化扩展,目前基本上覆盖了Foundation和UIKit的所有IO和耗时方法。

核心实现原理

协程的核心思想是控制调用栈的主动让出和恢复。一般的协程实现都会提供两个重要的操作:

我们基于线程的代码执行时候,是没法做出暂停操作的,我们现在要做的事情就是要代码执行能够暂停,还能够再恢复。 基本上代码执行都是一种基于调用栈的模型,所以如果我们能把当前调用栈上的状态都保存下来,然后再能从缓存中恢复,那我们就能够实现yield和 resume。

实现这样操作有几种方法呢?

上述第三种和第四种只是能过做到跳转,但是没法保存调用栈上的状态,看起来基本上不能算是实现了协程,只能算做做demo,第五种除非官方支持,否则自行改写编译器通用性很差。而第一种方案的 ucontext 在iOS上是废弃了的,不能使用。那么我们使用的是第二种方案,自己用汇编模拟一下 ucontext。

模拟ucontext的核心是通过getContext和setContext实现保存和恢复调用栈。需要熟悉不同CPU架构下的调用约定(Calling Convention). 汇编实现就是要针对不同cpu实现一套,我们目前实现了 armv7、arm64、i386、x86_64,支持iPhone真机和模拟器。

说了这么多,还是看看代码吧,我们从一个简单的网络请求加载图片功能来看看coobjc到底是如何使用的。

下面是最普通的网络请求的写法:

下面是使用coobjc库协程化改造后的代码:

原本需要20行的代码,通过coobjc协程化改造后,减少了一半,整个代码逻辑和可读性都更加好,这就是coobjc强大的能力,能把原本很复杂的异步代码,通过协程化改造,转变成逻辑简洁的顺序调用。

coobjc还有很多其他强大的能力,本文对于coobjc的实际使用就不过多介绍了,感兴趣的朋友可以去官方github仓库自行下载查看。

我们在iPhone7 iOS11.4.1的设备上使用协程和传统多线程方式分别模拟高并发读取数据的场景,下面是两种方式得到的压测数据。

从上面的表格我们可以看到使用在并发量很小的场景,由于多线程可以完全使用设备的计算核心,因此coobjc总耗时要比传统多线程略高,但是由于整体耗时都很小,因此差异并不明显,但是随着并发量的增大,coobjc的优势开始逐渐体现出来,当并发量超过1000以后,传统多线程开始出现线程分配异常,而导致很多并发任务并没有执行,因此在上表中显示的是大于20秒,实际是任务已经无法正常执行了,但是coobjc仍然可以正常运行。

我们在手机淘宝这种超级App中尝试了协程化改造,针对部分性能差的页面,我们发现在滑动过程中存在很多主线程IO调用、数据解析,导致帧率下降严重,通过引入coobjc,在不改变原有业务代码的基础上,通过全局hook部分IO、数据解析方法,即可让原来在主线程中同步执行的IO方法异步执行,并且不影响原有的业务逻辑,通过测试验证,这样的改造在低端机(iPhone6及以下的机器)上的帧率有20%左右的提升。

简明

易用

清晰

性能

程序是写来给人读的,只会偶尔让机器执行一下。——Abelson and Sussman

基于协程实现的编程范式能够帮助开发者编写出更加优美、健壮、可读性更强的代码。

协程可以帮助我们在编写并发代码的过程中减少线程和锁的使用,提升应用的性能和稳定性。

本文作者:淘宝技术

iOS开发——最简单web容器化框架

既然要承载 web 页面,一个原生的 WebView 必不可少。在 iOS 中,目前已经有两款高性能、功能齐全的 web 浏览器,UIWebView (=2.0)和 WKWebView(=7.0)。

当然,两种 web 浏览器选其一即可。网上有很多文章,包括我之前已经发表的博文中,都介绍过这两种浏览器,读者可以根据自己的需要选择。

就目前的情况看,UIWebView 发展了很多年,目前市面上大部分的 web 页面也都支持这样的浏览器,因此很多公司在选择的时候都使用这个,但是,我们知道,WKWebView 有太多改善前者的优点,而且也是苹果官方提倡大家使用的,为了性能,为了更多的特性,建议初次搭建的朋友采用 WKWebView。

为了实现 h5 与 native 之间的互相调用,我们需要在两者之间架一层桥来实现,关于 bridge,之前的文章也有介绍。

bridge 的功能包括:native 调用 h5,h5 回调 native,h5 调用 native,native 回调 h5。

有了 bridge,h5可以使用 native 支持的更多特性,native 可以获取 h5 页面加载的信息,也可以让 web 页面动态执行一些脚本做一些事。

总之,在 web 容器框架中,这个 bridge 还是很有必要的。

嗯,这个是辅助项,做了这一步可以进一步提高 web 容器的加载性能,而且资源缓存到本地后可以做到不依赖网络,提高用户体验。

通常有两种做法,

UIWebView 使用简单,而且现在用户的手机性能也已经不再是页面展示性能的瓶颈,所以,这里介绍的依然采用 UIWebView 作为 web 浏览器。

WebViewJavascriptBridge 是一款非常强大的第三方开源 bridge 库,同时支持 UIWebView 和 WKWebView。

git 地址

NJKWebViewProgress 是一款能使 UIWebview 显示加载进度的第三方开源框架,支持代理协议处理和 progressview 展示两种功能。

git 地址

iOS Speech框架 详解

原文地址:

一、引言

    iOS10系统是一个较有突破性的系统,其在Message,Notification等方面都开放了很多实用性的开发接口。本篇博客将主要探讨iOS10中新引入的SpeechFramework框架。有个这个框架,开发者可以十分容易的为自己的App添加语音识别功能,不需要再依赖于其他第三方的语音识别服务,并且,Apple的Siri应用的强大也证明了Apple的语音服务是足够强大的,不通过第三方,也大大增强了用户的安全性。

二、SpeechFramework框架中的重要类

    SpeechFramework框架比较轻量级,其中的类并不十分冗杂,在学习SpeechFramework框架前,我们需要对其中类与类与类之间的关系有个大致的熟悉了解。

SFSpeechRecognizer:这个类是语音识别的操作类,用于语音识别用户权限的申请,语言环境的设置,语音模式的设置以及向Apple服务发送语音识别的请求。

SFSpeechRecognitionTask:这个类是语音识别服务请求任务类,每一个语音识别请求都可以抽象为一个SFSpeechRecognitionTask实例,其中SFSpeechRecognitionTaskDelegate协议中约定了许多请求任务过程中的监听方法。

SFSpeechRecognitionRequest:语音识别请求类,需要通过其子类来进行实例化。

SFSpeechURLRecognitionRequest:通过音频URL来创建语音识别请求。

SFSpeechAudioBufferRecognitionRequest:通过音频流来创建语音识别请求。

SFSpeechRecognitionResult:语音识别请求结果类。

SFTranscription:语音转换后的信息类。

SFTranscriptionSegment:语音转换中的音频节点类。

三、申请用户语音识别权限与进行语音识别请求

    开发者若要在自己的App中使用语音识别功能,需要获取用户的同意。首先需要在工程的Info.plist文件中添加一个Privacy-Speech Recognition Usage Description键,其实需要对应一个String类型的值,这个值将会在系统获取权限的警告框中显示,Info.plist文件如下图所示:

使用SFSpeechRecognize类的requestAuthorization方法来进行用户权限的申请,用户的反馈结果会在这个方法的回调block中传入,如下:

  //申请用户语音识别权限

  [SFSpeechRecognizer requestAuthorization:^(SFSpeechRecognizerAuthorizationStatus status) {   

  }];

SFSpeechRecognizerAuthorzationStatus枚举中定义了用户的反馈结果,如下:

typedef NS_ENUM(NSInteger, SFSpeechRecognizerAuthorizationStatus) {

    //结果未知 用户尚未进行选择

    SFSpeechRecognizerAuthorizationStatusNotDetermined,

    //用户拒绝授权语音识别

    SFSpeechRecognizerAuthorizationStatusDenied,

    //设备不支持语音识别功能

    SFSpeechRecognizerAuthorizationStatusRestricted,

    //用户授权语音识别

    SFSpeechRecognizerAuthorizationStatusAuthorized,

};

如果申请用户语音识别权限成功,开发者可以通过SFSpeechRecognizer操作类来进行语音识别请求,示例如下:

    //创建语音识别操作类对象

    SFSpeechRecognizer * rec = [[SFSpeechRecognizer alloc]init];

    //通过一个音频路径创建音频识别请求

    SFSpeechRecognitionRequest * request = [[SFSpeechURLRecognitionRequest alloc]initWithURL:[[NSBundle mainBundle] URLForResource:@"7011" withExtension:@"m4a"]];

    //进行请求

    [rec recognitionTaskWithRequest:request resultHandler:^(SFSpeechRecognitionResult * _Nullable result, NSError * _Nullable error) {

        //打印语音识别的结果字符串

        NSLog(@"%@",result.bestTranscription.formattedString);

    }];

四、深入SFSpeechRecognizer类

SFSpeechRecognizer类的主要作用是申请权限,配置参数与进行语音识别请求。其中比较重要的属性与方法如下:

//获取当前用户权限状态

+ (SFSpeechRecognizerAuthorizationStatus)authorizationStatus;

//申请语音识别用户权限

+ (void)requestAuthorization:(void(^)(SFSpeechRecognizerAuthorizationStatus status))handler;

//获取所支持的所有语言环境

+ (NSSetNSLocale * *)supportedLocales;

//初始化方法 需要注意 这个初始化方法将默认以设备当前的语言环境作为语音识别的语言环境

- (nullable instancetype)init;

//初始化方法 设置一个特定的语言环境

- (nullable instancetype)initWithLocale:(NSLocale *)locale NS_DESIGNATED_INITIALIZER;

//语音识别是否可用

@property (nonatomic, readonly, getter=isAvailable) BOOL available;

//语音识别操作类协议代理

@property (nonatomic, weak) idSFSpeechRecognizerDelegate delegate;

//设置语音识别的配置参数 需要注意 在每个语音识别请求中也有这样一个属性 这里设置将作为默认值

//如果SFSpeechRecognitionRequest对象中也进行了设置 则会覆盖这里的值

/*

typedef NS_ENUM(NSInteger, SFSpeechRecognitionTaskHint) {

    SFSpeechRecognitionTaskHintUnspecified = 0,    // 无定义

    SFSpeechRecognitionTaskHintDictation = 1,      // 正常的听写风格

    SFSpeechRecognitionTaskHintSearch = 2,          // 搜索风格

    SFSpeechRecognitionTaskHintConfirmation = 3,    // 短语风格

};

*/

@property (nonatomic) SFSpeechRecognitionTaskHint defaultTaskHint;

//使用回调Block的方式进行语音识别请求 请求结果会在Block中传入

- (SFSpeechRecognitionTask *)recognitionTaskWithRequest:(SFSpeechRecognitionRequest *)request

                                          resultHandler:(void (^)(SFSpeechRecognitionResult * __nullable result, NSError * __nullable error))resultHandler;

//使用代理回调的方式进行语音识别请求

- (SFSpeechRecognitionTask *)recognitionTaskWithRequest:(SFSpeechRecognitionRequest *)request

                                              delegate:(id SFSpeechRecognitionTaskDelegate)delegate;

//设置请求所占用的任务队列

@property (nonatomic, strong) NSOperationQueue *queue;

SFSpeechRecognizerDelegate协议中只约定了一个方法,如下:

//当语音识别操作可用性发生改变时会被调用

- (void)speechRecognizer:(SFSpeechRecognizer *)speechRecognizer availabilityDidChange:(BOOL)available;

    通过Block回调的方式进行语音识别请求十分简单,如果使用代理回调的方式,开发者需要实现SFSpeechRecognitionTaskDelegate协议中的相关方法,如下:

//当开始检测音频源中的语音时首先调用此方法

- (void)speechRecognitionDidDetectSpeech:(SFSpeechRecognitionTask *)task;

//当识别出一条可用的信息后 会调用

/*

需要注意,apple的语音识别服务会根据提供的音频源识别出多个可能的结果 每有一条结果可用 都会调用此方法

*/

- (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didHypothesizeTranscription:(SFTranscription *)transcription;

//当识别完成所有可用的结果后调用

- (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishRecognition:(SFSpeechRecognitionResult *)recognitionResult;

//当不再接受音频输入时调用 即开始处理语音识别任务时调用

- (void)speechRecognitionTaskFinishedReadingAudio:(SFSpeechRecognitionTask *)task;

//当语音识别任务被取消时调用

- (void)speechRecognitionTaskWasCancelled:(SFSpeechRecognitionTask *)task;

//语音识别任务完成时被调用

- (void)speechRecognitionTask:(SFSpeechRecognitionTask *)task didFinishSuccessfully:(BOOL)successfully;

SFSpeechRecognitionTask类中封装了属性和方法如下:

//此任务的当前状态

/*

typedef NS_ENUM(NSInteger, SFSpeechRecognitionTaskState) {

SFSpeechRecognitionTaskStateStarting = 0,      // 任务开始

SFSpeechRecognitionTaskStateRunning = 1,        // 任务正在运行

SFSpeechRecognitionTaskStateFinishing = 2,      // 不在进行音频读入 即将返回识别结果

SFSpeechRecognitionTaskStateCanceling = 3,      // 任务取消

SFSpeechRecognitionTaskStateCompleted = 4,      // 所有结果返回完成

};

*/

@property (nonatomic, readonly) SFSpeechRecognitionTaskState state;

//音频输入是否完成

@property (nonatomic, readonly, getter=isFinishing) BOOL finishing;

//手动完成音频输入 不再接收音频

- (void)finish;

//任务是否被取消

@property (nonatomic, readonly, getter=isCancelled) BOOL cancelled;

//手动取消任务

- (void)cancel;

关于音频识别请求类,除了可以使用SFSpeechURLRecognitionRequest类来进行创建外,还可以使用SFSpeechAudioBufferRecognitionRequest类来进行创建:

@interface SFSpeechAudioBufferRecognitionRequest : SFSpeechRecognitionRequest

@property (nonatomic, readonly) AVAudioFormat *nativeAudioFormat;

//拼接音频流

- (void)appendAudioPCMBuffer:(AVAudioPCMBuffer *)audioPCMBuffer;

- (void)appendAudioSampleBuffer:(CMSampleBufferRef)sampleBuffer;

//完成输入

- (void)endAudio;

@end

五、语音识别结果类SFSpeechRecognitionResult

    SFSpeechRecognitionResult类是语音识别结果的封装,其中包含了许多套平行的识别信息,其每一份识别信息都有可信度属性来描述其准确程度。SFSpeechRecognitionResult类中属性如下:

//识别到的多套语音转换信息数组 其会按照准确度进行排序

@property (nonatomic, readonly, copy) NSArraySFTranscription * *transcriptions;

//准确性最高的识别实例

@property (nonatomic, readonly, copy) SFTranscription *bestTranscription;

//是否已经完成 如果YES 则所有所有识别信息都已经获取完成

@property (nonatomic, readonly, getter=isFinal) BOOL final;

SFSpeechRecognitionResult类只是语音识别结果的一个封装,真正的识别信息定义在SFTranscription类中,SFTranscription类中属性如下:

//完整的语音识别准换后的文本信息字符串

@property (nonatomic, readonly, copy) NSString *formattedString;

//语音识别节点数组

@property (nonatomic, readonly, copy) NSArraySFTranscriptionSegment * *segments;

当对一句完整的话进行识别时,Apple的语音识别服务实际上会把这句语音拆分成若干个音频节点,每个节点可能为一个单词,SFTranscription类中的segments属性就存放这些节点。SFTranscriptionSegment类中定义的属性如下:

//当前节点识别后的文本信息

@property (nonatomic, readonly, copy) NSString *substring;

//当前节点识别后的文本信息在整体识别语句中的位置

@property (nonatomic, readonly) NSRange substringRange;

//当前节点的音频时间戳

@property (nonatomic, readonly) NSTimeInterval timestamp;

//当前节点音频的持续时间

@property (nonatomic, readonly) NSTimeInterval duration;

//可信度/准确度 0-1之间

@property (nonatomic, readonly) float confidence;

//关于此节点的其他可能的识别结果

@property (nonatomic, readonly) NSArrayNSString * *alternativeSubstrings;

温馨提示:SpeechFramework框架在模拟器上运行会出现异常情况,无法进行语音识别请求。会报出kAFAssistantErrorDomain的错误,还望有知道解决方案的朋友,给些建议,Thanks。


文章标题:ios开发的框架,ios开发架构设计
文章路径:http://scyanting.com/article/dsehsdo.html