Swift Setter Causing Exc_Bad_Access

swift setter causing exc_bad_access

@vadian has provided a solution in his answer, which should fix your problem. Let me just explain what's happening.

You have created a computed property, i.e. a property which is not backed by a variable, instead both the getter and the setter do some processing, usually on another stored property, in order to respectively return a value and set a new value.

This is your computed property:

var test: NSNumber {
get { return self.test }
set {
println(newValue)
self.test = newValue
}
}

Look at the getter implementation:

return self.test

What does it do? It reads the test property of the current instance, and returns it. Which is the test property? It's this one:

var test: NSNumber {
get { return self.test }
set {
println(newValue)
self.test = newValue
}
}

Yes, it's the same property. What your getter does is to recursively and indefinitely calling itself, until a crash happen at runtime.

The same rule applies to the setter:

self.test = newValue 

it keeps invoking itself, until the app crashes.

Getting bad access on setter method in swift

Your name setter creates an infinite recursion:

In the setter you are assigning again into the same variable, which again calls the setter, and so on.

Your code would work just with:

var name: String  // no need for setter or getter
var age: Int // no need for setter or getter

Objective-C Property Getter/Setter crash EXC_BAD_ACCESS

Your problem is recursion. In the setter, you are calling the setter method again, and again and again.
When you declare

self.firstName = first name__;

is basically the equivalent of

[self setFirstName:first name__];

So the method is calling itself which doesn't make much sense to do.

You first need to wrap your head around properties and instance variables.

Objective C class instances often contain instance variables that hold values.
Even though it is possible to expose these variables to outside world via @public qualifier, this is not the established convention.
The convention is to have properties, which behind the scenes are a "wrapper" around private instance variable.
Since in Objective C you can only communicate with other objects via messages, to be able to access the values of instance variable you have setter and getter methods that are invoked when you send an appropriate message to the object.

Modern objective C creates instance variable for you implicitly when you declare properties. It is often said that those properties are backed by instance variables.

Normally there is no reason to explicitly implement setters and getters, as the compiler does this for you behind the scenes. (in a same manner, it also creates those instance variables for you)

But if you want to implement setters explicitly, you need to set the instance variable in the setter, not call the setter itself again (via dot notation convention) as I explained above.

Implicitly created instance variables have a naming convention with underscore as prefix. In your case it is

_firstName

When you declare a property called firstName, you also get an instance variable

_firstName

You setter should look like this

-(void)setFirstName:(NSString *)firstName 
{
_firstName = firstName;
}

And getter

-(NSstring *)getFirstName
{
return _firstName;
}

Weird EXC_BAD_ACCESS crash related with setter/getter in iOS

You have a for loop that is calling your -foo method, so self.obj is rapidly getting set to new values. Each time this happens, you're executing code asynchronously that is accessing your (nonatomic) property. But even if it is always getting a correct value for that property when being accessed from multiple threads, the main thread is very likely setting the property to a new value before the background thread finishes using the previous value of the property. And once the property gets changed to a new value, it releases the previous object that was assigned to it.

Since you're accessing your property from multiple threads, you want it to be atomic, not nonatomic, so change your property to this:

@property (strong) NSObject *obj;

atomic is the default. It is probably also safer to do the following with your asynchronous block:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSObject *obj = self.obj;
if (self.obj) {
NSLog(@"%@", [obj description]);
}
});

You should no longer see a crash if you do this, because obj will always either be nil or a valid object with a strong reference to it inside the block.

However, you probably won't get the results you expect from this. For each execution of your asynchronous block, it's not guaranteed that you'll get the subsequent instances of NSObject that you're creating. There might be times where it executes your block where obj is the same object both times, and where you never see some of the objects that were created. This is because your asynchronous block isn't getting the instance set immediately before you made the call to invoke the block, it's getting it from the property. If you want this to use the instance set immediately prior, you must do something like the following:

__block NSObject *obj = NSObject.new;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"%@", [obj description]);
});

This should always use the instance that you created specifically for that invocation of the asynchronous block.

Override a setter in swift

By writing this...

set(suit) {
self.suit = suit
}

... you introduce an infinite loop, because you call the setter from within the setter.

If your property isn't computed, you should take advantage of willSet and didSet notifiers to perform any additional work before/after the property changes.

By the way, you should remove te getter as well. It will cause another infinite loop when accessing the property.

didSet leads to EXC_BAD_ACCESS

After few hours and several rebuilds/restart the problem dissapeared. Don't know the reason. Imo, bug of XCode.

Setter for Bool in Swift

You are in recursive context.

You can't use currentShowLiked in the currentShowLiked property body as below:

// Recursive, Infinite loop
self.currentShowLiked = newValue

To fix this:

private var _currentShowLiked : Bool

var currentShowLiked: Bool {
get {
return [ some condition met on _currentShowLiked ] ? true : false
}
set {
self._currentShowLiked = newValue
}
}

EXC_BAD_ACCESS Using IBInspectable

You have an infinite recursion there, that is causing the crash. Basically within the setter of borderColor you're calling the setter for the same property, resulting the infinite recursion.

This happens because class extensions are not allowed to have stored properties, so Swift doesn't generate a backstore for your property, instead it treats it like a computed property, and calls the setter whenever you try to set the property.

There are two solutions that I can think of at this time, that will solve your problem:

  1. Subclass UIView, add the two properties there, update the class in IB to match the name of your new class.
  2. Use associated objects in your UIView accessors (objc_setAssociatedObject()/ objc_getAssociatedObject()) instead of direct iVar reference. You will not need to subclass and to update your xibs, however this solution is a little bit messier than the first one.

What is the purpose of willSet and didSet in Swift?

The point seems to be that sometimes, you need a property that has automatic storage and some behavior, for instance to notify other objects that the property just changed. When all you have is get/set, you need another field to hold the value. With willSet and didSet, you can take action when the value is modified without needing another field. For instance, in that example:

class Foo {
var myProperty: Int = 0 {
didSet {
print("The value of myProperty changed from \(oldValue) to \(myProperty)")
}
}
}

myProperty prints its old and new value every time it is modified. With just getters and setters, I would need this instead:

class Foo {
var myPropertyValue: Int = 0
var myProperty: Int {
get { return myPropertyValue }
set {
print("The value of myProperty changed from \(myPropertyValue) to \(newValue)")
myPropertyValue = newValue
}
}
}

So willSet and didSet represent an economy of a couple of lines, and less noise in the field list.

Why private(set) is not working in Swift?

Your problem lies here:

  set { self.name = "Unknown" }

You're setting the value of a computed property within its own setter. This causes infinite recursion. Don't forget that this is a computed property: it doesn't actually have storage. You don't have a variable "self.name" to put anything in; you only have a couple of functions to calculate it. Computed properties like this should use other, non-computed variables for storage. (That's why your structure example works, by the way: you're using a real property with storage.)

You're not being helped in your debugging by fact of running in a Playground. Don't get me wrong: Playgrounds are great. However, in this case, it's taking many seconds to crash, so the crash probably isn't showing up when you expect after an edit. It's also not showing you a full stack trace (which is massive for the problem you're getting, having reproduced it in a "real" app, and might have made it rather more obvious that you'd blown the stack.) When I built and ran the above as a console app, it finally blew up with a stack trace 104,832 calls deep, all but two of which were ...private_cmd.A.name.setter.... Bit of a clue :)



Related Topics



Leave a reply



Submit