0%

UIWebView上,不需要特殊处理直接加载 itunes 链接是可以直接跳转至AppStore的。

1
2
3
4
5
6
NSURL *URL = [NSURL URLWithString:@"https://itunes.apple.com/cn/app/id1013277346?mt=8"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];

self.webView = [UIWebView new];
self.webView.delegate = self;
[self.webView loadRequest:request];

但是,在WKWebView上则不行,需要在navigationDelegate中拦截,手动openURL才能跳转至AppStore。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
- (void)loadWithWKWebView
{
NSURL *URL = [NSURL URLWithString:@"https://itunes.apple.com/cn/app/id1013277346?mt=8"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];

self.wkWebView = [WKWebView new];
self.wkWebView.navigationDelegate = self;
[self.wkWebView loadRequest:request];
}

- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler
{
WKNavigationActionPolicy policy = WKNavigationActionPolicyAllow;
/* 简单判断host,真实App代码中,需要更精确判断itunes链接 */
if ([[navigationAction.request.URL host] isEqualToString:@"itunes.apple.com"] &&
[[UIApplication sharedApplication] openURL:navigationAction.request.URL])
{
policy = WKNavigationActionPolicyCancel;

}

decisionHandler(policy);
}

难以理解为啥WKWebView上不支持跳转至AppStore。
如果不处理,普通网页上链接至itunes的,点击后都无法跳转了。

之前写过一篇博客,介绍CATransaction的使用:理解CATransaction。文中提到,当需要监听动画结束时,可以利用-[CATransaction setCompletionBlock:]方法监听动画的结束,而不用修改接口参数。然而,利用这个方法监听动画结束,有一定的风险会导致 completionBlock 不被调用。

简单例子如下:

1
2
3
4
5
6
[CATransaction begin];
[CATransaction setCompletionBlock:^{
//complete block
}];
[self doAnimation]
[CATransaction commit];

一般情况下 completionBlock都会被调用。

但是当[self doAnimation]中做了一个repeatCount=HUGE_VALF的动画时,动画永远不会结束,因此, completionBlock 就永远不会被调用。

在同一个类中利用CATransaction来监听动画结束问题不大,但是做动画的代码中还会调用外面的类的话,就需要小心了。

一个int型整数,一般情况下占4个字节。那么这4个字节在内存中是怎么排列的呢?低内存地址存放的是低位字节还是高位子节呢?这就涉及到大端规则和小端规则。

这是一个特别小特别基础的知识点,在大部分的日常开发中,我们并不需要理会大小端规则。但是当涉及到跨平台网络数据传输的时候,就需要考虑大小端规则了。

大端规则(Big-Endian)

将高位字节存储在低位地址,低位字节存储在高位地址,这种存储方式成为大端规则,也称为大端序。

0xA1A2A3A4为例,使用大端规则,内存排列如下:

低地址 ——> ——> ——> ——> 高低地址
0xA1 0xA2 0xA3 0xA4
阅读全文 »

很久之前,写过一篇文章Hexo博客使用教程,介绍大概如何使用Hexo新建一个博客并部署到github上。最近抽空买了个域名和VPS,把自己的博客部署到自己的VPS上。在此分享下,正在考虑购买域名和VPS的同学可以进来看看。另外,在文章结尾,推荐一款Markdown写作App。

如果大家对于自己部署博客有什么疑问,欢迎留言讨论。

更新
2016-07-25:将DNS管理从DNSPod迁移到CloudXNS上。推荐大家使用CloudXNS。增加博客仓库介绍以及Markdown写作App推荐。

VPS

VPS可以到搬瓦工或者DigitalOcean上购买。链接就不提供了,谷歌一下很容易找到。
搬瓦工3USD一个月,DO要5USD一个月。考虑到目前博客访问量比较少,搬瓦工最低配置都够用了,所以选择了搬瓦工。迟点等VPN到期之后准备迁移到DO上,当博客主机和自己架ShadowSocks。

对着阮一峰的博客 Linux服务器的初步配置流程 ,把VPS设置好。补充一些阮一峰博客没有提到的点:

  • 终端老是报错误:

locale: Cannot set LC_CTYPE to default locale: No such file or directory
locale: Cannot set LC_ALL to default locale: No such file or director

阅读全文 »

最近中了数独的毒,没事就玩数独。玩到后面,发现其实也没啥技术含量,主要是看眼力和尝试,有点没劲。还是写代码求解下数独吧,比较不费劲。

求解数独应用到广度优先搜索和深度优先搜索算法。先简单介绍下这两个算法。最后在文末提供一个求解数据的demo。
数独所有可能的解法可以组成多叉树,遍历每一个节点,判断该节点是否是正解。

