EXC_BAD_ACCESS in swift_isUniquelyReferenced_nonNull_native when accessing swift array - ios

The Problem
While writing unit tests and mocking away the NSTimer I am seeing an
Exception: EXC_BAD_ACCESS (code=1, address=0x8)
inside
swift_isUniquelyReferenced_nonNull_native
The situation appear when accessing the array invalidateInvocations (inside func invalidate()) here.
class TimerMock: Timer {
/// Timer callback type
typealias TimerCallback = ((Timer) -> Void)
/// The latest used timer mock accessible to control
static var currentTimer: TimerMock!
/// The block to be invoked on a firing
private var block: TimerCallback!
/// Invalidation invocations (will contain the fireInvocation indices)
var invalidateInvocations: [Int] = []
/// Fire invocation count
var fireInvocations: Int = 0
/// Main function to control a timer fire
override open func fire() {
block(self)
fireInvocations += 1
}
/// Hook into invalidation
override open func invalidate() {
invalidateInvocations.append(fireInvocations)
}
/// Hook into the timer configuration
override open class func scheduledTimer(withTimeInterval interval: TimeInterval,
repeats: Bool,
block: #escaping TimerCallback) -> Timer {
// return timer mock
TimerMock.currentTimer = TimerMock()
TimerMock.currentTimer.block = block
return TimerMock.currentTimer
}
}
The interesting thing is if I change invalidateInvocations to a regular Int it can be accessed without any crashes.
Because accessing this variable leads to a EXC_BAD_ACCESS I would assume the array was already deallocated, but I would not see how this could happen.
The Demo
You can see a full running and crashing example in this repository (branch demo/crash)
https://github.com/nomad5modules/ArcProgressViewIOS/tree/demo/crash
Simply execute the unit tests and see it crashing.
The Question
What is happening here? I have observed a crash inside swift_isUniquelyReferenced_nonNull_native already in other projects too and I would love to completely understand the reason for this failure! So how is the process to find out what wrong here? And how to fix it?
Standalone reproduction project
https://drive.google.com/file/d/1fMGhgpmBRG6hzpaiTM9lO_zCZwNhwIpx/view?usp=sharing

The crash is due to not initialised member (it is NSObject not regular swift class, so explicit init() would be needed, but as this is Timer it has semi-abstract designated initializer, so override is not allowed).
The solution is to set up missed ivar explicitly, as below.
Tested & works on your Test project with Xcode 11.4.
override open class func scheduledTimer(withTimeInterval interval: TimeInterval,
repeats: Bool,
block: #escaping TimerCallback) -> Timer {
// return timer mock
TimerMock.currentTimer = TimerMock()
TimerMock.currentTimer.invalidateInvocations = [Int]() // << fix !!
TimerMock.currentTimer.block = block
return TimerMock.currentTimer
}

Related

What is the reason behind objc_sync_enter doesn't work well with struct, but works well with class?

