How Not to Crash #3: NSNotification通知引起的崩溃

How Not to Crash #3: NSNotification通知引起的崩溃html, body {overflow-x: initial !important;}html { font-size: 14px; }
body { margin: 0px; padding: 0px; height: auto; bottom: 0px; top: 0px; left: 0px; right: 0px; font-family: ‘Helvetica Neue‘, Helvetica, Arial, sans-serif; font-size: 1rem; line-height: 1.42857143; color: rgb(51, 51, 51); background-color: rgb(255, 255, 255); overflow-x: hidden; }
a:active, a:hover { outline: 0px; }
::selection { background-color: rgb(181, 214, 252); text-shadow: none; background-position: initial initial; background-repeat: initial initial; }
#write { max-width: 854px; margin: 0px auto; height: auto; width: inherit; word-break: normal; word-wrap: break-word; position: relative; white-space: pre-wrap; text-align: justify; padding-bottom: 70px; }
body.typora-export { padding-left: 30px; padding-right: 30px; }
.typora-export #write { margin: 0px auto; }
#write > p:first-child, #write > ul:first-child, #write > pre:first-child, #write > blockquote:first-child, #write > div:first-child { margin-top: 30px; }
img { max-width: 100%; }
input, button, select, textarea { color: inherit; font-family: inherit; font-size: inherit; font-style: inherit; font-variant: inherit; font-weight: inherit; line-height: inherit; }
input[type="checkbox"], input[type="radio"] { line-height: normal; padding: 0px; }
::before, ::after, * { box-sizing: border-box; }
#write p, #write h1, #write h2, #write h3, #write h4, #write h5, #write h6, #write div, #write pre { width: inherit; }
h1 { font-size: 2rem; }
p, .mathjax-block { display: block; -webkit-margin-before: 1rem; -webkit-margin-after: 1rem; -webkit-margin-start: 0px; -webkit-margin-end: 0px; }
.hidden { display: none; }
.md-blockmeta { color: rgb(204, 204, 204); font-weight: bold; font-style: italic; }
a { cursor: pointer; }
li span { min-width: 10px; }
#write input[type="checkbox"] { cursor: pointer; width: inherit; height: inherit; margin: 4px 0px 0px; }
tr { page-break-inside: avoid; page-break-after: auto; }
thead { display: table-header-group; }
table { border-collapse: collapse; border-spacing: 0px; width: 100%; overflow: auto; page-break-inside: auto; }
table.md-table td { min-width: 80px; }
.CodeMirror-placeholder { opacity: 0.3; }
.CodeMirror-code pre { padding: 0px; }
.CodeMirror-lines { padding: 0px; }
div.hr:focus { cursor: none; }
.md-fences, pre.md-fences { font-size: 0.9rem; display: block; page-break-inside: avoid; text-align: left; overflow: visible; white-space: pre; position: relative !important; }
.md-fences .CodeMirror.cm-s-default.CodeMirror-wrap { top: -1.6em; margin-bottom: -1.6em; }
.md-fences.mock-cm { white-space: pre-wrap; }
.footnotes { color: rgb(136, 136, 136); font-size: 0.9rem; padding-top: 1em; padding-bottom: 1em; }
.footnotes + .footnotes { margin-top: -1em; }
sub, sup { line-height: inherit; position: inherit; top: inherit; vertical-align: super; }
.md-reset { margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: top; background-color: transparent; text-decoration: none; color: rgb(255, 255, 255); font-family: ‘Helvetica Neue‘, Helvetica, Arial, sans-serif; font-size: 1rem; text-shadow: none; float: none; position: static; width: auto; height: auto; white-space: nowrap; cursor: inherit; line-height: normal; font-weight: normal; text-align: left; box-sizing: content-box; direction: ltr; background-position: initial initial; background-repeat: initial initial; }
li div { padding-top: 0px; }
blockquote { margin: 1rem 0px; }
li p, li .mathjax-block { margin: 0.5rem 0px; }
li { margin: 0px; position: relative; }
blockquote > :last-child { margin-bottom: 0px; }
blockquote > :first-child { margin-top: 0px; }
.footnotes-area { color: rgb(136, 136, 136); margin-top: 0.714rem; padding-bottom: 0.143rem; }
@media print {
html, body { height: 100%; }
.typora-export * { -webkit-print-color-adjust: exact; }
}
.footnote-line { margin-top: 0.714em; font-size: 0.7em; }
a img, img a { cursor: pointer; }
#write pre.md-meta-block { font-size: 0.8rem; min-height: 2.86rem; white-space: pre; background-color: rgb(204, 204, 204); display: block; background-position: initial initial; background-repeat: initial initial; }
p > .md-image:only-child { display: inline-block; width: 100%; text-align: center; }
#write .MathJax_Display { margin: 0.8em 0px 0px; }
.mathjax-block { white-space: pre; padding-bottom: 0.65rem; overflow: hidden; width: 100%; }
p + .mathjax-block { margin-top: -1.143rem; }
.mathjax-block:not(:empty)::after { display: none; }
[contenteditable="true"]:active, [contenteditable="true"]:focus { outline: none; box-shadow: none; }
:focus { outline: none; box-shadow: rgb(79, 172, 249) 0px 0px 2px 3px, rgb(120, 174, 218) 0px 0px 2px inset; }
.task-list { list-style-type: none; }
.task-list-item { position: relative; padding-left: 1em; }
.task-list-item input { position: absolute; top: 0px; left: 0px; }
.math { font-size: 1rem; }
.md-toc { min-height: 3.58rem; position: relative; font-size: 0.9rem; border-top-left-radius: 10px; border-top-right-radius: 10px; border-bottom-right-radius: 10px; border-bottom-left-radius: 10px; }
.md-toc-content { position: relative; margin-left: 0px; }
.md-toc::after, .md-toc-content::after { display: none; }
.md-toc-item { display: block; color: rgb(65, 131, 196); text-decoration: none; }
.md-toc-inner:hover { text-decoration: underline; }
.md-toc-inner { display: inline-block; cursor: pointer; }
.md-toc-h1 .md-toc-inner { margin-left: 0px; font-weight: bold; }
.md-toc-h2 .md-toc-inner { margin-left: 2em; }
.md-toc-h3 .md-toc-inner { margin-left: 4em; }
.md-toc-h4 .md-toc-inner { margin-left: 6em; }
.md-toc-h5 .md-toc-inner { margin-left: 8em; }
.md-toc-h6 .md-toc-inner { margin-left: 10em; }
.md-toc-h6 { margin-left: 12em; }
@media screen and (max-width: 48em) {
.md-toc-h3 .md-toc-inner { margin-left: 3.5em; }
.md-toc-h4 .md-toc-inner { margin-left: 5em; }
.md-toc-h5 .md-toc-inner { margin-left: 6.5em; }
.md-toc-h5 .md-toc-inner { margin-left: 8em; }
.md-toc-h6 { margin-left: 9.5em; }
}
a.md-toc-inner { color: inherit; font-size: inherit; font-style: inherit; font-weight: inherit; text-decoration: inherit; line-height: inherit; }
.footnote-line a:not(.reversefootnote) { color: inherit; }
.md-attr { display: none; }
.md-fn-count::after { content: ‘.‘; }
.md-tag { opacity: 0.5; }
h1 .md-tag, h2 .md-tag, h3 .md-tag, h4 .md-tag, h5 .md-tag, h6 .md-tag { font-weight: initial; opacity: 0.35; }

