get the iOS device CPU architecture in runtime
from:http://stackoverflow.com/questions/19859388/how-can-i-get-the-ios-device-cpu-architecture-in-runtime
#include <sys/types.h>
#include <sys/sysctl.h>
#include <mach/machine.h>
NSString *getCPUType(void)
{
NSMutableString *cpu = [[NSMutableString alloc] init];
size_t size;
cpu_type_t type;
cpu_subtype_t subtype;
size = sizeof(type);
sysctlbyname("hw.cputype", &type, &size, NULL, 0);
size = sizeof(subtype);
sysctlbyname("hw.cpusubtype", &subtype, &size, NULL, 0);
// values for cputype and cpusubtype defined in mach/machine.h
if (type == CPU_TYPE_X86)
{
[cpu appendString:@"x86 "];
// check for subtype ...
} else if (type == CPU_TYPE_ARM)
{
[cpu appendString:@"ARM"];
switch(subtype)
{
case CPU_SUBTYPE_ARM_V7:
[cpu appendString:@"V7"];
break;
// ...
}
}
return [cpu autorelease];
}
- (NSString *)getCPUType {
NSMutableString *cpu = [[NSMutableString alloc] init];
size_t size;
cpu_type_t type;
cpu_subtype_t subtype;
size = sizeof(type);
sysctlbyname("hw.cputype", &type, &size, NULL, 0);
size = sizeof(subtype);
sysctlbyname("hw.cpusubtype", &subtype, &size, NULL, 0);
// values for cputype and cpusubtype defined in mach/machine.h
if (type == CPU_TYPE_X86_64) {
[cpu appendString:@"x86_64"];
} else if (type == CPU_TYPE_X86) {
[cpu appendString:@"x86"];
} else if (type == CPU_TYPE_ARM) {
[cpu appendString:@"ARM"];
switch(subtype)
{
case CPU_SUBTYPE_ARM_V6:
[cpu appendString:@"V6"];
break;
case CPU_SUBTYPE_ARM_V7:
[cpu appendString:@"V7"];
break;
case CPU_SUBTYPE_ARM_V8:
[cpu appendString:@"V8"];
break;
}
}
return cpu;
}
ReactiveCocoa(RAC)框架
以下是RAC的Github主页:ReactiveCocoa
以及官方给出的用法链接
本文转载于:http://yimouleng.com/2015/12/20/ios-ReactiveCocoa/
##第一部分 简单使用
文本框事件
原来我们在使用textFiled
的时候我们需要写到
[textField addTarget:self action:@selector(textChanged:) forControlEvents:UIControlEventEditingChanged];
然后实现textChanged:方法,在RAC中,对于文本框的监听,是非常简单的一件事情,看如下代码:
UITextField * textField = ({
UITextField * textField = [[UITextField alloc]init];
textField.backgroundColor = [UIColor cyanColor];
textField;
});
[self.view addSubview:textField];
@weakify(self); // __weak __typeof__(self) self_weak_ = self;
[textField mas_makeConstraints:^(MASConstraintMaker *make) {
@strongify(self); // __strong __typeof__(self) self = self_weak_;
make.size.mas_equalTo(CGSizeMake(180, 40));
make.center.equalTo(self.view);
}];
[[textField rac_signalForControlEvents:UIControlEventEditingChanged]
subscribeNext:^(id x) {
LxDBAnyVar(x);
}];
[textField.rac_textSignal subscribeNext:^(NSString *x) {
LxDBAnyVar(x);
}];
打印结果:
📍__31-[ViewController textFiledTest]_block_invoke_2 + 215🎈 x = 12
📍__31-[ViewController textFiledTest]_block_invoke241 + 211🎈 x = <UITextField: 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '123'; clipsToBounds = YES; opaque = NO; gestureRecognizers = <NSArray: 0x7fe810f58fb0>; layer = <CALayer: 0x7fe810c51600>>
📍__31-[ViewController textFiledTest]_block_invoke_2 + 215🎈 x = 123
📍__31-[ViewController textFiledTest]_block_invoke241 + 211🎈 x = <UITextField: 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '1231'; clipsToBounds = YES; opaque = NO; gestureRecognizers = <NSArray: 0x7fe810f58fb0>; layer = <CALayer: 0x7fe810c51600>>
📍__31-[ViewController textFiledTest]_block_invoke_2 + 215🎈 x = 1231
📍__31-[ViewController textFiledTest]_block_invoke241 + 211🎈 x = <UITextField: 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '12312'; clipsToBounds = YES; opaque = NO; gestureRecognizers = <NSArray: 0x7fe810f58fb0>; layer = <CALayer: 0x7fe810c51600>>
📍__31-[ViewController textFiledTest]_block_invoke_2 + 215🎈 x = 12312
📍__31-[ViewController textFiledTest]_block_invoke241 + 211🎈 x = <UITextField: 0x7fe810c51a90; frame = (97.5 313.5; 180 40); text = '123123'; clipsToBounds = YES; opaque = NO; gestureRecognizers = <NSArray: 0x7fe810f58fb0>; layer = <CALayer: 0x7fe810c51600>>
📍__31-[ViewController textFiledTest]_block_invoke_2 + 215🎈 x = 123123
我们很容易的监听到textFiled中发生的变化,其中x的类型默认为id类型, 我们已知它的类型的时候我们可以将其改变,就像上面代码,将id改成了NSString类型。
手势
self.view.userInteractionEnabled = YES;
UITapGestureRecognizer * tap = [[UITapGestureRecognizer alloc]init];
[[tap rac_gestureSignal] subscribeNext:^(UITapGestureRecognizer * tap) {
LxDBAnyVar(tap);
}];
[self.view addGestureRecognizer:tap];
为了方便,我们直接添加到self.view上,点击屏幕,得到打印结果:
📍__29-[ViewController gestureTest]_block_invoke + 184🎈 tap = <UITapGestureRecognizer: 0x7fa2e3e1f9f0; state = Ended; view = <UIView 0x7fa2e3e20b70>; target= <(action=sendNext:, target=<RACPassthroughSubscriber 0x7fa2e3c064f0>)>>
通知
[[[NSNotificationCenter defaultCenter] rac_addObserverForName:UIApplicationDidEnterBackgroundNotification object:nil] subscribeNext:^(NSNotification * notification) {
LxDBAnyVar(notification);
}];
我们建立了一个通知,叫做进入后台, 当程序进入后台的时候通知相应,当我们用RAC写通知的时候,我们有一个好处,就是不用removeObserver通知,因为RAC通知的监听者师RAC自己,它会帮你管理释放方法。可以看方法实现如下:
- (RACSignal *)rac_addObserverForName:(NSString *)notificationName object:(id)object {
@unsafeify(object);
return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
@strongify(object);
id observer = [self addObserverForName:notificationName object:object queue:nil usingBlock:^(NSNotification *note) {
[subscriber sendNext:note];
}];
return [RACDisposable disposableWithBlock:^{
[self removeObserver:observer];
}];
}] setNameWithFormat:@"-rac_addObserverForName: %@ object: <%@: %p>", notificationName, [object class], object];
###定时器
//1. 延迟某个时间后再做某件事
[[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{
LxPrintAnything(rac);
}];
//2. 每间隔多长时间做一件事
[[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]]subscribeNext:^(NSDate * date) {
LxDBAnyVar(date);
}];
这是定时器最常用的两种写法,第一种方法,延迟时间去做某件事,更改afterDelay的属性。
第二种方法,每间隔多长时间做一件事,更改interval属性。
###代理
UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:@"RAC" message:@"ReactiveCocoa" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Ensure", nil];
[[self rac_signalForSelector:@selector(alertView:clickedButtonAtIndex:) fromProtocol:@protocol(UIAlertViewDelegate)] subscribeNext:^(RACTuple * tuple) {
LxDBAnyVar(tuple);
LxDBAnyVar(tuple.first);
LxDBAnyVar(tuple.second);
LxDBAnyVar(tuple.third);
}];
[alertView show];
// 更简单的方式:
[[alertView rac_buttonClickedSignal]subscribeNext:^(id x) {
LxDBAnyVar(x);
}];
用RAC去写代理的时候,会有局限,只能取代没有返回值的代理方法,什么是没有返回值的代理呢?比如说tableView的代理方法:
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
这两个方法一个返回的是CGFloat,一个是void,RAC只能取代void的代理。
###KVO
UIScrollView * scrollView = [[UIScrollView alloc]init];
scrollView.delegate = (id<UIScrollViewDelegate>)self;
[self.view addSubview:scrollView];
UIView * scrollViewContentView = [[UIView alloc]init];
scrollViewContentView.backgroundColor = [UIColor yellowColor];
[scrollView addSubview:scrollViewContentView];
@weakify(self);
[scrollView mas_makeConstraints:^(MASConstraintMaker *make) {
@strongify(self);
make.edges.equalTo(self.view).insets(UIEdgeInsetsMake(80, 80, 80, 80));
}];
[scrollViewContentView mas_makeConstraints:^(MASConstraintMaker *make) {
@strongify(self);
make.edges.equalTo(scrollView);
make.size.mas_equalTo(CGSizeMake(CGRectGetWidth(self.view.frame), CGRectGetHeight(self.view.frame)));
}];
[RACObserve(scrollView, contentOffset) subscribeNext:^(id x) {
LxDBAnyVar(x);
}];
用RAC写KVO的好处就是方法简单,keypath有代码提示。
##第二部分 进阶
###信号
- (RACSignal *)loginSignal
{
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
RACDisposable * schedulerDisposable = [[RACScheduler mainThreadScheduler]afterDelay:2 schedule:^{
if (arc4random()%10 > 1) {
[subscriber sendNext:@"Login response"];
[subscriber sendCompleted];
}
else {
[subscriber sendError:[NSError errorWithDomain:@"LOGIN_ERROR_DOMAIN" code:444 userInfo:@{}]];
}
}];
return [RACDisposable disposableWithBlock:^{
[schedulerDisposable dispose];
}];
}];
}
RAC的核心就是RACSignal,也就是信号,我们可以直接创建信号createSignal,并发送它sendNext,当信号完成后我们同时用dispose方法销毁它。发送信号,我们同时也要订阅信号,订阅信号代码如下:
[signal subscribeNext:^(id x) {
LxDBAnyVar(x);
} error:^(NSError *error) {
LxDBAnyVar(error);
} completed:^{
LxPrintAnything(completed);
}];
在信号发送的时候, 错误的时候,以及完成的时候,我们都可以得到相应。
##信号的处理
###map (映射)
UITextField * textField = ({
UITextField * textField = [[UITextField alloc]init];
textField.backgroundColor = [UIColor cyanColor];
textField;
});
[self.view addSubview:textField];
@weakify(self); // __weak __typeof__(self) self_weak_ = self;
[textField mas_makeConstraints:^(MASConstraintMaker *make) {
@strongify(self); // __strong __typeof__(self) self = self_weak_;
make.size.mas_equalTo(CGSizeMake(180, 40));
make.center.equalTo(self.view);
}];
[[textField.rac_textSignal map:^id(NSString *text) {
LxDBAnyVar(text);
return @(text.length);
}] subscribeNext:^(id x) {
LxDBAnyVar(x);
}];
map这个函数,在这里不是地图的意思,代表映射。map能做的事情就是把监听的rac_textSignal所返回的值,替换成别的就像上面代码中的text的长度。
###filter
为了方便演示,我就不再赋值创建textField的代码了,请到Demo中查看
[[[textField.rac_textSignal map:^id(NSString *text) {
LxDBAnyVar(text);
return @(text.length);
}]filter:^BOOL(NSNumber *value) {
return value.integerValue > 3;
}] subscribeNext:^(id x) {
LxDBAnyVar(x);
}];
filter是个BOOL值,它代表的是一个条件,当这个条件发生的时候才会作出相应,比如上面代码中,当长度大于3的时候,才会打印x的值。
###delay
//创建信号
RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[subscriber sendNext:@"rac"];
[subscriber sendCompleted];
return nil;
}]delay:2];
LxPrintAnything(start);
//创建订阅者
[signal subscribeNext:^(id x) {
LxDBAnyVar(x);
}];
delay的作用就是延迟,或者说等待,如上,等待2秒之后打印了x。
###startWith
RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// [subscriber sendNext:@"123"];//startWith:@"123"等同于这句话 也就是第一个发送,主要是位置
[subscriber sendNext:@"rac"];
[subscriber sendCompleted];
return nil;
}]startWith:@"123"];
LxPrintAnything(start);
//创建订阅者
[signal subscribeNext:^(id x) {
LxDBAnyVar(x);
}];
startWith也就是最开始的意思,看以上代码 startWith:@"123"等同于[subscriber sendNext:@"123"] 也就是第一个发送,主要是位置.
###timeOut
[[[RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
[[RACScheduler mainThreadScheduler]afterDelay:3 schedule:^{
[subscriber sendNext:@"rac"];
[subscriber sendCompleted];
}];
return nil;
}] timeout:2 onScheduler:[RACScheduler mainThreadScheduler]]
subscribeNext:^(id x) {
LxDBAnyVar(x);
} error:^(NSError *error) {
LxDBAnyVar(error);
} completed:^{
LxPrintAnything(completed);
}];
```
上面代码的意思就是,我设置了超时限制为(timeout)2秒钟,但是我代码延迟3秒钟发送,超时了,所以这条信息发生错误,会走error的方法。 这种情况可以用在封装http client中,当然你可能遇到别的需求,也需要它。
###take – skip
RACSignal * signal = [[RACSignal createSignal:^RACDisposable *(id
[subscriber sendNext:@"rac1"];
[subscriber sendNext:@"rac2"];
[subscriber sendNext:@"rac3"];
[subscriber sendNext:@"rac4"];
[subscriber sendCompleted];
return nil;
}]take:2];//Skip
[signal subscribeNext:^(id x) {
LxDBAnyVar(x);
}];
比如说我们发送了很多次请求
> take表示我们只取前两次
skip表示跳过前两次
takeLast表示倒数的前两次
takeUntil这个值比较特殊,他后面的参数是个信号,它的意思是,当takeUntil发送这个信号的时候,上面的发送信号就会停止发送。
接下来是几个block回调方法
> takeWhileBlock BOOL值,意思是当返回YES的时候,订阅者才能收到信号
skipWhileBlock BOOL值,意思是当返回YES的时候,订阅者就会跳过信号,NO的时候才接受
skipUntilBlock BOOL值,意思是 返回NO的时候,不会收到消息, 直到返回YES的时候才开始收消息。
###即时搜索优化 (throttle,distinctUntilChanged,ignore)
UITextField * textField = [[UITextField alloc]init];
textField.backgroundColor = [UIColor cyanColor];
[self.view addSubview:textField];
@weakify(self);
[textField mas_makeConstraints:^(MASConstraintMaker *make) {
@strongify(self);
make.size.mas_equalTo(CGSizeMake(180, 40));
make.center.equalTo(self.view);
}];
//throttle 后面是个时间 表示rac_textSignal发送消息,0.3秒内没有再次发送就会相应,若是0.3内又发送消息了,便会在新的信息处重新计时
//distinctUntilChanged 表示两个消息相同的时候,只会发送一个请求
//ignore 表示如果消息和ignore后面的消息相同,则会忽略掉这条消息,不让其发送
[[[[[[textField.rac_textSignal throttle:0.3] distinctUntilChanged] ignore:@""] map:^id(id value) {
return [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
// network request
[subscriber sendNext:value];
[subscriber sendCompleted];
return [RACDisposable disposableWithBlock:^{
// cancel request
}];
}];
}]switchToLatest] subscribeNext:^(id x) {
LxDBAnyVar(x);
}];
以上代码,是用textField模拟一个即时搜索优化的功能,其中参数如下:
> throttle 后面是个时间 表示rac_textSignal发送消息,0.3秒内没有再次发送就会相应,若是0.3内又发送消息了,便会在新的信息处重新计时
distinctUntilChanged 表示两个消息相同的时候,只会发送一个请求
ignore 表示如果消息和ignore后面的消息相同,则会忽略掉这条消息,不让其发送
这样做,是不是给服务器减小了很多的压力,更是节省了我们大量的代码。 其中我们用map建立了一个新的信号,我们知道textField的改变是一个信号, map就是在这个信号上,又加了一个信号,即signal of signals。
订阅者所打印的消息x则是,map发出的信号。我们可以再map中发送新的信号,以及取消信号disposable.
当我们用map发送信号的时候,我们则需要使用 switchToLatest这个参数来获取最后一个信号,也就是我们最后所打印的x,就是map最后发错的这个信号。
###repeat
[[[[[RACSignal createSignal:^RACDisposable *(id
[subscriber sendNext:@"rac"];
[subscriber sendCompleted];
return nil;
}]delay:1]repeat]take:3] subscribeNext:^(id x) {
LxDBAnyVar(x);
} completed:^{
LxPrintAnything(completed);
}];
repeat,顾名思义,就是重复发送这条消息,当我们在后面添加了delay和take的时候,意思就是每隔1秒发送一次这条消息,发送3次后停止。
###merge – concat – zipWith
RACSignal * signalA = [RACSignal createSignal:^RACDisposable *(id
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
LxPrintAnything(a);
[subscriber sendNext:@"a"];
[subscriber sendCompleted];
});
return nil;
}];
RACSignal * signalB = [RACSignal createSignal:^RACDisposable *(id
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(3 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
LxPrintAnything(b);
[subscriber sendNext:@"b"];
[subscriber sendCompleted];
});
return nil;
}];
[[RACSignal merge:@[signalA, signalB]]subscribeNext:^(id x) {
LxDBAnyVar(x);
}];
我们创建了两个请求,A和B,用GCD的方法A延迟两秒钟,B延迟了3秒钟,我们用merge方法合并了A和B,打印结果为
📍__23-[ViewController merge]_block_invoke_2 + 66🎈 a
📍__23-[ViewController merge]_block_invoke29 + 87🎈 x = a
📍__23-[ViewController merge]_block_invoke_215 + 77🎈 b
📍__23-[ViewController merge]_block_invoke29 + 87🎈 x = b
也就是A和B不管谁发送都会打印x,简单的说就是A和B的打印方法用的是同一个。他们之间关系是独立的,如果A发送失败,B依然会执行。
当我们用concat方法链接A和B之后,意思就是当A执行完了之后才会执行B,他们之间是依赖的关系,如果A发送失败,B也不会执行。
请注意合并(merge)和链接(concat)的区别。
zipWith,当用zipWith链接A和B的时候,只有在A.B每隔都至少发送过一次消息的时候才会执行zipWith的方法,它的返回值是一个集合,也就是数组,同时包含了A和B的打印结果。
zipWith的写法等同于 :
[[RACSignal combineLatestWith:@[signalA, signalB]subscribeNext:^(id x) {
LxDBAnyVar(x);
}];
亦或者
[[RACSignal combineLatest:@[signalA, signalB]]subscribeNext:^(id x) {
LxDBAnyVar(x);
}];
但是使用`combineLatest`,可以再后面添加更多的信号.
##RAC(<#TARGET, …#>) 宏
//button setBackgroundColor:forState:
UIButton * button = [UIButton buttonWithType:UIButtonTypeCustom];
[self.view addSubview:button];
@weakify(self);
[button mas_makeConstraints:^(MASConstraintMaker *make) {
@strongify(self);
make.size.mas_equalTo(CGSizeMake(180, 40));
make.center.equalTo(self.view);
}];
RAC(button, backgroundColor) = [RACObserve(button, selected) map:^UIColor *(NSNumber * selected) {
return [selected boolValue] ? [UIColor redColor] : [UIColor greenColor];
}];
[[button rac_signalForControlEvents:UIControlEventTouchUpInside]subscribeNext:^(UIButton * btn) {
btn.selected = !btn.selected;
}];
比如Btn的设置背景颜色的属性,OC中并没有button setBackgroundColor:forState:这种方法,我们不能直接设置其选中后的颜色。在RAC中,则可以很简单的改变BTN的背景颜色。不得不说RAC的简单和强大。
做一个秒表
UILabel * label = ({
UILabel * label = [[UILabel alloc]init];
label.backgroundColor = [UIColor cyanColor];
label;
});
[self.view addSubview:label];
@weakify(self);
[label mas_makeConstraints:^(MASConstraintMaker *make) {
@strongify(self);
make.size.mas_equalTo(CGSizeMake(240, 40));
make.center.equalTo(self.view);
}];
RAC(label, text) = [[RACSignal interval:1 onScheduler:[RACScheduler mainThreadScheduler]] map:^NSString *(NSDate * date) {
return date.description;
}];
只有这么多代码,我们便可以完美的做一个秒表,是否很cool?

当我们大量使用RAC写代码的时候,会把一个个事件封装成一个个信号,通过触发信号,订阅这个信号来返回各种信息。RAC使我们的代码耦合性根底,聚合性更高。
若有不懂得地方可以留言,若有写错的地方,请及时与我联系,可以留言或者Email等。
文本所用的Demo,下载地址 [戳这里](https://github.com/yimouleng/RACDemo).
App Transport Security
App Transport Security is a feature that improves the security of connections between an app and web services. The feature consists of default connection requirements that conform to best practices for secure connections.
App Transport Security(ATS)是Apple为提高系统及应用安全性而在iOS 9和OS X EI Capitan中引入的新特性,必然,出于安全性的考虑,在新发布的watchOS 2系统中也会适用。
一旦开启ATS后,应用所有的网络请求将会自动转换为HTPPS传输,且采用一系列配置要求来保证数据传输的安全性,包括:
- Transport Layer Security协议版本要求TLS1.2以上;
- 服务的Ciphers配置要求支持Forward Secrecy等;
- 证书签名算法符合ATS要求等。
这些配置项在升级服务器支持HTTPS过程中都需要严格遵守的,否则就会导致你的HTTPS服务在iOS 9系统中连接仍是失效的。
如果你的App的服务也在升级以适配ATS要求,可以使用如下的方式进行校验:
在OS X EI Capitan系统的终端中通过nscurl命令来诊断检查你的HTTPS服务配置是否满足Apple的ATS要求: $ nscurl --verbose --ats-diagnostics https://<your_server_domain>。
当然,你也可以参考Apple提供官方指南 App Transport Security Technote进行服务的升级配置以满足ATS的要求。
Apple虽然希望开发者可以积极的参与并为系统及应用安全共同努力,但官方仍提供了一些参考配置去禁用ATS功能或降低ATS的安全性要求。
开发者可以在App的Info.plist中添加NSAppTransportSecurity的相关配置,用以禁用ATS或者添加白名单,可用的配置参数如下:
- NSAllowsArbitraryLoads - 设置true即支持所有HTTP请求
- NSExceptionDomains - 添加白名单
- NSExceptionMinimumTLSVersion - 白名单指定域名支持的TLS版本
- NSExceptionRequiresForwardSecrecy - 白名单指定域名是否支持Forward Secrecy
- NSExceptionAllowsInsecureHTTPLoads - 白名单指定域名禁用ATS
- NSThirdPartyExceptionMinimumTLSVersion - 白名单指定第三方服务域名最低支持的TLS版本
- NSThirdPartyExceptionRequiresForwardSecrecy - 白名单指定第三方服务域名是否支持Forward Secrecy
- NSThirdPartyExceptionAllowsInsecureHTTPLoads - 白名单指定第三方域名禁用ATS
Copyright © 2015 Powered by MWeb, 豫ICP备09002885号-5