I have the following demo code.
struct IdGenerator {
private var lastId: Int64
private var set: Set<Int64> = []
init() {
self.lastId = 0
}
mutating func nextId() -> Int64 {
objc_sync_enter(self)
defer {
objc_sync_exit(self)
}
repeat {
lastId = lastId + 1
} while set.contains(lastId)
precondition(lastId > 0)
let (inserted, _) = set.insert(lastId)
precondition(inserted)
return lastId
}
}
var idGenerator = IdGenerator()
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view.
}
#IBAction func click(_ sender: Any) {
DispatchQueue.global(qos: .userInitiated).async {
for i in 1...10000 {
let id = idGenerator.nextId()
print("i : \(id)")
}
}
DispatchQueue.global(qos: .userInitiated).async {
for j in 1...10000 {
let id = idGenerator.nextId()
print("j : \(id)")
}
}
}
}
Whenever I execute click, I would get the following crash
Thread 5 Queue : com.apple.root.user-initiated-qos (concurrent)
#0 0x000000018f58b434 in _NativeSet.insertNew(_:at:isUnique:) ()
#1 0x000000018f598d10 in Set._Variant.insert(_:) ()
#2 0x00000001001fe31c in IdGenerator.nextId() at /Users/yccheok/Desktop/xxxx/xxxx/ViewController.swift:30
#3 0x00000001001fed8c in closure #2 in ViewController.click(_:) at /Users/yccheok/Desktop/xxxx/xxxx/ViewController.swift:56
It isn't clear why the crash happen. My raw guess is, under struct, objc_sync_enter(self) doesn't work as expected. 2 threads accessing Set simultaneously will cause such an issue.
If I change the struct to class, everything just work fine.
class IdGenerator {
private var lastId: Int64
private var set: Set<Int64> = []
init() {
self.lastId = 0
}
func nextId() -> Int64 {
objc_sync_enter(self)
defer {
objc_sync_exit(self)
}
repeat {
lastId = lastId + 1
} while set.contains(lastId)
precondition(lastId > 0)
let (inserted, _) = set.insert(lastId)
precondition(inserted)
return lastId
}
}
May I know what is the reason behind? Why the above objc_sync_enter works well in class, but not in struct?
The objc_sync_enter/objc_sync_exit functions take an object instance and use its identity (i.e., address in memory) in order to allocate and associate a lock in memory — and use that lock to protect the code between the enter and exit calls.
However, structs are not objects, and don't have reference semantics which would allow them to be used in this way — they're not even guaranteed to be allocated in a stable location in memory. However, to support interoperation with Objective-C, structs must have a consistent object-like representation when used from Objective-C, or else calling Objective-C code with, say, a struct inside of an Any instance could trigger undefined behavior.
When a struct is passed to Objective-C in the guise of an object (e.g., inside of Any, or AnyObject), it is wrapped up in a temporary object of a private class type called __SwiftValue. This allows it to look like an object to Objective-C, and in some cases, be used like an object, but critically, it is not a long-lived, stable object.
You can see this with the following code:
struct Foo {}
let f = Foo()
print(f) // => Foo()
print(f as AnyObject) // => __SwiftValue
print(ObjectIdentifier(f as AnyObject)) // => ObjectIdentifier(0x0000600002595900)
print(ObjectIdentifier(f as AnyObject)) // => ObjectIdentifier(0x0000600002595c60)
The pointers will change run to run, but you can see that every time f is accessed as an AnyObject, it will have a new address.
This means that when you call objc_sync_enter on a struct, a new __SwiftValue object will be created to wrap your struct, and that object is passed in to objc_sync_enter. objc_sync_enter will then associate a new lock with the temporary object value which was automatically created for you... and then that object is immediately deallocated. This means two major things:
When you call objc_sync_exit, a new object will be created and passed in, but the runtime has no lock associated with that new object instance! It may crash at this point.
Every time you call objc_sync_enter, you're creating a new, separate lock... which means that there's effectively no synchronization at all: every thread is getting a new lock altogether.
This new pointer instance isn't guaranteed — depending on optimization, the object may live long enough to be reused across objc_sync_* calls, or a new object could be allocated exactly in the same place as an old one... or a new object could be allocated where a different struct used to be, and you accidentally unlock a different thread...
All of this means that you should definitely avoid using objc_sync_enter/objc_sync_exit as a locking mechanism from Swift, and switch over to something like NSLock, an allocated os_unfair_lock, or even a DispatchQueue, which are well-supported from Swift. (Really, the objc_sync_* functions are primitives for use largely by the Obj-C runtime only, and probably should be un-exposed to Swift.)

Closure cannot implicitly capture a mutating self parameter

