热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

UILabel怎么可能成为一名CALayer的人并导致崩溃呢?-howcantheUILabelbecomeaCALayerandcauseacrash?

IvegotacustomUIViewofwhichseveralinstancesarecreatedinsidealoop:我有一个自定义的UIView其中有几个实例

I've got a custom UIView of which several instances are created inside a loop:

我有一个自定义的UIView其中有几个实例是在循环中创建的:

let models = CDMyModel.MR_findAllSortedBy("position", ascending: true) as! [CDMyModel]

for view in myViews {
    view.removeFromSuperview()
}

self.myViews.removeAll(keepCapacity: true)

for model in models {
    let myView = MYFaqView(width: CGRectGetWidth(self.view.frame))
    myView.titleLabel.text = model.title
    myView.content.text = model.content
    myView.titleLabel.sizeToFit()
    self.scrollView.addSubview(myView)
    self.myViews.append(myView)
}

I do sometimes see crashes in Crashlytics in the line with myView.content.text = model.content:

我有时会在myView.content中看到Crashlytics中的崩溃。文本= model.content:

enter image description here

According to the crash I assume it has something to do with memory, but I really don't know how the myView could have been released at that point.

根据这次崩溃,我认为它与内存有关,但我真的不知道myView当时是如何发布的。

All this happens in viewWillAppear:. Could the removing before has to do something with this? But I assume everything happens on the main thread, so this shouldn't be a problem as well - I'm really stuck here.

所有这些在viewWillAppear中发生:。之前的移除有什么用吗?但是我假设所有的事情都发生在主线上,所以这也不应该是一个问题——我真的被困在这里了。

The crash happens on iOS 9.

崩溃发生在iOS 9上。

EDIT

编辑

MyFaqView init method:

MyFaqView init方法:

init(width:CGFloat) {
    self.width = width

    super.init(frame: CGRectZero)

    self.addSubview(self.titleLabel)
    self.addSubview(self.toggleImageView)
    self.addSubview(self.separatorView)
    self.content.clipsToBounds = true
    self.addSubview(self.content)

    self.translatesAutoresizingMaskIntoCOnstraints= false
    self.clipsToBounds = true
}

EDIT

编辑

let content:UILabel = {
    let l = UILabel()
    l.numberOfLines = 0
    if let fOnt= UIFont(name: "OpenSans", size: 14) {
        l.fOnt= font
    }
    return l
}()

2 个解决方案

#1


2  

These problems are always very tricky to track down.

这些问题总是很难找到。

Basically, what is happening is memory corruption. The address 0x14f822a0 that was previously occupied by your UILabel content has been used by something else, in this case a CALayer. You can verify this if the crash happens locally by entering po 0x14f822a0 in lldb and sure enough it will output that address to be of type CALayer.

基本上,正在发生的是内存损坏。之前UILabel内容占用的地址0x14f822a0已经被其他东西使用,在本例中是一个CALayer。如果崩溃发生在本地,您可以通过在lldb中输入po 0x14f822a0来验证这一点,并确保它将输出该地址为CALayer类型。

With these errors, although the crash line can provide a clue, it is not always the cause of the error. Something has already happened elsewhere.

对于这些错误,虽然崩溃线可以提供线索,但它并不总是错误的原因。其他地方已经发生了一些事情。

Although Swift is mostly memory managed, there are still pitfalls for the unwary. Personally I have seen two principal causes of memory corruption. The first is with retain cycles caused by self referencing closures. The second - more pertinent to your problem - is with views related to Storyboards and Xibs.

尽管Swift大部分都是内存管理的,但对于粗心的人来说,仍然存在一些隐患。就我个人而言,我发现了记忆腐败的两个主要原因。第一种方法是使用自引用闭包引起的保留周期。第二个与您的问题更相关的是与故事板和xib相关的视图。

If we follow this through logically, we can consider that the CALayer now occupies the address space previously taken by your UILabel content. The runtime attempts to send a message to the object is thinks occupies that address, and that is caught by a Swift runtime assert which then triggers a EXC_BAD_INSTRUCTION crash.

如果我们从逻辑上理解这一点,我们可以考虑到,CALayer现在占据了之前由UILabel内容所占用的地址空间。运行时尝试向对象发送消息is think占用该地址,该地址被Swift运行时断言捕获,然后触发exc_bad_instructions崩溃。

Now, for some other object to have taken up residence at that address, the original inhabitant the UILabel content must have been released. So why would the runtime release content? Because it is no longer required, i.e. it is not a subview or property of any view that it still required.

现在,如果有其他物体在那个地址定居,那么UILabel的原始居住者一定已经被释放了。那么为什么运行时发布内容呢?因为不再需要它,也就是说,它不是仍然需要的任何视图的子视图或属性。

I would bet that if you change content to be a subclass UILabel and add a deinit method that you then breakpoint, you will be surprised to see that it is being unexpectedly deinitialised early on. To test this create a type as follows:

我敢打赌,如果您将内容更改为UILabel的一个子类,并添加一个deinit方法,然后将其作为断点,您会惊讶地发现,它在早期就被意外地取消了初始化。要测试这一点,创建如下类型:

class DebugLabel: UILabel
{
   func deinit
   {
     NSLog("Breakpoint on this line here!")
   }
}

Then change content's type to be the DebugLabel above.