html { font-size: 16px; }
html, body { background-color: rgb(243, 242, 238); font-family: ‘PT Serif‘; color: rgb(31, 9, 9); line-height: 1.5em; }
#write { max-width: 36em; }
ol, ul { list-style: none; }
blockquote, q { quotes: none; }
blockquote::before, blockquote::after, q::before, q::after { content: none; }
table { border-collapse: collapse; border-spacing: 0px; }
h1, h2, h3, h4, h5, h6 { font-weight: bold; }
h1 { font-size: 1.875em; line-height: 1.6em; margin-top: 2em; }
h2, h3 { font-size: 1.3125em; line-height: 1.15; margin-top: 2.285714em; margin-bottom: 1.15em; }
h3 { font-weight: normal; }
h4 { font-size: 1.125em; margin-top: 2.67em; }
h5, h6 { font-size: 1em; }
h1 { border-bottom-width: 1px; border-bottom-style: solid; margin-bottom: 1.875em; padding-bottom: 0.8125em; }
a { text-decoration: none; color: rgb(6, 85, 136); }
a:hover, a:active { text-decoration: underline; }
p, blockquote, pre.md-fences, .md-fences { margin-bottom: 1.5em; }
h1, h2, h3, h4, h5, h6 { margin-bottom: 1.5em; }
blockquote { font-style: italic; border-left-width: 5px; border-left-style: solid; margin-left: 2em; padding-left: 1em; }
ul, ol { margin: 0px 0px 1.5em 1.5em; }
ol li { list-style-type: decimal; list-style-position: outside; }
ul li { list-style-type: disc; list-style-position: outside; }
.md-meta, .md-before, .md-after { color: rgb(153, 153, 153); }
table { margin-bottom: 1.5em; font-size: 1em; }
thead th, tfoot th { padding: 0.25em 0.25em 0.25em 0.4em; text-transform: uppercase; }
th { text-align: left; }
td { vertical-align: top; padding: 0.25em 0.25em 0.25em 0.4em; }
code, pre.md-fences { background-color: rgb(218, 218, 218); padding-left: 1ch; padding-right: 1ch; }
pre.md-fences { margin-left: 2em; margin-bottom: 3em; }
pre, code, tt { font-size: 0.875em; line-height: 1.714285em; }
h1 { line-height: 1.3em; font-weight: normal; margin-bottom: 0.5em; }
p + ul, p + ol { margin-top: -1em; }
h3 + ul, h4 + ul, h5 + ul, h6 + ul, h3 + ol, h4 + ol, h5 + ol, h6 + ol { margin-top: 0.5em; }
li > ul, li > ol { margin-top: inherit; }
h2, h3 { margin-bottom: 0.75em; }
hr { border-style: none none solid; border-bottom-width: 1px; }
h1 { border-color: rgb(197, 197, 197); }
blockquote { border-color: rgb(186, 186, 186); color: rgb(101, 101, 101); }
thead.md-table-edit { background-color: transparent; }
thead { background-color: rgb(218, 218, 218); }
tr:nth-child(even) { background-color: rgb(232, 231, 231); background-position: initial initial; background-repeat: initial initial; }
hr { border-color: rgb(197, 197, 197); }
.task-list { padding-left: 1rem; }
.task-list-item { padding-left: 1.5rem; list-style-type: none; }
.task-list-item input::before { content: ‘√‘; display: inline-block; width: 1.25rem; height: 1.5rem; vertical-align: middle; text-align: center; color: rgb(221, 221, 221); background-color: rgb(243, 242, 238); }
.task-list-item input:checked::before, .task-list-item input[checked]::before { color: inherit; }
#write pre.md-meta-block { min-height: 1.875rem; color: rgb(85, 85, 85); border: 0px; background-color: transparent; margin-left: 1em; margin-top: 1em; background-position: initial initial; background-repeat: initial initial; }
.md-image > .md-meta { color: rgb(155, 81, 70); }
.md-expand.md-image > .md-meta { background-color: rgba(255, 255, 255, 0.65098); }
.md-image > .md-meta { font-family: Menlo, ‘Ubuntu Mono‘, Consolas, ‘Courier New‘, ‘Microsoft Yahei‘, ‘Hiragino Sans GB‘, ‘WenQuanYi Micro Hei‘, sans-serif; }
#write > h3.md-focus::before { left: -2.5rem; color: rgb(153, 153, 153); border-color: rgb(153, 153, 153); }
#write > h4.md-focus::before { left: -2.5rem; top: 0.25rem; color: rgb(153, 153, 153); border-color: rgb(153, 153, 153); }
#write > h5.md-focus::before { left: -2.5rem; color: rgb(153, 153, 153); border-color: rgb(153, 153, 153); }
#write > h6.md-focus::before { left: -2.5rem; top: 0.3125rem; color: rgb(153, 153, 153); border-color: rgb(153, 153, 153); }
.md-toc:focus .md-toc-content { margin-top: 19px; }
.md-toc-content:empty::before { color: rgb(6, 85, 136); }
.md-toc-item { color: rgb(6, 85, 136); }
#write div.md-toc-tooltip { background-color: rgb(243, 242, 238); }
#outline-dropmenu { background-color: rgb(243, 242, 238); -webkit-box-shadow: rgba(0, 0, 0, 0.372549) 0px 6px 12px; box-shadow: rgba(0, 0, 0, 0.372549) 0px 6px 12px; }
.pin-outline #outline-dropmenu { background-image: inherit; background-size: inherit; background-attachment: inherit; background-origin: inherit; background-clip: inherit; background-color: inherit; box-shadow: none; border-right-width: 1px; border-right-style: dashed; background-position: inherit inherit; background-repeat: inherit inherit; }
.pin-outline #outline-dropmenu:hover .outline-title-wrapper { border-left-width: 1px; border-left-style: dashed; }
.outline-item:hover { background-color: rgb(218, 218, 218); border-left-width: 18px; border-left-style: solid; border-left-color: rgb(218, 218, 218); border-right-width: 18px; border-right-style: solid; border-right-color: rgb(218, 218, 218); }
.outline-expander::before { content: ‘?‘; font-family: FontAwesome; font-size: 14px; top: 1px; }
.outline-expander:hover::before, .outline-item-open > .outline-item > .outline-expander::before { content: ‘?‘; }

