解决iOS项目的版本兼容问题-结合宏、Category和Runtime

更新

2015-11-16

感谢微博好友@zyyy_000的评论,补充了为什么要在+ (void)load方法里面做Method Swizzling

前言

最近,在做项目时,因为某种原因,突然要“适配”iOS6(也是醉了。。。),保证极少数的iOS6用户可以“用上”新的版本。哪怕界面上有瑕疵,只要功能正常就行。于是就只好花几天时间对iOS6进行紧急适配(心中一万头驼羊奔跑而过。。。)

本文总结了一些常规的,和“非常规”的iOS项目向老版本兼容的办法,结合了宏定义CategoryRuntime,大家看着消遣一下就好哈~

用Runtime的手段填充任意NSObject对象的nil属性

前言

好久没有写东西了,忙啊。

前段时间参加了一下我们华科联创的HackDay(本人在读研=。=,目前在阿里实习),作品是一款实时在线对战游戏 - 波波攒,(介绍请看知乎
从iOS游戏客户端(用的SpriteKit)到后台(PHP CI + Node + SocketIO + MySQL)全是自己一个人倒腾出来的,做了一把真正的全栈工程师,爽啊~
后面会完善整个游戏,增加角色、优化啥的,过上一段时间会上线的哈~

回到正文,本文主要介绍了怎么用Runtime的手段遍历任意NSObject对象的所有property,检查其值是否是nil,是的话根据其类型为其填充一个默认值。
Runtime毕竟是个“危险”的技术,本文的代码只是个初步的尝试。

有趣的Autolayout示例-Masonry实现

更新

前言

好久没有写Blog了,这段时间有点忙啊=。=
本文举了3个比较有“特点”的Autolayout例子,源于微博上好友的提问,感觉比较有意思,也比较有代表性,就写了出来,分享给大家~
至于为什么用Masonry,那是因为它好用啊!(被问到过有关Masonry的问题,就索性用它来实现吧=。=)。

效果图

效果图

Github地址

https://github.com/zekunyan/AutolayoutExampleWithMasonry

RPC框架Thrift例子-PHP调用C++后端程序

更新

  • 2016-02-22: Response对象不用主动创建。

前言

前段时间用了一下Facebook的开源RPC框架Thrift,做PHP客户端调用C++后端程序,真心觉得Thrift不错!

本文项目地址:https://github.com/zekunyan/ThriftDemo_PHP_CPP

先看看本文的例子示意图:

通信示意图

流程

  1. PHP客户端发起请求,请求参数是“Request”类型,里面有studentID参数。
  2. CPP服务端收到请求返回数据,返回类型为“Response”,里面包含了student的信息,此处只是简单的示例。

GCD使用经验与技巧浅谈

前言

GCD(Grand Central Dispatch)可以说是Mac、iOS开发中的一大“利器”,本文就总结一些有关使用GCD的经验与技巧。

dispatch_once_t必须是全局或static变量

这一条算是“老生常谈”了,但我认为还是有必要强调一次,毕竟非全局或非static的dispatch_once_t变量在使用时会导致非常不好排查的bug,正确的如下:

1
2
3
4
5
//静态变量,保证只有一份实例,才能确保只执行一次
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
//单例代码
});

其实就是保证dispatch_once_t只有一份实例。

为GCD队列绑定NSObject类型上下文数据-利用__bridge_retained(transfer)转移内存管理权

2015-5-28更新

下面评论的好友“@Jim”给了种新的思路,就是在清除context的函数里面,用“_bridge_transfer”转换context,把context的内存管理权限重新交给ARC,这样,就不用显式调用“CFRelease”了。如下:

1
2
3
4
5
6
7
void cleanStaff(void *context) {
//这里用_bridge_transfer转换,将内存管理权限交还给ARC
Data *data = (_bridge_transfer Data *)(context);
NSLog(@"In clean, context number: %d", data.number);
//不用显式释放context的内存!
}

前言

看过GCD(Grand Central Dispatch)的Apple官方文档的朋友一定见过“dispatch_set_context”和“dispatch_get_context”这两个函数,那么这两个函数该怎么用呢?

我们都知道,GCD的接口参数都是“C语言类型“的,那么,我们如何将NSObject类型(Foundation框架)的数据,传入GCD的接口呢?(即:Core Foundation和Foundation对象的转换)

本文关键字

  • GCD:dispatch_set_context,dispatch_get_context
  • __bridge,__bridge_retained,__bridge_transfer
  • Core Foundation, NSObject

Enum-枚举的正确使用-Effective-Objective-C-读书笔记-Item-5

前言

Enum,也就是枚举,从C语言开始就有了,C++、Java、Objective-C、Swift这些语言,当然都有对应的枚举类型,功能可能有多有少,但是最核心的还是一个—规范的定义代码中的状态、选项等“常量”。

Item 5 - Use Enumerations for States, Options, and Status Codes

本节的内容就是如何正确的使用枚举。

状态与选项的区别(states and options)

在用enum之前,我个人觉得,区分一下状态和选项的概念还是很必要的。

状态,同时只能有一种,如“OK”,“Error”,不可能同时是OK和Error。
选项,同时可以有一种或一种以上,如App可以同时支持横屏和竖屏,横屏竖屏在这个时候就是“屏幕方向”的两种不同的选项。

接下来,我们看看如何用枚举定义状态和选项。

@autoreleasepool-内存的分配与释放

前言

开发过iOS、Mac的朋友应该对“@autoreleasepool”不陌生。只要在Xcode里创建一个工程,就能看到下面这样的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//iOS program
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}
//Command line program
int main(int argc, const char *argv[]) {
@autoreleasepool {
//...
}
return 0;
}

看,每个main函数的主体都被@autoreleasepool的Block块包在里面,也就是说,接下来所有的对象创建都在这个block里面。

那么,@autoreleasepool的作用到底是什么呢?我们开发中可以用它来做什么呢?

可以在某些情况下,大幅度降低程序的内存占用,如下图:

autoreleasepool测试内存占用图

  • 测试的内容:500000次循环,每次循环创建一个NSNumber实例和两个NSString实例。
  • 图:红线表示没有用@autoreleasepool时的内存占用。
  • 图:绿线表示用了@autoreleasepool优化后的内存占用!

效果是不是很明显!

代码Github地址:AutoReleasePoolTestExample Xcode 6, iOS 8, iPhone 5模拟器.

有关宏定义的经验与技巧-简化代码-增强Log

前言

宏定义、#define啥的,我们经常遇到。
一般来说,最常用的可能就是定义一些常量、简单的“函数”,如下:

1
2
3
4
5
//定义常量PI
#define PI 3.1415926
//定义“函数”MIN
#define MIN(A,B) ((A) < (B) ? (A) : (B))

但是,这样定义常量、函数,有一定的风险。(见:Effective-Objective-C-读书笔记-Item-4-如何正确定义常量, 宏定义的黑魔法 - 宏菜鸟起飞手册

本文就列出几条我个人在iOS开发当中常用的经验与技巧。

当前网速较慢或者你使用的浏览器不支持博客特定功能,请尝试刷新或换用Chrome、Firefox等现代浏览器