然后将内容的类型更改为上面的DebugLabel。

So why is all this happening? My money is on you having one of your view properties that has been created programmatically as being either weak or unowned. Perhaps you had these set up previously using an IBOutlet that you then removed but forgot to remove the weak designator?

为什么会这样呢?我的钱就花在你的视图属性上,你的视图属性是通过编程创建的,要么是弱属性,要么是空属性。也许您之前已经使用IBOutlet设置了这些内容,然后您删除了它,但忘记了删除弱指示器?

Check through each and every one carefully and I am sure you will find the cause of the problem above. Nothing that is created programatically either by using an initialiser or UINib should be designated weak or unowned.

仔细检查每一个问题,我相信你会找到上面问题的原因。使用初始化程序或UINib以编程方式创建的任何内容都不应该被指定为弱或非所有。

#2


0  

Brief viewing shows me two potential problems:

简单的观察给我展示了两个潜在的问题:

  1. You can break iterator here, that cause undefined behavior - removeFromSuperview() really remove the view from the hierarchy and release it and reduce the number of elements in myViews.
  2. 您可以在这里中断迭代器,这会导致未定义的行为——removeFromSuperview()实际上从层次结构中删除视图并释放它,并减少myViews中的元素数量。

for view in myViews { view.removeFromSuperview() }

在myViews中查看。removefromsuperview ()}

  1. What do you do here? Seems you repeat the previous step.
  2. 你在这里做什么?看来你重复了前面的步骤。

self.myViews.removeAll(keepCapacity: true)

self.myViews。removeAll(keepCapacity:真)


推荐阅读
  • 在 Android 开发中,通过 Intent 启动 Activity 或 Service 时,可以使用 putExtra 方法传递数据。接收方可以通过 getIntent().getExtras() 获取这些数据。本文将介绍如何使用 RoboGuice 框架简化这一过程,特别是 @InjectExtra 注解的使用。 ... [详细]
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • 本文介绍了在Android项目中实现时间轴效果的方法,通过自定义ListView的Item布局和适配器逻辑,实现了动态显示和隐藏时间标签的功能。文中详细描述了布局文件、适配器代码以及时间格式化工具类的具体实现。 ... [详细]
  • 实现‘点击恢复’功能 - Tap-to-Resume Feature in SpriteKit
    了解如何在应用程序从非活动状态返回时,在SpriteKit游戏中添加一个‘点击恢复’的文字提示。 ... [详细]
  • CSS高级技巧:动态高亮当前页面导航
    本文介绍了如何使用CSS实现网站导航栏中当前页面的高亮显示,提升用户体验。通过为每个页面的body元素添加特定ID,并结合导航项的类名,可以轻松实现这一功能。 ... [详细]
  • 深入解析ESFramework中的AgileTcp组件
    本文详细介绍了ESFramework框架中AgileTcp组件的设计与实现。AgileTcp是ESFramework提供的ITcp接口的高效实现,旨在优化TCP通信的性能和结构清晰度。 ... [详细]
  • 在编译BSP包过程中,遇到了一个与 'gets' 函数相关的编译错误。该问题通常发生在较新的编译环境中,由于 'gets' 函数已被弃用并视为安全漏洞。本文将详细介绍如何通过修改源代码和配置文件来解决这一问题。 ... [详细]
  • 本文探讨了如何在Classic ASP中实现与PHP的hash_hmac('SHA256', $message, pack('H*', $secret))函数等效的哈希生成方法。通过分析不同实现方式及其产生的差异,提供了一种使用Microsoft .NET Framework的解决方案。 ... [详细]
  • ListView简单使用
    先上效果:主要实现了Listview的绑定和点击事件。项目资源结构如下:先创建一个动物类,用来装载数据:Animal类如下:packagecom.example.simplelis ... [详细]
  • 本文详细探讨了Java中的ClassLoader类加载器的工作原理,包括其如何将class文件加载至JVM中,以及JVM启动时的动态加载策略。文章还介绍了JVM内置的三种类加载器及其工作方式,并解释了类加载器的继承关系和双亲委托机制。 ... [详细]
  • 本文探讨了如何在Java中使用JAXB解组两个具有相同名称但不同结构的对象。我们将介绍一个抽象类Bar及其具体实现,并展示如何正确地解析XML文档以获取正确的对象实例。 ... [详细]
  • 当unique验证运到图片上传时
    2019独角兽企业重金招聘Python工程师标准model:public$imageFile;publicfunctionrules(){return[[[na ... [详细]
  • 烤鸭|本文_Spring之Bean的生命周期详解
    烤鸭|本文_Spring之Bean的生命周期详解 ... [详细]
  • 深入解析Android中的SQLite数据库使用
    本文详细介绍了如何在Android应用中使用SQLite数据库进行数据存储。通过自定义类继承SQLiteOpenHelper,实现数据库的创建与版本管理,并提供了具体的学生信息管理示例代码。 ... [详细]
  • 在现代移动应用开发中,尤其是iOS应用,处理来自服务器的JSON数据是一项基本技能。无论是使用Swift还是PHP,有效地解析和利用JSON数据对于提升用户体验至关重要。本文将探讨如何在Swift中优雅地处理JSON,以及PHP中处理JSON的一些技巧。 ... [详细]
author-avatar
好宝贝蛋_282
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有