How do I use objective-c-runtime's object_getIvar & object_setIvar in swift? - swift

Does anybody know why I get BAD_ACCESS on getting & setting of my iVars with the following code ?
class myClass: NSObject {
var model = "Unspecified"
override init() {
super.init()
var key: NSString = "model"
var aClass : AnyClass? = self
var ivar: Ivar = class_getInstanceVariable(aClass, key.UTF8String)
// Set
object_setIvar(aClass, ivar, "R56")
// Get
var value: AnyObject = object_getIvar(aClass, ivar)
}
}
myClass()

You get a bad access because Swift classes do not have traditional iVars anymore (try to grab a Swift class' iVar layout and see for yourself). But Swift classes are also Objective-C objects to the runtime, and there don't appear to be any paths excluding Swift classes in it.
What winds up happening is the runtime hands you a bogus iVar that it truly thinks points to a proper offset in the class definition (probably 0 or thereabouts because it doesn't exist). When you try to get said iVar, the runtime literally derefs you some of the object's bytes and tries to wrap it back up in an Objective-C pointer. Often this data has the tagged bit set unintentionally, and so often maps to tagged classes (in my tests I was reliably getting back a tagged pointer for what the runtime thought was NSMutableData).
Long story short: you can't do it anymore.

Related

What's the difference between these two declarations of delegates?

I'm learning about delegates and I don't understand why
let friendsFunctionsDelegate = FriendsFunctionsDelegate()
let friendsFunctions = FriendsFunctions()
friendsFunctionsDelegate.delegate = friendsFunctions
is correct whilst
let friendsFunctionsDelegate = FriendsFunctionsDelegate()
friendsFunctionsDelegate.delegate = FriendsFunction()
is wrong.
Here is the full code:
protocol FriendsDelegate: AnyObject {
func orderPizza()
func takeABreak()
}
class FriendsFunctionsDelegate {
weak var delegate: FriendsDelegate? = nil
func buyPizza() {
delegate?.orderPizza()
}
func sleep() {
delegate?.takeABreak()
}
}
class FriendsFunctions: FriendsDelegate {
func orderPizza() {
print("I ordered a pizza")
}
func takeABreak() {
print("I'm going to sleep")
}
}
let friendsFunctionsDelegate = FriendsFunctionsDelegate()
let friendsFunctions = FriendsFunctions()
friendsFunctionsDelegate.delegate = friendsFunctions
ARC (for Automatic Reference Counting)
ARC is the system which manages automatically the memory allocation / deallocation for your objects.
The way it works is that as long as you'll have AT LEAST 1 strong reference to an object in your code it will remain in memory. Please note that by default any property definition not define as weak is implicitly strong.
When specifying a property as weak it won't increment the "holding reference count" by one.
The issue you are experiencing...
In your first example, when you first create a let constant you hold a strong reference to it, then you assign it to the weak variable.
You have then =>
1 weak reference to the object (stored on the friendsFunctionsDelegate.delegate)
1 strong reference to the object (the let constant let friendsFunctions = FriendsFunctions())
As a result, ARC is NOT deallocating the object (strong reference >= 1) => It is working ✅
In your second example, when you directly instantiate + assign the delegate to the weak variable WITHOUT creating a constant first.
You have then =>
1 weak reference to the object (stored on the friendsFunctionsDelegate.delegate)
0 strong reference to the object
As a result, ARC is deallocating (release from memory) the object (strong reference == 0) directly after the assignment => Not working ❌
Conclusion
As a conclusion, you need to keep a strong reference somewhere to that delegate object.
Weak usage in delegate pattern
When using delegation we use a weak property to prevent memory retain cycle. This is happening when you have one object (Object A) holding a strong reference to another object (Object B) which is also having a strong reference to the first object (Object A).
A => B STRONG
B => A STRONG
=> ⚠️RETAIN CYCLE⚠️
When you'll try to get rid of object A or B from memory strong reference count will still be 1, you'll then get a memory leak with memory filled with unused objects, which might lead to an usable app. The solution is to define one of those 2 references as weak (not both). When applying the delegate pattern, you would define the property holding the reference to the delegate as weak.
Few extra comments:
Be careful to the naming which might be misleading. The delegate keyword should be appended only to the protocol and not to the class name. If you remove it though you would have an overlap, which is a hint that the naming could have more appropriately defined.
When you define a property as Optional and you want it to be nil as default, you don't have to explicitly specify the = nil. Though you can still do it ;)
Best practices tell you that when you want a class to conform to a delegate / protocol, you should go with an extension instead of directly conforming at the class definition.
Delegate pattern should be a blind communication pattern, so your class should not be aware about out of scope functions. Then the naming of the delegate methods should be modified to something like func didBuyPizza() and func didTakeABreak()or similar.
The one with
let friendsFunctions = FriendsFunctions() // holds a strong reference
friendsFunctionsDelegate.delegate = friendsFunctions
Works as it holds a strong reference , while this
friendsFunctionsDelegate.delegate = FriendsFunction()
Don't work as both parts (lhs & rhs) are weak so no retaining happens ( delegate is a weak property )
Notice how the FriendsFunctionsDelegate.delegate property is a weak reference:
weak var delegate: FriendsDelegate? = nil
^^^^
If you did
friendsFunctionsDelegate.delegate = FriendsFunction()
You created a FriendsFunction object, and the only object that has a reference to it is friendsFunctionsDelegate, via its delegate property. But this is a weak reference. There is no strong reference to the new FriendsFunction object! As a result, it will be deallocated immediately after it is created.
You should see a warning here that says:
Instance will be immediately deallocated because property 'delegate' is 'weak'
On the other hand, if you put the newly created FriendsFunction object into a let constant first,
let friendsFunctions = FriendsFunctions()
That let constant, friendsFunctions will be a strong reference to the FriendsFunctions object, since it is not weak. And since there is at least one strong reference to it, the object will not be deallocated until all the strong references are gone.
For more info, see Automatic Reference Counting in the Swift guide.

How can I Intentionally create a Zombie Object in Swift [duplicate]

I've read How to demonstrate memory leak and zombie objects in Xcode Instruments? but that's for objective-c. The steps don't apply.
From reading here I've understood zombies are objects which are:
deallocated
but something pointer is still trying to point to them and send messages to them.
not exactly sure how that's different from accessing a deallocated object.
I mean in Swift you can do:
var person : Person? = Person(name: "John")
person = nil
print(person!.name)
Is person deallocated? Yes!
Are we trying to point to it? Yes!
So can someone share the most common mistake which leads to creating a dangling pointer?
Here's zombie attack in under 15 lines of code:
class Parent { }
class Child {
unowned var parent: Parent // every child needs a parent
init(parent: Parent) {
self.parent = parent
}
}
var parent: Parent? = Parent()
let child = Child(parent: parent!) // let's pretend the forced unwrap didn't happen
parent = nil // let's deallocate this bad parent
print(child.parent) // BOOM!!!, crash
What happens in this code is that Child holds an unowned reference to Parent, which becomes invalid once Parent gets deallocated. The reference holds a pointer to the no longer living parent (RIP), and accessing that causes a crash with a message similar to this:
Fatal error: Attempted to read an unowned reference but object 0x1018362d0 was already deallocated2018-10-29 20:18:39.423114+0200 MyApp[35825:611433] Fatal error: Attempted to read an unowned reference but object 0x1018362d0 was already deallocated
Note The code won't work in a Playground, you need a regular app for this.
This is not a dangling pointer or a zombie. When you use ! you're saying "if this is nil, then crash." You should not think of person as a pointer in Swift. It's a value. That value may be .some(T) or it may be .none (also called nil). Neither of those is dangling. They're just two different explicit values. Swift's nil is nothing like null pointers in other languages. It only crashes like null pointers when you explicitly ask it to.
To create zombies, you'll need to be using something like Unmanaged. This is extremely uncommon in Swift.
Zombie objects are Objective-C objects which have been deallocated, but still receive messages.
In Objective-C, __unsafe_unretained can be used to create an additional pointer to an object which does not increase the reference count. In Swift that would be unowned(unsafe).
Here is a self-contained example:
import Foundation
class MyClass: NSObject {
func foo() { print("foo"); }
deinit { print("deinit") }
}
unowned(unsafe) let obj2: MyClass
do {
let obj1 = MyClass()
obj2 = obj1
print("exit scope")
}
obj2.foo()
obj1 is a pointer to a newly created object, and obj2 is another pointer to the same object, but without increasing the reference counter. When the do { ... } block is left, the object is deallocated. Sending a message to it via obj2 causes the Zombie error:
exit scope
deinit
*** -[ZombieTest.MyClass retain]: message sent to deallocated instance 0x1005748d0
This can also happen if you use Managed (e.g. to convert pointers to Swift objects to C void pointers in order to pass them to C callback functions) and you don't choose the correct retained/unretained combination. A contrived example is:
let obj2: MyClass
do {
let obj1 = MyClass()
obj2 = Unmanaged.passUnretained(obj1).takeRetainedValue()
print("exit scope")
}
obj2.foo()
Zombie Object is a deallocated object which behaves itself like alive. It is possible because of dangling pointer.
dangling pointer points on some address in the memory where data is unpredictable
Objective-C has unsafe_unretained[About] property attributes. [Example]
Swift has
unowned(unsafe)[About] reference
Unmanaged - a wrapper for non ARC Objc- code
unowned(unsafe) let unsafeA: A
func main() {
let a = A() // A(ref count = 1)
unsafeA = a
} // A(ref count = 0), deinit() is called
func additional() {
unsafeA.foo() //<- unexpected
}

How can I demonstrate a zombie object in Swift?

I've read How to demonstrate memory leak and zombie objects in Xcode Instruments? but that's for objective-c. The steps don't apply.
From reading here I've understood zombies are objects which are:
deallocated
but something pointer is still trying to point to them and send messages to them.
not exactly sure how that's different from accessing a deallocated object.
I mean in Swift you can do:
var person : Person? = Person(name: "John")
person = nil
print(person!.name)
Is person deallocated? Yes!
Are we trying to point to it? Yes!
So can someone share the most common mistake which leads to creating a dangling pointer?
Here's zombie attack in under 15 lines of code:
class Parent { }
class Child {
unowned var parent: Parent // every child needs a parent
init(parent: Parent) {
self.parent = parent
}
}
var parent: Parent? = Parent()
let child = Child(parent: parent!) // let's pretend the forced unwrap didn't happen
parent = nil // let's deallocate this bad parent
print(child.parent) // BOOM!!!, crash
What happens in this code is that Child holds an unowned reference to Parent, which becomes invalid once Parent gets deallocated. The reference holds a pointer to the no longer living parent (RIP), and accessing that causes a crash with a message similar to this:
Fatal error: Attempted to read an unowned reference but object 0x1018362d0 was already deallocated2018-10-29 20:18:39.423114+0200 MyApp[35825:611433] Fatal error: Attempted to read an unowned reference but object 0x1018362d0 was already deallocated
Note The code won't work in a Playground, you need a regular app for this.
This is not a dangling pointer or a zombie. When you use ! you're saying "if this is nil, then crash." You should not think of person as a pointer in Swift. It's a value. That value may be .some(T) or it may be .none (also called nil). Neither of those is dangling. They're just two different explicit values. Swift's nil is nothing like null pointers in other languages. It only crashes like null pointers when you explicitly ask it to.
To create zombies, you'll need to be using something like Unmanaged. This is extremely uncommon in Swift.
Zombie objects are Objective-C objects which have been deallocated, but still receive messages.
In Objective-C, __unsafe_unretained can be used to create an additional pointer to an object which does not increase the reference count. In Swift that would be unowned(unsafe).
Here is a self-contained example:
import Foundation
class MyClass: NSObject {
func foo() { print("foo"); }
deinit { print("deinit") }
}
unowned(unsafe) let obj2: MyClass
do {
let obj1 = MyClass()
obj2 = obj1
print("exit scope")
}
obj2.foo()
obj1 is a pointer to a newly created object, and obj2 is another pointer to the same object, but without increasing the reference counter. When the do { ... } block is left, the object is deallocated. Sending a message to it via obj2 causes the Zombie error:
exit scope
deinit
*** -[ZombieTest.MyClass retain]: message sent to deallocated instance 0x1005748d0
This can also happen if you use Managed (e.g. to convert pointers to Swift objects to C void pointers in order to pass them to C callback functions) and you don't choose the correct retained/unretained combination. A contrived example is:
let obj2: MyClass
do {
let obj1 = MyClass()
obj2 = Unmanaged.passUnretained(obj1).takeRetainedValue()
print("exit scope")
}
obj2.foo()
Zombie Object is a deallocated object which behaves itself like alive. It is possible because of dangling pointer.
dangling pointer points on some address in the memory where data is unpredictable
Objective-C has unsafe_unretained[About] property attributes. [Example]
Swift has
unowned(unsafe)[About] reference
Unmanaged - a wrapper for non ARC Objc- code
unowned(unsafe) let unsafeA: A
func main() {
let a = A() // A(ref count = 1)
unsafeA = a
} // A(ref count = 0), deinit() is called
func additional() {
unsafeA.foo() //<- unexpected
}

Can't set nil to an optional property with custom setter in Swift

I have swift class with various properties, some of which have optional types.
class UserObject: PFUser{
//optional property
var optionalPhotoURL:String? {
get {
if let optionalPhotoURL:String = objectForKey("optionalPhotoURL"){
return optionalPhotoURL
}
//not needed but just for emphasis
return nil
}
//I am unable to set UserObject.optionalPhotoURL = nil with this setters
set {
if let newPhotoURL:String = newValue! {
setObject(newPhotoURL, forKey: "optionalPhotoURL")
}else{
self.optionalPhotoURL = nil
}
}
}
}
I am unable to set optionalPhotoURL as nil, if it already had a previous value assigned to it.
I guess my question is, how do i "unset" an optional property with custom setter?
Update
These setters all crash
set {
if let newPhotoURL:String = newValue {
setObject(newPhotoURL, forKey: "optionalPhotoURL")
}else{
self.optionalPhotoURL = nil
}
}
and this
set {
if (newValue != nil) {
setObject(newValue!, forKey: "optionalPhotoURL")
}else{
self.optionalPhotoURL = nil
}
}
What you have here is a computed property.
Swift properties can either be computed or stored. We can observe value changes in our stored properties by using didSet and willSet but here we still have a stored property.
In your case, since you have overridden set and get*, you don't have a stored property, you have a computed property. If you want a computed property to have a backing storage, you must create that independently.
So you may want something like this:
class FooClass {
private var storageProperty: String?
var accessProperty: String? {
get {
return self.storageProperty
}
set {
self.storageProperty = newValue
// or whatever logic you may like here
}
}
}
*: You can't override set without also overriding get. You can however override get without overriding set--this makes a readonly computed value.
Moreover, it's important that we implement our storage properties in this way over relying on key-value coding.
For starters, setObject(forKey:) approach doesn't even work on pure Swift types. This will only work on objects which inherit from Objective-C types. It's an inherited method from NSObject's compliance to NSKeyValueCoding protocol. Why the base object of Objective-C conforms to so many protocols is beyond me... but it does and there's nothing we can do about it.
If we have a code base in which some of our objects are inheriting from Objective-C objects (which basically any project will have, UIViewController, etc), and some of our objects are pure Swift objects (which you will tend to have when you're creating your own Swift classes from scratch), then our Swift objects will not be able to implement this same pattern. If we have some objects of both types, we'll either have to implement the pattern I show above for all of them (and then we have consistency) or we'll have to implement one pattern for some types and another for other types (Swift structs would definitely have to implement the above pattern, you can't just make them inherit from NSObject) (and then we have inconsistency, which we don't like).
But what's far worse about setObject(forKey:) is that the first argument of this method always will be of type AnyObject. There is no type safety to the method at all. Where things are stored via setObject(forKey:) is based purely on the key which we use. When we use setObject(forKey:), we take a pile of type-safety advantages that Swift gives us and we throw them out the window. If we don't care to leverage the advantages Swift gives us over Objective-C, why are we writing it in Swift at all?
We can't even make the stored property private when we use setObject(forKey:). Anyone who knows the key can call setObject(forKey:) and set that object to whatever they want. And that includes objects which are not strings. All we have to do to introduce a crash to this codebase is write a class extension or subclass which has a key collision on a different type other than what you've used (so maybe an NSData value for the same key). And even if it doesn't happen to be a different type, simply duplicating the same key for multiple properties is going to introduce bugs... and bugs that are hard to debug.
Never set a value of a computed property in its set scope by calling itself !
This causes an infinite loop and the app will crash.
I don't know which API setObject:forKey belongs to, but in the case of nil you are supposed to remove the object
set {
if let newPhotoURL = newValue {
setObject(newPhotoURL, forKey: "optionalPhotoURL")
} else {
removeObjectForKey("optionalPhotoURL")
}
}
Your property optionalPhotoURL is a computed property, it does not store any values:
https://developer.apple.com/library/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Properties.html
You might want to create an additional property which actually stores the value. However, why do you want to set it to nil, since you are not deleting they object in case of nil.

Differentiating Between a Struct and a Class in Swift

I know why I would use a struct as opposed to a class, but how could I best tell which is being used by an API I'm using?
Obviously looking at the header file (or hopefully documentation) should make it immediately obvious. I am wondering if there is a way to know if the object I am using is a struct or class on face value though?
You can’t inherit from other structures or types. Classes have the ability to inherit functions, variables, and constants from parent classes.
In swift structs are value types while classes are reference types. Working with value types can make your code less error prone.
When you make a copy of a reference type variable, both variables are referring to the same object in memory. A change to one of the variables will change the other.
when you make a copy of a value type variable, the complete variable is copied to a new place in memory. A change to one of the copies will not change the other. If the copying of an object is cheap, it is far safer to make a copy than it is to share memory.
Auto completion in Xcode knows the type of type:
I'm not sure what you mean by "face-value". You can test to see if an object is an instance of a class by getting it's MirrorType using reflect and checking for the MirrorType's objectIdentifier property, like this:
struct TestStruct { }
class TestClass { }
let testStruct = TestStruct()
let testClass = TestClass()
if let x = reflect(testStruct).objectIdentifier {
println("I am a class...")
} else {
println("I am not a class...") // prints "I am not a class..."
}
if let x = reflect(testClass).objectIdentifier {
println("I am a class...") // prints "I am a class..."
} else {
println("I am not a class...")
}
This answer may be outdated with the upcoming release of Swift 1.2 (I do not have the new xCode beta so I can't say for sure), which I understand has better object introspection, but this does do the trick.