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 →

不带导航条的UIViewController推出带导航条的UIViewController

左侧controller A隐藏导航条,推出右侧controller B显示导航条,类似这个效果:

Read on →

[UIWindow setRootViewController:]后view无限叠加的问题修复

工程中有时会直接修改window.rootViewController,来导航到新的页面。
按理说对window的rootViewController属性设好了新值,老的rootViewController被释放了,UIKit应当自动把老的rootViewController的view一并remove掉,然而实测并非如此。
在iOS8/9中(更老版本没有测试),当window有rootViewController时,把新的controller赋值给window.rootViewController,老的rootViewController的view还是会留在window上。这些被遗留的view虽然看不见,但是浪费了内存,造成了view泄露;而且view的controller已经dealloc,此时view如果回调或通知controller的话,有造成崩溃的隐患。

多次设置rootViewController后,view结构如图,window上加了多个UILayoutContainerView:

Read on →

iOS8的UITextView输入光标显示不全的hack

在iOS8及以下版本的系统上,在定高的UITextView中,输入内容超过Text View高度后,输入光标有时会在Text View的底部显示不全,如how-to-make-a-uitextview-scroll-while-typing-editing中截图所描述。

尝试了各种方案,挑选了一种体验较好的。在textViewDidChanged:中,检测到正在编辑的区域在文字最下行,无动画滚动到结尾:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
- (void)textViewDidChange:(UITextView *)textView
{
    //hack for iOS8
    if (isLessThanIOS9)//in iOS9 Apple has already fixed this bug
    {
        CGRect line = [textView caretRectForPosition:
                       textView.selectedTextRange.start];
        CGFloat overflow = line.origin.y + line.size.height
        - (textView.contentOffset.y + textView.bounds.size.height
           - textView.contentInset.bottom - textView.contentInset.top);
        if (overflow > 0)//If at the bottom of text view
        {
            //disable animation. Otherwise, when a input confirm scroll animation is doing, input new text, animation will re-do from animation beginning, which looks strange.
            [UIView setAnimationsEnabled:NO];

            //scroll to text end
            [textView scrollRangeToVisible:NSMakeRange([textView.text length], 0)];
            [UIView setAnimationsEnabled:YES];
        }
    }
}

Over

Objective-c中property以new开头报错

在ARC中,属性名使用new开头会报错。比如说更改密码中原始密码的输入框叫oldPasswordTextField,可以;新密码的输入框叫newPasswordTextField,对不起,不行,编译错误。

在ARC出现之前,方法名如果以alloc、copy、init、mutableCopy和new开头,标准做法是返回一个retain count+1的对象。在ARC中,默认声明时强制遵守了这一规范:方法名如果以alloc、copy、init、mutableCopy和new开头,会被隐式声明为attribute((ns_returns_retained))。此行为可被显示声明attribute((ns_returns_not_retained))覆盖。

一般情况下不要使用attribute((ns_returns_not_retained))更改这一行为,除非有什么不得不履行的大义。

引用Clang 3.5 documentation | Objective-C Automatic Reference Counting | Retained return values:

A function or method which returns a retainable object pointer type may be marked as returning a retained value, signifying that the caller expects to take ownership of a +1 retain count.

Methods in the alloc, copy, init, mutableCopy, and new families are implicitly marked attribute((ns_returns_retained)). This may be suppressed by explicitly marking the method attribute((ns_returns_not_retained)).

参考帖子:http://stackoverflow.com/questions/24308162/property-name-starting-with-new-prefix-leads-to-bad-access-error-in-ios

Over

Strong-weak Dance 错误两则

第一则:RAC中strong-weak dance不完整造成内存泄露

今天在工程中发现了RAC导致的retain cycle:

1
2
3
4
@weakify(self)
[RACObserve(self, fooProperty) subscribeNext:^(id fooProperty) {
    [self doSomething];
}];

相对于正常的RAC用法:

1
2
3
4
5
@weakify(self)
[RACObserve(self, fooProperty) subscribeNext:^(id fooProperty) {
    @strongify(self)
    [self doSomething];
}];

少了一行@strongify(self)即造成了循环引用,即对于RAC来说,strong-weak dance是必须做的,不做strong-weak dance就会循环引用。

Read on →

iPhone SDK Bug Collection

  1. convertRect:fromView 返回乘以screen scale以后的结果:
    在iOS8上,view如果未添加到任何window,调用此方法可能会出现此后果。

  2. 定高UITextView输入时,文字超过text view高度,输入光标被遮挡或截断,显示不全,继续输入时正在输入的内容也被遮挡:
    参考iOS8的UITextView输入光标显示不全的hack

  3. window.rootViewController设置后,老的rootViewController的view仍然贴在window上:
    参考[UIWindow setRootViewController:]后view无限叠加的问题修复

Over