How Not to Crash #3: NSNotification通知引起的崩溃The One Way to Crash引起崩溃的原因The Big Rule怎么避免崩溃?Blanket Unregistering不怎么好的移除通知的方法移除指定通知的弊端移除通知的正确方法Beware Double Registrations注意多次注册同一通知Register in init, unregister in dealloc正确的注册通知方法Avoid addObserverForName避免使用此方法原文链接和译文参考

How Not to Crash #3: NSNotification通知引起的崩溃

In general, I prefer NSNotification to KVO and (especially) to bindings. I do use KVO sometimes — there are times when it’s the most sensible thing. But NSNotification, like many older APIs, is easier to use without crashing.(总体上来说,使用NSNotification比使用KVO更不容易崩溃)

But you still need to be careful.

The One Way to Crash引起崩溃的原因

When an object registers for a notification, and then is deallocated without unregistering, then the app will crash if that notification is posted. That’s the thing you need to avoid. The rest of this article describes how to do that.

The Big Rule怎么避免崩溃?

I have one simple, hard-and-fast rule: NSNotifications are posted on the main thread only.(通知总是在主线程发出) No exceptions. If some code is running in another thread and it needs to post a notification, it does so on the main thread.

This avoids all problems with notifications coming in on threads you don’t expect. It avoids race conditions with unregistering for notifications.(避免了通知在不同线程引起的崩溃,避免了资源竞争引发的问题)

