I'm having a problem, which I can't figure out for the life of me. I've searched the internet, trying to understand Swifts's EXC_BAD_ACCESS
, but nothing seemed to help.
我有个问题,我一辈子也搞不清楚。我在互联网上搜索,试图理解Swifts的EXC_BAD_ACCESS,但似乎没有任何帮助。
The following code is quite long, but most of the time the comments are all the information needed to understand the item of relevance.
下面的代码相当长,但是大多数时候注释都是理解相关项所需的所有信息。
I have a class CalculatorController
, which contains the following relevant methods and properties:
我有一个CalculatorController类,它包含以下相关的方法和属性:
import UIKit
class CalculatorController: UIViewController {
// the actual `@IBOutlet` which is never accessed directly
@IBOutlet private weak var _mainDisplay: UILabel!
// an instance of `MainDisplayMicroController`
// holds a reference to `_mainDisplay`
// is used to manipulate `_mainDisplay` in a controlled way
private var mainDisplay: MainDisplayMicroController!
override func viewDidLoad() {
super.viewDidLoad()
// connects `mainDisplay` with `_mainDisplay`
mainDisplay = MainDisplayMicroController(label: _mainDisplay)
// sets `_mainDisplay`'s `text` property to "0"
mainDisplay.content = .Number(0)
//...
}
//...
}
In order to manage _mainDisplay
in a certain way, I have created a class MainDisplayMicroController
, which on the one hand contains a reference to the the UILabel
itself, and on the other hand contains methods and properties, which perform actions on the UILabel
:
为了以某种方式管理_mainDisplay,我创建了一个类MainDisplayMicroController,它一方面包含对UILabel本身的引用,另一方面包含方法和属性,它们对UILabel执行操作:
import UIKit
class MainDisplayMicroController {
// used to express what `label.text` is currently showing
private enum DisplayState {
case ShowingNumber
case ShowingConstant
case ShowingErrorMessage
case Unknown
}
// holds the current state of what `label.text` is showing
private var state = DisplayState.Unknown
// used to pass different types of values in and out of this class
enum ContentType {
case Number(Double)
case Constant(String)
case ErrorMessage(String)
case Unknown(Any?)
}
// holds the reference to the label which is being manipulated/managed
private var label: UILabel?
// makes `label`'s `text` property directly accessible, as `label` is `private`
var text: String? {
get {
return label?.text
}
set {
label?.text = newValue
removeLeadingZeros()
transformToInteger()
}
}
// a property to allow controlled retrieval and manipulation of `label.text`
// uses `ContentType` to make clear what the information in `label.text` is/ is supposed to be
var content: ContentType {
get {
switch state {
case .ShowingNumber:
if let string = text {
if let value = NSNumberFormatter().numberFromString(string)?.doubleValue {
return .Number(value)
}
}
case .ShowingConstant:
if let symbol = text {
return .Constant(symbol)
}
case .ShowingErrorMessage:
if let message = text {
return .ErrorMessage(message)
}
default:
break
}
state = .Unknown
return .Unknown(text)
}
set {
switch newValue {
case .Number(let value):
text = "\(value)"
state = .ShowingNumber
removeLeadingZeros()
transformToInteger()
case .Constant(let symbol):
text = symbol
state = .ShowingConstant
case .ErrorMessage(let message):
text = message
state = .ShowingErrorMessage
case .Unknown(let thing):
text = "Error: Passed unknown value: \(thing)"
state = .ShowingErrorMessage
}
}
}
// removes the ".0" from `label.text`, if it is a whole number
private func transformToInteger() {
if state == .ShowingNumber {
switch content {
case .Number(let value):
if round(value) == value {
var doubleString = "\(value)"
if doubleString.rangeOfString("e") == nil {
dropLast(doubleString)
dropLast(doubleString)
}
text = doubleString
}
default:
break
}
}
}
// removes leading "0"s from `label.text` if they are redundant
private func removeLeadingZeros() {
if state == .ShowingNumber {
switch content {
case .Number(let displayedValue):
content = .Number(displayedValue)
default:
break
}
}
}
//...
}
Now, when I run the code I get the following error:
现在,当我运行代码时,我得到以下错误:
From what I've read on EXC_BAD_ACCESS
, the error often occurs when trying to call methods on released objects. I've tried using NSZombie
to check the issue, but I didn't find anything (probably due to my incompetence when using NSZombie
).
从我在EXC_BAD_ACCESS中看到的内容来看,当尝试调用释放对象上的方法时,常常会出现错误。我尝试过使用NSZombieto检查问题,但没有发现任何问题(可能是由于我在使用NSZombie时的无能)。
If I try to follow what is happening by logic, I come to following conclusion:
如果我试着用逻辑去理解正在发生的事情,我会得出以下结论:
-
mainDisplay
is set successfully inviewDidLoad()
- 在viewDidLoad()中成功设置主显示器
-
mainDisplay.content
is called - mainDisplay。内容被称为
- in the
content
's setter the switch-statement executes the.Number
case - 在内容的setter中,开关语句执行.Number实例。
-
text
andstate
are successfully set - 成功设置文本和状态
-
removeLeadingZeros()
is called - removeLeadingZeros()
- the switch-statement accesses
content
's getter - 切换语句访问内容的getter
- the switch-statement in
content
's getter executes the.ShowingNumber
case - content的getter中的switch语句执行.ShowingNumber案例
- the if-statements resolve to true, finally trying to evaluate the
NSNumberFormatter
expression - if语句解析为true,最后尝试计算NSNumberFormatter表达式
- the
EXC_BAD_ACCESS
occurs - EXC_BAD_ACCESS发生
Does anyone know why this is happening? Does it have to do with me manipulating an @IBOutlet
in a different class?
Any help is greatly appreciated!
有人知道这是为什么吗?这是否与我在另一个类中操作一个@IBOutlet有关?非常感谢您的帮助!
Here are links to the complete CalculatorController
and MainDisplayMicroController
.
这里是到完整CalculatorController和MainDisplayMicroController的链接。
Update #1:
As @abdullah suggested I have tried directing the NSNumberFormatter
expression in to multiple expressions. I still get the error though:
正如@abdullah所说,我尝试将NSNumberFormatter表达式定向到多个表达式。但我还是得到了一个错误:
Update #2:
I've removed all references and external classes, to make it as simple as possible, while maintaining the same functionality.
All of the methods and properties defined in MainDisplayMicroController
have been moved to CalculatorModel
.
These methods and properties now access the original @IBOutlet
, not any reference to it.
我已经删除了所有引用和外部类,使其尽可能简单,同时保持相同的功能。MainDisplayMicroController中定义的所有方法和属性都已转移到CalculatorModel。这些方法和属性现在访问原始的@IBOutlet,而不是对它的任何引用。
But still when trying to run it I get EXC_BAD_ACCESS(code=2)
at the same line of code.
I'm just super confused, as it can't have anything to do with weird references, or objects being released too soon anymore.
但是当尝试运行它时,我仍然在同一行代码中获得EXC_BAD_ACCESS(代码=2)。我只是非常困惑,因为它与奇怪的引用或对象发布得太快没有任何关系。
Here's the complete code for the new CalculatorController
.
这是新CalculatorController的完整代码。
Update #3:
I've removed the NSNumberFormatter
line, by changing it to:
我将NSNumberFormatter行改为:
Now I get the following error though:
现在我得到以下错误:
I assume there's some fundamental problem with the code, so I'm scrapping it. But thanks for all the help, and attempts at figuring this out.
我认为这段代码有一些基本的问题,所以我将它删除。但谢谢你的帮助,并试图解决这个问题。
Update #4:
This is what I get when adding a breakpoint on throw for all exceptions:
这是我在为所有异常添加抛出断点时得到的结果:
4 个解决方案
#1
6
I don't really see anything in that line that can cause a crash. I suggest you do the following:
在这条线上我没有看到任何可能导致崩溃的东西。我建议你做以下事情:
- Make a clean build (clean, nuke your derived data folder, then build) and see if the crash persists
- 做一个干净的构建(清理,使用你的衍生数据文件夹,然后构建),看看崩溃是否持续
- If the crash persists, set a breakpoint on throw for all exceptions to see which operation in the callstack caused the crash, and take it from there
- 如果崩溃持续,那么在抛出时为所有异常设置一个断点,以查看调用堆栈中的哪个操作导致了崩溃,并从那里获取它
#2
0
@WarrenBurton is on to something.
@WarrenBurton发现了什么。
Take your line that crashes out of your big class and run it in the playground and it works fine:
把你的线从你的大班跑出来,在操场上运行它,它很好:
let string = "1.213"
if let value = NSNumberFormatter().numberFromString(string)?.doubleValue
{
println("value = \(value)")
}
Displays the result
显示结果
value = 1.213
值= 1.213
Where is your variable "string" defined in your class?
在类中定义的变量“string”在哪里?
#3
0
Notice that string is blue, like a keyword, not black, like other local variables.
注意,字符串是蓝色的,像关键字,而不是黑色的,像其他局部变量一样。
I'd try local variable string ==> myString just to know for sure.
我试试局部变量string => myString来确定。
#4
0
Just 'cuz I was seeing the same thing and noticed no one had commented past your last edit (and maybe a fellow Googler for this issue will see this someday):
因为我看到了同样的事情,并且注意到没有人在你最后一次编辑后评论过(也许有一天这个问题的google同事会看到):
For both of our situations the issue is infinite recursion - we're calling a method from itself infinitely. That's the bug. The implication in the crash of NSNumberFormatter
is a red herring.
对于这两种情况,问题都是无限递归——我们从自身调用一个方法。这是错误。NSNumberFormatter崩溃的含义是转移注意力的。
#1
6
I don't really see anything in that line that can cause a crash. I suggest you do the following:
在这条线上我没有看到任何可能导致崩溃的东西。我建议你做以下事情:
- Make a clean build (clean, nuke your derived data folder, then build) and see if the crash persists
- 做一个干净的构建(清理,使用你的衍生数据文件夹,然后构建),看看崩溃是否持续
- If the crash persists, set a breakpoint on throw for all exceptions to see which operation in the callstack caused the crash, and take it from there
- 如果崩溃持续,那么在抛出时为所有异常设置一个断点,以查看调用堆栈中的哪个操作导致了崩溃,并从那里获取它
#2
0
@WarrenBurton is on to something.
@WarrenBurton发现了什么。
Take your line that crashes out of your big class and run it in the playground and it works fine:
把你的线从你的大班跑出来,在操场上运行它,它很好:
let string = "1.213"
if let value = NSNumberFormatter().numberFromString(string)?.doubleValue
{
println("value = \(value)")
}
Displays the result
显示结果
value = 1.213
值= 1.213
Where is your variable "string" defined in your class?
在类中定义的变量“string”在哪里?
#3
0
Notice that string is blue, like a keyword, not black, like other local variables.
注意,字符串是蓝色的,像关键字,而不是黑色的,像其他局部变量一样。
I'd try local variable string ==> myString just to know for sure.
我试试局部变量string => myString来确定。
#4
0
Just 'cuz I was seeing the same thing and noticed no one had commented past your last edit (and maybe a fellow Googler for this issue will see this someday):
因为我看到了同样的事情,并且注意到没有人在你最后一次编辑后评论过(也许有一天这个问题的google同事会看到):
For both of our situations the issue is infinite recursion - we're calling a method from itself infinitely. That's the bug. The implication in the crash of NSNumberFormatter
is a red herring.
对于这两种情况,问题都是无限递归——我们从自身调用一个方法。这是错误。NSNumberFormatter崩溃的含义是转移注意力的。