阅读全文 »

NSString是最最常用的类之一。但是时不时还是会被NSString坑到。在这里记录两个我遇到的坑。

length

length方法每天用来用去竟然也有坑!!?不信的话看看以下的代码。

1
2
3
4
NSString *str = @"您来啦啦";
NSData *data = [NSData dataWithBytes:str.UTF8String length:[str length]];
NSString *str2 = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", str2);

最后输出什么呢?当然不是您来啦啦,而是(null)。str2为nil。原因是str中包含中文,UTF8编码下,中文占多个byte。

1
2
NSLog(@"lenght: %zd", [str length]);                            // lenght: 4
NSLog(@"length of UTF8String: %ld", strlen(str.UTF8String)); // length of UTF8String: 12

正确的写法如下:

1
2
3
4
NSString *str = @"您来啦啦";
NSData *data = [NSData dataWithBytes:str.UTF8String length:[str lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
NSString *str2 = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSLog(@"%@", str2); // 您来啦啦
阅读全文 »

假设你有一张图片如下:

在不同的场景下你需要将这个图标显示成不同的颜色,特别是对于有皮肤功能的app来说,这种场景相对多一些。效果如下:

该如何实现呢?本文提供三种实现方法。如果各位看官有更好的实现方法,欢迎留言讨论。

阅读全文 »

写动画的时候偶尔会用到CATransaction来设置一些动画参数。有时候,调用一个接口做一些动画,但是接口并没有提供一个参数completionBlock,也可以利用CATransaction来添加completionBlock而不用改到别人的接口。

1
2
3
4
5
6
7
[CATransaction begin];
[CATransaction setCompletionBlock:^{
//complete block
}];
// do animation
[CATransaction commit];

⚠️ CATransaction 踩坑:completion block 没有立即调用

只知道可以这么用,但是CATransaction到底是一个什么东西呢?

CATransaction

官方文档 如是说:

CATransaction is the Core Animation mechanism for batching multiple layer-tree operations into atomic updates to the render tree. Every modification to a layer tree must be part of a transaction. Nested transactions are supported.

CATransaction是事务,用于批量提交多个对layer-tree的操作,并且是原子性的。所有对layer-tree的修改都必须包含在事务内。事务可以嵌套。

阅读全文 »

众所周知,Objective-C 中的方法调用跟C语言中的函数调用很不一样,OC 中的方法调用称为消息发送。例如,[self callMethod]称为对 self 对象发送callMethod的消息。正是这种消息发送机制,让 OC 有一个很神奇的特性,对nil进行方法调用不会导致崩溃。

本文粗略讲述下OC的方法调用,介绍下在 OC 中通过 selector 的形式调用方法,实际上都发生了什么。

performSelector

先看下 OC runtime 的源码对于 performSelector 的实现。

1
2
3
4
- (id)performSelector:(SEL)sel withObject:(id)obj1 withObject:(id)obj2 {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL, id, id))objc_msgSend)(self, sel, obj1, obj2);
}

原来 performSelector 的实现如此简单,那么完全可以自己对 NSObject 做一个扩展,支持调用需要三个参数的 selector。

1
2
3
4
- (id)performSelector:(SEL)sel withObject:(id)obj1 withObject:(id)obj2 withObject:(id)obj3 {
if (!sel) [self doesNotRecognizeSelector:sel];
return ((id(*)(id, SEL, id, id, id))objc_msgSend)(self, sel, obj1, obj2, obj3);
}

消息发送流程

performSelector实际上是调用了objc_msgSendobjc_msgSend并没有源码可以给我们参考。不过我们看下NSObject中的几个跟消息发送相关的方法。

阅读全文 »

在iOS的开发中,UITableView是最经常用到的UI组件之一。然而,UITableView却非常容易引起「NSInternalInconsistencyException(数据不一致)」的崩溃。其中,调用reloadSections时,一不留神就会引发崩溃。

reloadSections简介

当UITableView的数据源变化时,通常会调用reloadData或者reloadSections:withRowAnimation:通知UITableView刷新UI。单从UI角度考虑,两者最大的区别就是reloadData没有动画。所以,一般为用户体验考虑,我一般使用reloadSections:withRowAnimation:

reloadSections引发崩溃

调用reloadSections:withRowAnimation:方法时,UITableView会校验其他section,如果发现UITableView内记录的某section的row的数量和[dataSource tableView:numberOfRowsInSection]返回的不一致时,抛出NSInternalInconsistencyException异常。

阅读全文 »