Almost all of an app’s code should be written to run on the main thread. Code that runs in an NSOperation or GCD queue should be isolated from everything else, and should use a delegate pattern (with or without blocks) when multiple objects work together.

Ensuring that notifications are always posted on the main thread ought to be easy. (I’ll do another how-not-to-crash article on threading and queues that goes into more detail.)

Blanket Unregistering

不怎么好的移除通知的方法

Some people like the extra housekeeping work of unregistering for each NSNotification explicitly in dealloc. You get things like this:

[[NSNotificationCenter defaultCenter] removeObserver:self name:kSomeNotificationName object:someObject];

[[NSNotificationCenter defaultCenter] removeObserver:self name:kSomeOtherNotificationName object:someOtherObject];

etc...

移除指定通知的弊端

You can prove when you write this that it’s correct. But it’s not enough to think of a snapshot of your code — you have to think about your code as it moves through time.

And future you or future somebody else might add another notification, and not remember to call removeObserver for that specific notification. And then there’s a crash.

The other problem is that future coder may have to go through your code and do an audit to make sure each registered observation is removed. This is a pain: it’s manual and error-prone.

移除通知的正确方法

Instead, always do this:

[[NSNotificationCenter defaultCenter] removeObserver:self];

It’s what Indiana Jones(电影,夺宝奇兵的主角) would do.

