Objective-c使用运行时dump Class的方法列表

最近需要对UIWebView内请求的静态文件做缓存,还要把Gif替换成静态图以节约CPU资源等,于是查了一下私有API可不可以抓取UIWebView内的请求打个标记,以便NSURLProtocol中可以准确判断是不是UIWebView发出的请求。
经调试发现hookwebThreadWebView:resource:willSendRequest:redirectResponse:fromDataSource:可以做这件事。调试过程就不细说了。

首先是dump类方法列表的函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <objc/runtime.h>
void DumpObjcMethods(Class clz)
{
    unsigned int methodCount = 0;
    Method *methods = class_copyMethodList(clz, &methodCount);
    printf("Found %d methods on '%s'\n", methodCount, class_getName(clz));

    for (unsigned int i = 0; i < methodCount; i++)
    {
        Method method = methods[i];

        printf("\t'%s' has method named '%s' of encoding '%s'\n",
               class_getName(clz),
               sel_getName(method_getName(method)),
               method_getTypeEncoding(method));
        /**
         *  Or do whatever you need here...
         */
    }
    free(methods);
}
Read on →

iOS抓包(使用BurpSuite和tcpdump)

Introduce

开发过程中我们经常会需要对网络请求抓包,本次介绍的是使用BurpSuite抓取HTTP/HTTPS包,以及不越狱使用tcpdump抓取iPhone的网络包。

使用BurpSuite对HTTP/HTTPS抓包

开发中我们经常会需要对HTTP/HTTPS请求进行抓包。
抓包实际上是在中间机器开了一个代理服务,让需要抓包的请求经过代理,我们就可以看到这些请求了。本质上是中间人攻击。
BurpSuite是一个常用的调试工具。

1. 下载BurpSuite

BurpSuite官网下载jar包,右键点击,运行:

Read on →

在lldb中一键打开模拟器sandbox路径

打开~/.lldbinit,在里面加入一行:

1
command alias sb script from subprocess import call; call(["open", '{0:s}'.format(lldb.frame.EvaluateExpression("NSHomeDirectory()")).split("\"")[1]]);

然后中断时,在lldb里打sb回车,就能打开模拟器当前运行的app的沙箱路径了。

Read on →

OTHTTPRequest v2.0 Release

这几天重写了OTHTTPRequest的大部分代码,发布了2.0版。
改动主要是上传文件功能,以前做的比较粗,是整个文件读到内存再上传的,不能支撑大文件上传,现在multipart/form请求全部改为流上传。此外增加了上传速度计算的功能。

最早做这个的原因是13年5月份做网易云音乐的下载性能优化,ASIHTTPRequest下载文件占用CPU时间太长,而当时iPhone4还有一定占有量,做了这个库来提升下载性能。
这次发布2.0,修改上传功能,是因为用ASIHTTPRequest做大文件上传时,进度回调有bug,尝试修结果没修成,于是花了点时间做了这个版本。

和1.0一样,整个框架基于NSURLRequest和NSURLConnection。

Github链接

Read on →

Xcode/lldb自动导入UIKit

lldb导入UIKit

使用lldb调试app时,lldb经常提示view.bounds无法打印:

实际上是lldb启动时没有默认导入UIKit,所以UIKit中的方法无法识别。在lldb中使用@import手动导入

1
expr @import UIKit

即可解决:

在开发Mac App时也是一样的,比如不导入AppKit则无法打印frame属性,手动导入AppKit即可:

1
expr @import AppKit

工程自动导入

但是大部分人都换有懒癌,对于每次调试都要手打一行命令是难以接受的。我们可以在main上加个断点:

在main中断时执行expr @import UIKit,并自动continue:

然后在工程启动时就会自动导入UIKit到lldb了。

全局自动导入

对于懒癌晚期的患者,每个工程单独配置还是挺麻烦的,可以在lldbinit中设置全局自动导入UIKit。在命令行中执行:

1
2
echo display @import UIKit >> ~/.lldbinit
echo display @import AppKit >> ~/.lldbinit

再重新启动调试即可(Xcode7测试时无需重启Xcode)。

Over

GCD异步同步互转

同步转异步

这个是GCD最常见的用法之一,耗时长的操作放在global queue中做,完成之后将结果交给主线程处理:

1
2
3
4
5
6
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
  id result = [self longTimeTask];
  dispatch_async(dispatch_get_main_queue(), ^{
      [self handleResultOnMainThread:result];
  });
});

异步转同步

这个本人并不常用,偶尔有不得不用的场景。
在异步操作开始前create信号量,然后使用dispatch_semaphore_wait等待此信号量。在异步操作完成后对此信号量发送signal:

1
2
3
4
5
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
[self someAsyncTaskWithCallback:^(BOOL successed) {
      dispatch_semaphore_signal(sema);
}];
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);

Over

App/Framework/Static Library开启BitCode,既踩坑笔记

苹果对BitCode的介绍看上去很美,今天尝试了一下,掉入深坑,克服种种困难终于爬上来了。成功开启后的效果还是挺好的。

下面介绍一下如何开启BitCode,以及我掉的坑有哪些。

Read on →

Self在执行方法的过程中dealloc引起的崩溃处理

场景和产生原因

在我的一个view controller里(为方便我们成为controller A),有一个doSomething方法,每次调用时,会延迟5秒调用delayAction,如果在5秒之内再次调用,会取消上次的延迟调用delayAction,再在5秒之后调用delayAction。

这在UI操作中是一个稀松平常的需求,代码如下:

1
2
3
4
5
- (void)doSomething
{
    [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(delayAction) object:nil];
    [self performSelector:@selector(delayAction) withObject:nil afterDelay:5];
}

然而就在某种情况下,这个正常工作的代码崩溃了,原因是第4行代码self已经释放,成为了僵尸指针,调用performSelector时造成了崩溃。

Read on →

使用nomad cli测试iOS的Push Notification

安装和使用

Nomad cli是一个ruby工具,涵盖了多项打包,测试功能。
首先,安装nomad cli:

1
gem install nomad cli

然后即可使用apn push命令发送push了:

1
apn push devicetoken8fd63xxxxxxxxxxxxxxxxxxe27bc82a3b313475bb488ee92092d3c -c push_cert.pem -n -m "A message from openthread"
Read on →

Xcode 中手动 Symbolicate Crash Log

从 Xcode7 开始 Organizer 集成了查看崩溃日志的功能,若 Xcode 可以定位到 crash 的 build,则可以直接在 Organizer 中查看崩溃是在具体哪一行。
但是不能自动定位到 build 的情况也非常常见,此时地址不能自动转换成符号:

此时即需要手动转换。

Read on →