I am using Firebase to observe event and then setting an image inside completion handler
FirebaseRef.observeSingleEvent(of: .value, with: { (snapshot) in
if let _ = snapshot.value as? NSNull {
self.img = UIImage(named:"Some-image")!
} else {
self.img = UIImage(named: "some-other-image")!
}
})
However I am getting this error
Closure cannot implicitly capture a mutating self parameter
I am not sure what this error is about and searching for solutions hasn't helped
The short version
The type owning your call to FirebaseRef.observeSingleEvent(of:with:) is most likely a value type (a struct?), in which case a mutating context may not explicitly capture self in an #escaping closure.
The simple solution is to update your owning type to a reference once (class).
The longer version
The observeSingleEvent(of:with:) method of Firebase is declared as follows
func observeSingleEvent(of eventType: FIRDataEventType,
with block: #escaping (FIRDataSnapshot) -> Void)
The block closure is marked with the #escaping parameter attribute, which means it may escape the body of its function, and even the lifetime of self (in your context). Using this knowledge, we construct a more minimal example which we may analyze:
struct Foo {
private func bar(with block: #escaping () -> ()) { block() }
mutating func bax() {
bar { print(self) } // this closure may outlive 'self'
/* error: closure cannot implicitly capture a
mutating self parameter */
}
}
Now, the error message becomes more telling, and we turn to the following evolution proposal was implemented in Swift 3:
SE-0035: Limiting inout capture to #noescape contexts
Stating [emphasis mine]:
Capturing an inout parameter, including self in a mutating
method, becomes an error in an escapable closure literal, unless the
capture is made explicit (and thereby immutable).
Now, this is a key point. For a value type (e.g. struct), which I believe is also the case for the type that owns the call to observeSingleEvent(...) in your example, such an explicit capture is not possible, afaik (since we are working with a value type, and not a reference one).
The simplest solution to this issue would be making the type owning the observeSingleEvent(...) a reference type, e.g. a class, rather than a struct:
class Foo {
init() {}
private func bar(with block: #escaping () -> ()) { block() }
func bax() {
bar { print(self) }
}
}
Just beware that this will capture self by a strong reference; depending on your context (I haven't used Firebase myself, so I wouldn't know), you might want to explicitly capture self weakly, e.g.
FirebaseRef.observeSingleEvent(of: .value, with: { [weak self] (snapshot) in ...
Sync Solution
If you need to mutate a value type (struct) in a closure, that may only work synchronously, but not for async calls, if you write it like this:
struct Banana {
var isPeeled = false
mutating func peel() {
var result = self
SomeService.synchronousClosure { foo in
result.isPeeled = foo.peelingSuccess
}
self = result
}
}
You cannot otherwise capture a "mutating self" with value types except by providing a mutable (hence var) copy.
Why not Async?
The reason this does not work in async contexts is: you can still mutate result without compiler error, but you cannot assign the mutated result back to self. Still, there'll be no error, but self will never change because the method (peel()) exits before the closure is even dispatched.
To circumvent this, you may try to change your code to change the async call to synchronous execution by waiting for it to finish. While technically possible, this probably defeats the purpose of the async API you're interacting with, and you'd be better off changing your approach.
Changing struct to class is a technically sound option, but doesn't address the real problem. In our example, now being a class Banana, its property can be changed asynchronously who-knows-when. That will cause trouble because it's hard to understand. You're better off writing an API handler outside the model itself and upon finished execution fetch and change the model object. Without more context, it is hard to give a fitting example. (I assume this is model code because self.img is mutated in the OP's code.)
Adding "async anti-corruption" objects may help
I'm thinking about something among the lines of this:
a BananaNetworkRequestHandler executes requests asynchronously and then reports the resulting BananaPeelingResult back to a BananaStore
The BananaStore then takes the appropriate Banana from its inside by looking for peelingResult.bananaID
Having found an object with banana.bananaID == peelingResult.bananaID, it then sets banana.isPeeled = peelingResult.isPeeled,
finally replacing the original object with the mutated instance.
You see, from the quest to find a simple fix it can become quite involved easily, especially if the necessary changes include changing the architecture of the app.
If someone is stumbling upon this page (from search) and you are defining a protocol / protocol extension, then it might help if you declare your protocol as class bound. Like this:
protocol MyProtocol: class {
...
}
You can try this! I hope to help you.
struct Mutating {
var name = "Sen Wang"
mutating func changeName(com : #escaping () -> Void) {
var muating = self {
didSet {
print("didSet")
self = muating
}
}
execute {
DispatchQueue.global(qos: .background).asyncAfter(deadline: .now() + 15, execute: {
muating.name = "Wang Sen"
com()
})
}
}
func execute(with closure: #escaping () -> ()) { closure() }
}
var m = Mutating()
print(m.name) /// Sen Wang
m.changeName {
print(m.name) /// Wang Sen
}
Another solution is to explicitly capture self (since in my case, I was in a mutating function of a protocol extension so I couldn't easily specify that this was a reference type).
So instead of this:
functionWithClosure(completion: { _ in
self.property = newValue
})
I have this:
var closureSelf = self
functionWithClosure(completion: { _ in
closureSelf.property = newValue
})
Which seems to have silenced the warning.
Note this does not work for value types so if self is a value type you need to be using a reference type wrapper in order for this solution to work.

Call class method with argument from another class method

In my code file MyItemVC.swift I have defined the following class and method:
class MyItemVC: UIViewController, UITextViewDelegate {
var timer = NSTimer()
func cycleTimer(toggleOn: Bool) {
if toggleOn == true {
// Timer calls the replaceItem method every 3 seconds
timer = NSTimer.scheduledTimerWithTimeInterval(3, target: self, selector: Selector("replaceItem"), userInfo: nil, repeats: true)
} else {
timer.invalidate() // stop the timer
}
}
}
Elsewhere in this class, I call cycleTimer(true) to start the timer and cycleTimer(false) to stop it.
Now, I also want to use the usual methods in my AppDelegate.swift code file to start and stop the timer when the app moves from active to inactive state. But I'm having trouble calling the cycleTimer method from that class.
I found an answer on Stack Overflow that suggested I could call it like this:
func applicationWillResignActive(application: UIApplication) {
MyItemVC.cycleTimer()
}
But I also need to pass in an argument. So I tried calling it like this:
func applicationWillResignActive(application: UIApplication) {
MyItemVC.cycleTimer(true)
}
But I got this error:
Cannot invoke 'cycleTimer' with an argument list of type '(Bool)'
How can I call this method from the AppDelegate methods while passing in an argument?
Thanks for the help. I realize this must be a very basic question but I'm new to programming and trying to teach myself using Swift. An answer using Swift rather than Obj-C would be greatly appreciated.
You need to use class function to be able to use it this way.
class func cycleTimer(toggleOn: Bool) {
However, I'm not sure about thread safety.
The function you have specified is not a class function. Add class keyword before func keyword.
The changed code:
class func cycleTimer
Note: In the previous versions of Swift you must use the following code (and also in C or other languages):
static func cycleTimer

problems using Grand Central Dispatch IOS Swift Xcode 6.3.1

I'm learning swift now and having hard time understanding the multithreading issues..
specific problem Im having is that i'm loading data from the internet and
trying to return an array ("broadcasts") containing this data while using dispatch_async .
My problem is that the return execution with the empty array happens before
the array is filled with the data (this line "println(broadcasts)" happens but the array returns empty.. )
Here is my code:
import UIKit
public class BroadcastRequest {
func requestNewBroadcasts() -> [BroadcastModel] {
var broadcasts = [BroadcastModel]()
var sectionsOfBroadcasts = [[BroadcastModel]]()
DataManager.getBroadcastsFrom׳TweeterWithSuccess { (youTubeData) -> Void in
dispatch_async(dispatch_get_main_queue()) { () -> Void in
let json = JSON(data: youTubeData)
if let broadcastsArray = json["result"].array {
for broadcastDict in broadcastsArray{
var broadcastID: String? = broadcastDict["id"].string
var broadcastURL: String? = broadcastDict["broadcast"].string
DataManager.getBroadcastDetailsFromYouTubeWithSuccess(broadcastURL!) { (youTubeData) -> Void in
dispatch_async(dispatch_get_main_queue()) { () -> Void in
let json2 = JSON(data: youTubeData)
if let broadcastDetailsDict = json2["result"].dictionary {
var cover: String! = broadcastDetailsDict["cover"]!.string
var caption: String! = broadcastDetailsDict["caption"]!.string
var broadcast = BroadcastModel(id: broadcastID, broadcastURL: broadcastURL, cover: cover, caption: caption)
broadcasts.append(broadcast)
**println(broadcasts)**
}
}
}
}
}
}
}
**return broadcasts**
}
}
After looking at answers i have changed the code to this:
import UIKit
public class BroadcastRequest {
func requestNewBroadcasts() {
var broadcasts = [BroadcastModel]()
var sectionsOfBroadcasts = [[BroadcastModel]]()
DataManager.getBroadcastsFrom׳TweeterWithSuccess { (youTubeData) -> Void in
dispatch_async(dispatch_get_main_queue()) { () -> Void in
let json = JSON(data: youTubeData)
if let broadcastsArray = json["result"].array {
for broadcastDict in broadcastsArray{
var broadcastID: String? = broadcastDict["id"].string
var broadcastURL: String? = broadcastDict["broadcast"].string
DataManager.getBroadcastDetailsFromYouTubeWithSuccess(broadcastURL!) { (youTubeData) -> Void in
dispatch_async(dispatch_get_main_queue()) { () -> Void in
let json2 = JSON(data: youTubeData)
if let broadcastDetailsDict = json2["result"].dictionary {
var cover: String! = broadcastDetailsDict["cover"]!.string
var caption: String! = broadcastDetailsDict["caption"]!.string
var broadcast = BroadcastModel(id: broadcastID, broadcastURL: broadcastURL, cover: cover, caption: caption)
broadcasts.append(broadcast)
println(broadcasts)
}
}
}
}
}
}
}
**TableViewController.requestFinished(broadcasts)**
}
}
And in class TableViewController-
public class TableViewController: UITableViewController {
...
...
public func requestFinished(requestedBroadcasts: [BroadcastModel]) {
self.broadcasts = requestedBroadcasts
self.tableView.reloadData()
}
Now i get the error:
Cannot invoke 'requestFinished' with an argument list of type '([(BroadcastModel)])'
Your code is wrong. A call to a GCD function like dispatch_async returns immediately, before the code in the closure has even begun executing. That's the nature of concurrent programming.
You can't write async code that makes a call and then has the answer on the next line. Instead you need to change your logic so that you make the call to dispatch async and then return and forget about the request until the block completes. Then you put the code that handles the result inside the closure. You can add a call inside your closure that calls out to your app on the main thread to notify it that processing is complete.
EDIT:
Your new code has multiple problems:
Your call to dispatch_async is using the main queue, which is a queue on the main thread. If your goal is to get this code to run in the background, this code fails to do that.
The call to TableViewController.requestFinished(broadcasts) is still in the wrong place. It needs to be inside the block, after the data has been fetched. it also needs to be performed on the main thread.
The call to TableViewController.requestFinished(broadcasts) appears to be sending a message to the TableViewController class rather than to an instance of the TableViewController class, which is wrong. You can't fix that unless your block has access to the instance of TableViewController that you want to send the message to.
You should probably refactor your requestNewBroadcasts method as follows:
Make it not return anything. (The result won't be available until after the async block completes anyway.)
Make requestNewBroadcasts take a completion block (or rather a closure, as they are called in Swift). Get rid of the TableViewController.requestFinished(broadcasts) call entirely, and instead have your network code call the completion block once the network request is complete.
Make your call to dispatch_async use a background queue rather than the main queue so that your task actually runs in the background.
Make your requestNewBroadcasts method invoke the completion block on the main thread.
Each of those steps is going to require work and research on your part.
Figuring out how to add a closure as a parameter will take digging. (See the Swift Programming Language iBook. It explains it well.)
Figuring out how to get a background queue will take work. (See the Xcode docs documentation on GCD. In particular look at dispatch_get_global_queue)
Figuring out how to make a call to the main thread from a background thread will take research (again see the Xcode docs on GCD. Hint: Your current call to dispatch_async is sending your block to a queue on the main thread.).
return broadcasts is executed before the loop that appends data to your array because of DataManager.getBroadcastsFromTweeterWithSuccess's closure.

Swift function that return two strings fail when its in loop

I Wrote a function that return two Strings, when calling the function regularly its works fine, but when I'm running the function through loop, I'm getting this error:
Thread 1: EXC_BAD_ACCESS (code=2, address=0xbfffcba0)
override func viewDidLoad()
{
super.viewDidLoad()
test()
}
func test()
{
var funcs = [checkButton]
var a = checkButton(value: 1) // Runs OK
for f in funcs{
var result = f(value: 1) // Fail
}
}
func checkButton(#value: Int) -> (location: String, pattern: String){
return ("abc","cba")
}
Update:
I'm using Xcode 6 beta 2, and running Mavericks on VMware Workstation.
Also, I've just created new clean project with that code and still getting the error.
This code runs fine for me. Your EXC_BAD_ACCESS must be coming from some other part of your code. Try setting a breakpoint and stepping through the code to find the line throwing the error.
From the “The Swift Programming Language.”
“An instance method can be called only on a specific instance of the type it belongs to. It cannot be called in isolation without an existing instance.”
checkButton() is an instance method, not a closure. It works in the first case because there is an implicit self. before checkButton(). It will not work in the second case.
If you want to make checkButton a closure you could declare it like so:
let checkButton = { (#value: Int) -> (location: String, pattern: String) in
return ("abc","cba")
}
I can confirm that it doesn't work for me either. Created a iOS single-view app from template, and added above code. crash. As an experiment, I took it out of the array (just f = self.checkButton) and got the same result.
I think it's a bug in the compiler.
First according to the book, a method is actually a function which is actually a closure, albeit one with special properties and restrictions. Shouldn't self.checkButton (or implicit version) be sufficient to "give it an existing instance", making it a closure? If MattL is correct that instance methods can't be used as closures, then the compiler shouldn't allow you to assign one to anything.
Second, the crash occurs on the exit, not on the call. And if you reference self in checkButton, (e.g. println(self.title) having previously set title), it works fine. That suggests that the instance is indeed known and operating, just something wrong on the return.
Third, changing it to a class method doesn't help. Changing these lines
var a = ViewController.checkButton(value: 1)
var funcs = [ViewController.checkButton]
class func checkButton(#value: Int) -> (location: String, pattern: String)
results in the same crash. I don't see any similar prohibition on context for class methods.
Fourth, if you simply change the return type from (location: String, pattern: String) to just String and return abc, then the whole thing works fine.
Fourth, if you wrap test and checkButton in a new class testClass, and then call it as below, it works:
class testClass {
func test()
{
var funcs = [checkButton]
var a = checkButton(value: 1) // Runs OK
for f in funcs {
var result = f(value: 1) // Fail
println(result)
}
}
func checkButton(#value: Int) -> (location: String, pattern: String){
return ("abc","cba")
}
}
class ViewController: UIViewController {
override func viewDidLoad()
{
super.viewDidLoad()
let g = testClass()
g.test()
}
}
Now change testClass to testClass: NSObject and it crashes.
So it looks like the compiler is botching up a method return when called as a closure with a tuple in a Obj-C subclass. When I put it like that, I must say that it's not terribly surprising nobody's noticed yet; you're really pushing the edge here!
More practically, in the meantime, if it's helpful, an alternative to changing your method to a closure is to keep it unchanged and just wrap it as you put it in the array:
var funcs = [{value in self.checkButton(value: value)}]
This seems to work.

Resources