Beware Double Registrations注意多次注册同一通知

If an object registers for a notification, and then registers for it again, the notification handler will get called twice.(如果多次注册同一通知,通知的处理方法会调用多次) There’s no automatic coalescing.

(This used to happen in the old days on iOS a lot with viewDidLoad. People would put registration code there — but remember that views could get unloaded and reloaded, which meant multiple registrations for the same notification.)

Your notification handlers should be written so that they can deal with getting called twice. And it should be impossible for a given object to register twice for the same notification. Both.

Register in init, unregister in dealloc正确的注册通知方法

In almost every single case, I register for observations in an init method and remove observations in dealloc. If I find that an object needs to add and remove observations during the lifetime of the object, then I consider it a strong code smell.

There’s a good chance that 1) either it doesn’t really need to do that, or 2) the object should be split into smaller objects.

You know that an init method will be called just once for a given object. You know that dealloc will be called just once when there are no other references to that object. You can use this knowledge to balance out registering and unregistering without having to think about it or keep track of it. So easy.

Avoid addObserverForName避免使用此方法

Some people like -[NSNotificationCenter addObserverForName:?object:?queue:?usingBlock:]. It feels modern because it’s block-based, and we all love blocks. (I sure do.)

But it’s a bad idea. You may have saved yourself writing a notification handler method, but you’ve made your housekeeping worse because now you have an extra object to keep around and do a removeObserver: on later. That means no blanket unregistering; it means you’re back to doing audits; it means you have another thing to get right.

You might like that the block-based version means you can keep the registration and the notification handler together — but the cost is too high in housekeeping and potential crashes.

原文链接和译文参考

  • http://ifujun.com/yi-wen-ru-he-cai-neng-bu-beng-kui-3-nsnotification/
  • http://inessential.com/2015/05/21/how_not_to_crash_3_nsnotification
时间: 2024-11-03 21:48:29

How Not to Crash #3: NSNotification通知引起的崩溃的相关文章

iPhone开发 Swift - NSNotification 通知

Swift创建Notification通知 创建一个SingleView Application 打开AppDelegate.swift,在方法 application(application:UIApplication,didFinishLaunchingWithOptions launchOptions: NSDictionary?) 中输入代码: func application(application: UIApplication, didFinishLaunchingWithOptio

iOS Crash 分析(文二)-崩溃日志组成

iOS Crash 分析(文二)-崩溃日志组成 现在我们看一个淘宝iOS主客崩溃的例子: ### 1.进程信息 ### Incident Identifier: E4201F10-6F5F-40F9-B938-BB3DA8ED7D50 CrashReporter Key: TODO Hardware Model: iPhone4,1 Process: Taobao4iPhone [3538] Path: /var/mobile/Applications/E3B51E77-D44D-4B3E-87

【iOS开发-65】QQ聊天界面案例:自定义cell、图片拉伸处理、NSNotification通知、键盘与视图移动以及输入框左边缩进处理

(1)案例 (2)源代码于素材下载 http://pan.baidu.com/s/1bnpiBCz (3)总结 --还是代码封装.控制器.视图.模型分别独立.里面还有很多代码可以独立出来整一个类. --如果某一个值只有特定的几个数字,那么可以用枚举来定义,注意命名规范 typedef enum{ WPMessageTypeMe=0, WPMessageTypeOther=1 }WPMessageType; --依然是计算一段文字所占据的宽和高 CGSize textMaxSize=CGSizeM

通知中心NSNotification与委托的异同,需要注意的要点

调度表 通知中心保存了一个调度表,表的内容包括:通知观察者(必须存在).通知名称和通知发送者. 通知中心的调度表给观察者指定了对应的通知集,一个通知集是通知中心发出的通知的子集. 调度表入口有4种类型,如下表所示: (英文版说明) Notification name Notification sender Notification set specified Specified Specified Notifications with a particular name from a speci

通知(NSNotificationCenter)

通知 如今天遇到了一个问题,长按相片,将此相片传到发布说说那个控制器中,不管用push,还是其它方法都无法实现,后来发现一个view添加到了Windows上面了,view添加完毕了就移除了和这个控制器一点关系都没有,这时一个大牛(朋友)用了"通知'这个方法,解决了我的难题,记录下. 1.发送通知 /**   postNotificationName: 是发布的通知的名字,谁要注册通知时,必须和这个名字一致 *   Object :是要传递的对象或参数,如果不传为nil (id类型). **/ [

crash日志的分析

怎样获得crash日志 怎样解析crash日志 怎样分析crash日志 1. iOS策略相关 2. 常见错误标识 3. 代码bug 一.怎样获得crash日志 当一个iOS应用程序崩溃时,系统会创建一份crash日志保存在设备上. 这份crash日志记录着应用程序崩溃时的信息,通常包括着每一个运行线程的栈调用信息(低内存闪退日志例外),对于开发者定位问题非常有帮助. 假设设备就在身边,能够连接设备,打开Xcode - Window - Organizer,在左側面板中选择Device Logs(

iOS应用的crash日志的分析基础

iOS应用的crash日志的分析基础 分类: iOS  |  作者: jasonblog 相关  |  发布日期 : 2013-06-22  |  热度 : 11° Outline 如何获得crash日志 如何解析crash日志 如何分析crash日志      1. iOS策略相关      2. 常见错误标识      3. 代码bug 一.如何获得crash日志 当一个iOS应用程序崩溃时,系统会创建一份crash日志保存在设备上.这份crash日志记录着应用程序崩溃时的信息,通常包含着每

UI_通知中心_传值的一种方法

NSNotification 通知中心传值,可以跨越多个页面传值, 一般也是从后面的页面传给前面的页面. 思路: 第三个界面的值传给第一个界面. 1. 在第一个界面建立一个通知中心, 通过通知中心,注册一个监听事件 2. 在第一个界面中,设置接收到通知的事件. 3. 在第一个界面中的dealloc中, 将通知中心remove掉 4. 在第三个界面中, 建立一个通知中心, 通过通知中心, 发送通知(发送通知的过程就是传值的过程,将要传输的值作为object的值传给第一个界面 代码片段: 第一界面:

iOS-----分析iOS Crash文件:符号化iOS Crash文件的3种方法

iOS Crash 分析(文一)- 开始 1. 名词解释 1. UUID 一个字符串,在iOS上每个可执行文件或库文件都包含至少一个UUID.目的是为了唯一识别这个文件. 2. dwarfdump 苹果提供的命令行工具,其中一些功能就是查看可执行文件件或库文件的UUID 3. symbolicatecrash 一个苹果提供的脚本.可以将crash日志符号化为可读的堆栈信息. 4. atosl 苹果提供的命令行工具,可以将crash的base_address和load_address转化为可读的堆