I'm using this open source library which is a wrapper on AddressBook.framework. There's no method for deleting contact, so I'm gonna use default ABAddressBookRemoveRecord. However for that I need the ABAddressBookRef.
Since it's declared in APAddressBook.m file of that APAddressBook library as
#property (nonatomic, readonly) ABAddressBookRef addressBook; and I'm not able to get access to it, I wanted to write extension in Swift, containing method returning it.
So this is body of my extension:
extension APAddressBook {
private struct AssociatedKey {
static var addressBookRef = "addressBook"
}
var xo: ABAddressBook! {
get {
return objc_getAssociatedObject(self, &AssociatedKey.addressBookRef)
}
set(newValue) {
objc_setAssociatedObject(self, &AssociatedKey.addressBookRef, newValue, objc_AssociationPolicy(OBJC_ASSOCIATION_RETAIN))
}
}
func getABAddressBook() -> ABAddressBookRef {
return self.xo
}
}
I've also tried using private var xoAssociationKey: UInt8 = 0 as associatedKey, but calling getABAddressBook() function always crashes with fatal error: unexpectedly found nil while unwrapping an Optional value.
What's wrong with my code? Also is there better way to solve my problem?
Well maybe it's not particulary an answer to your questions but here is some thoughts.
You only know what to pass in obc_objc_getAssociatedObject because your lib is open source.
So why wouldnt you use that to fit it under your needs?
If i were you I'd just move that property to the public access. I dont find it a really worse solution than trying to access private property via obc_ methods.
Regarding your question did you try to specify addressBookRef as : NSString? Since Apple now made swift's String and NSString two different types.
Related
I'm working with Property wrappers in a project that is divided into few Swift package modules dependent on each others. I have been using my own property wrappers in the code, but I want to switch to Combine, as it contains a lot of similar functionalities to my own property wrappers. In the process of converting I often occur the compiler issue:
Abort trap: 6 with error message: Global is external, but doesn't have external or weak linkage!.
As the first step I have decided to get rid of this error while still using my own property wrappers, because it can occur even there, but I managed to get rid of it. But in not a clean way, and I would like to get more knowledge on what is going on, so I could proceed with Combine later - with the same errors.
Ok, so to get rid of the Abort trap: 6 with my old property wrappers I needed to switch the way I used this property in some of modules. Instead of writing and reading it directly, I access it with $property.wrappedValue. Then it works, but this is very ugly in code, and kinda denies the puropse of using a property wrapper. Could someone explain me why this error occurs? In some of the modules Im able to use it directly with no problem. I have no idea what is going on, and what I can do to resolve this. I tried to convert a lot of similar properties with Combine, and I just get more of this errors, and actually I was not even able to resolve them like this.
Please tell me what is this error about, why it happens and what I can do to resolve it.
If his helps, this is how this property wrapper is defined:
#propertyWrapper
public class ObservableChangedValue<Value: Equatable>: Observable<Value> {
public var projectedValue: ObservableChangedValue { self }
public override var wrappedValue: Value {
get { super.wrappedValue }
set { super.wrappedValue = newValue }
}
override func shouldExecuteNotifications(oldValue: Value, newValue: Value) -> Bool {
oldValue != newValue
}
}
public class Observable<Value> {
public init(wrappedValue: Value) {
self.wrappedValue = wrappedValue
}
internal var observations = [Observation<Value>]() { didSet { isBeingObserved = !observations.isEmpty } }
public var wrappedValue: Value {
didSet {
guard shouldExecuteNotifications(oldValue: oldValue, newValue: wrappedValue) else { return }
observations.forEach {
$0.executeNotification(oldValue: oldValue, newValue: wrappedValue)
}
}
}
public weak var delegate: ObservableDelegate?
public var isBeingObserved = false {
didSet {
guard isBeingObserved != oldValue else { return }
delegate?.isBeingObservedChanged(isBeingObserved)
}
}
internal func shouldExecuteNotifications(oldValue: Value, newValue: Value) -> Bool { true }
}
One big thing - I have noticed that the error only occurs when I access this variable from other file than where it was defined. I added getters and setters for now, but still not a nice solution. This seems to be a compiler error, but Im not sure.
Using property wrappers in extensions from different file seems to be
causing this
see what they claims in documentation
Property wrapper types
A property wrapper type is a type that can be used as a property wrapper. There are two basic requirements for a property wrapper type:
The property wrapper type must be defined with the attribute
#propertyWrapper. The attribute indicates that the type is meant to
be used as a property wrapper type, and provides a point at which
the compiler can verify any other consistency rules.
The property wrapper type must have a property named wrappedValue,
whose access level is the same as that of the type itself. This is
the property used by the compiler to access the underlying value on
the wrapper instance.
Is anyway to return itself property in the getter and set itself on the setter? Because I just want to print a log inside the getter and the setter and thats it.
For example I trying to do something like this:
private(set) var internetConnectionAvailable: Bool {
get {
logger.debug("verifying internet connection")
// here return itself property
}
set {
logger.debug("changing internet connection")
// here set itself
}
}
If I return self.internetConnectionAvailable on the getter I get:
Linker command failed with exit code 1
when I try to compile the project.
I'm trying to do that because I don't want to create an extra private property to store the get and the set. I'm looking if there are something different to achieve that.
EDIT: I note that you said you don't want to create an extra private property. Then sorry. No. Not unless you make this an NSManagedObject subclass (and hook into the willAccessValueForKey system), or otherwise hook into the ObjC runtime on an NSObject (you could swizzle your own getter for instance to add logging; don't laugh, I've done that before). But all of these approaches are insane in Swift (and insane in ObjC; I only used them for debugging). Just make the backing variable.
If you only wanted to log the setter, then this would be straightforward: use willSet rather than set. But logging the getter requires implementing it all by hand. You do that with a private backing variable.
private var _internetConnectionAvailable: Bool
private(set) var internetConnectionAvailable: {
get {
logger.debug("verifying internet connection")
return _internetConnectionAvailable
}
set {
logger.debug("changing internet connection")
_internetConnectionAvailable = newValue
}
}
Once you define get yourself, you've said you don't want the default handling, which means you get no automatic backing variable.
This is valid Swift without a backing property:
private(set) var internetConnectionAvailable: Bool {
get {
print("verifying internet connection")
// here return itself property
return false
}
set {
print("changing internet connection")
// here set itself
}
}
Just need to specify a type, and return false from the get.
I would to use custom classes with optional types in realm.
In order to serialize and work with a CLLocation instance my idea is this:
class MyClass : Object {
dynamic var _coordinates :NSData?
var coordinates :CLLocation? {
get {
if _coordinates == nil {
return nil
}
// we can cache it too to avoid deserialization every time
let coordinatesObj : CLLocation = NSKeyedUnarchiver.unarchiveObjectWithData(_coordinates!) as! CLLocation
return coordinatesObj
}
set(newCoordinates) {
if newCoordinates == nil {
_coordinates = nil
} else {
_coordinates = NSKeyedArchiver.archivedDataWithRootObject(newCoordinates!)
}
}
}
...
}
Is there a better way?
Should we have some sort of protocol in Realm which allow us to return optional NSData for a specific property?
Another idea is to have a custom method like ignoredProperties which can be used to implement the logic to convert an object to NSData? and viceversa for a set of custom properties.
I don't really think there is a better way than that. If you're looking to serve more complex objects than the ones that Realm supports, you'll always need to implement some additional logic to serialize/deserialize that data.
Personally, I'm a fan of the latter method you suggested: add a new property, mark it as ignored, and then manually implement its accessors to perform the necessary logic on the related Realm-backed property.
At this time there is not another way or workaround to manage my issue.
However I've found another much clearner way to handle this needs.
In fact the main concept is the same but it uses flatMap in order to avoid some boilerplate checks.
Hope it helps.
class MyClass: Object {
dynamic var _coordinates: NSData?
var coordinates: CLLocation? {
get {
return _coordinates.flatMap(NSKeyedUnarchiver.unarchiveObjectWithData) as? CLLocation
}
set {
_coordinates = newValue.flatMap(NSKeyedArchiver.archivedDataWithRootObject)
}
}
}
In the app that I'm currently working on, I try to take advantage of the new protocol extension feature in Swift. The idea is that I have a lot of classes implementing the same protocol. Since all these classes should have the same computed properties, and since the properties should behave identically in de different classes, I thought it would be nice to add the functionality only once.
My code is structured as the following example
protocol SomeProtocol { ... }
// There could potentially be unlimited different versions of "SomeClass" that implements "SomeProtocol"
class SomeClass : SomeProtocol { ... }
extension SomeProtocol {
var computedProperty1: Type? {
get { getData(SOME_ENUM) }
set { validateAndSave(newValue, atKey: SOME_ENUM) }
}
var computedProperty2: Type? {
get { getData(SOME_OTHER_ENUM) }
set { validateAndSave(newValue, atKey: SOME_OTEHR_ENUM) }
}
...
func getData(atKey: ENUM_TYPE) -> Type? {
[NEED SOME WAY TO GET THE SAVED DATA AND RETURN IT]
}
func validateAndSave(value: Type?, atKey: ENUM_TYPE) {
[NEED SOME WAY TO SAVE DATA FOR LATER RETURNING]
}
}
// The properties needs to be visible to the client code like this:
class ClientCode {
let someClassObject: SomeProtocol = SomeClass()
someClassObject.computedProperty1 = Type()
print(someClassObject.computedProperty1)
}
(The code above shows signs of storing the data in different dictionaries, which was my first thought)
The problem is that an extension does not support stored properties. But where/how do I store the data submitted to the computed properties then?
I can think of 2 different solutions, but none of them good..
I could transform the extension into a class that implements SomeProtocol instead, and then make SomeClass a subclass of it. That would allow me to save the data in stored properties. But it would also require me to implement all the methods the protocol requires in the new class - and that makes absolutely no sense, since it's the different versions of SomeClass that should provide different functionality..
I could just drop the entire extension idea, and move all the properties into SomeProtocol. But that would require me to implement all the computed properties in all the different versions of SomeClass with identical functionality, and the whole point of my extension idea was to avoid writing the same implementation for the same properties over and over again..
Is there some completely easy logical solution that I have overlooked?
... or a nice way to save data in a protocol extension that I do not know about?
... or another way of obtaining the desired functionality?
... or should I just suck it up and use one of my not-so-pretty solutions?
Assuming I understand the question correctly to work around the fact that protocol extensions don't support stored properties you could extend NSObject and use the objective C runtime to store your properties.
import ObjectiveC
private var AssociationKey: UInt8 = 0
class YourStoredObject {
// Whatever object your are persisting
}
extension NSObject {
var yourStoredObject: (YourStoredObject)! {
get {
return objc_getAssociatedObject(self, &AssociationKey) as? YourStoredObject
}
set(newValue) {
objc_setAssociatedObject(self, &AssociationKey, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN)
}
}
}
protocol YourProtocol {
var yourStoredObject: YourStoredObject! { get set }
}
extension YourProtocol {
func customYourStoredObjectGetter() -> YourStoredObject {
return yourStoredObject
}
}
extension UILabel : YourProtocol {
func myExtendedFunc() {
// Get (and print) your object directly
print(yourStoredObject)
// Get your object through a protocol custom getter
print(customYourStoredObjectGetter())
// Set your object
yourStoredObject = YourStoredObject()
}
}
I'm not saying this is the best solution but this is the only solution I can think of. I'm also looking for nicer Swift alternatives but still have not found any.
Protocol extension? Why?
Sometimes we get so hung up on an idea that we ignore a practical solution staring right at our face.
1. Do you have set of computed properties? No, you want stored properties.
Since all these classes should have the same computed properties, and
since the properties should behave identically in de different
classes...
... but later
The problem is that an extension does not support stored properties.
But where/how do I store the data submitted to the computed properties
then?
2. Assuming that it is a set of stored properties that you want, you practically provided the solution yourself! Made one change that will make sense now.
I could transform the extension into a class that implements
SomeProtocol instead, and then make SomeClass a subclass of it. That
would allow me to save the data in stored properties.
You extend the class whenever you want to and then confirm its subclasses to SomeProtocol to get the features. This is cleaner.
On a side note, Swift's protocols not being able to store properties is by design. Protocols do not have existence in their own right and it doesn't make sense to add stored properties in them.
Calling a method from its name (in a String format) can be sometimes useful.
In Swift it is recomended to change behavior and to use closures to do something "dynamically", so for example you can have a dictionary of functions, with the name as the key, and the implementation as the value.
However, sometimes you want to simply know "how to do it", and this is the reason of this question.
So, how to call dynamically a Swift method starting from it's name as string?
In Objective C it was simple:
[self performSelector:NSSelectorFromString(#"aSelector")];
But performSelector is banned in Swift
Is there any alternative?
In Swift, you should use closures and change your approach.
However, if you want to use performSelector to dynamically call a method given only it's String signature, altough it's not supported natively, I've found how to do it.
It is possible to create a C alternative to performSelector that:
works even on native swift classes (non objective-c)
takes a selector from string
However it's not so straightforward to implement a complete version of it, and it's necessary to create the method in C.
in C we have dlsym(), a function that returns a pointer to a function given the char symbol.
Well, reading this interesting post:
http://www.eswick.com/2014/06/inside-swift/
I've learned a lot of interesting things about swift.
Swift instance methods are plain functions with a specific signature, like this
_TFC14FirstSwiftTest12ASampleClass13aTestFunctionfS0_FT_CSo8NSString
where the "self" value is passed as the last parameter
in short you can call it directly from the c side without any kind of bridging, it is sufficient to rebuild the correct function signature.
In the signature above, there is the name of the project (FirstSwiftTest) and the lenght (14), the name of the class (ASampleClass) and the lenght (12), the name of the function (aTestFunction) and the lenght (13), then other values as the return type ecc ecc. For other details look at the previous link
The function above, is the representation of this:
class ASampleClass
{
func aTestFunction() -> NSString
{
println("called correctly")
return NSString(string: "test")
}
}
Well, on the c side, I was able to create this function
#include <stdio.h>
#include <dlfcn.h>
typedef struct objc_object *id;
id _performMethod(id stringMethod, id onObject)
{
// ...
// here the code (to be created) to translate stringMethod in _TFC14FirstSwiftTest12ASampleClass13aTestFunctionfS0_FT_CSo8NSString
// ...
id (*functionImplementation)(id);
*(void **) (&functionImplementation) = dlsym(RTLD_DEFAULT, "_TFC14FirstSwiftTest12ASampleClass13aTestFunctionfS0_FT_CSo8NSString");
char *error;
if ((error = dlerror()) != NULL) {
printf("Method not found \n");
} else {
return functionImplementation(onObject); // <--- call the function
}
return NULL
}
And then called it on the swift side
let sampleClassInstance = ASampleClass()
println(_performMethod("aTestFunction", sampleClassInstance))
The function resulted in these statement printed on the log:
called correctly
test
So it should be not so difficult to create a _performMethod() alternative in C that:
creates automatically the function signature (since it seems to have a logic :-)
manages different return value types and parameters
EDIT
In Swift 2 (and maybe in Beta3, I didn't try) It seems that performSelector() is permitted (and you can call it only on NSObject subclasses). Examining the binary, It seems that now Swift creates static functions that can be specifically called by performSelector.
I created this class
class TestClass: NSObject {
func test() -> Void {
print("Hello");
}
}
let test = TestClass()
let aSel : Selector = NSSelectorFromString("test")
test.performSelector(aSel)
and now in the binary I find
000000010026d830 t __TToFC7Perform9TestClass4testfT_T_
At this time, I don't understand well the reasons behind this, but I'll investigate further
You could call a method from a String this way:
let foo = <some NSObject subclass instance>
let selectorName = "name"
foo.perform(Selector(selectorName))
It is available only when your foo class is subclass of NSObject
swift3 version
class MyClass:NSObject
{
required public override init() { print("Hi!") }
public func test(){
print("This is Test")
}
public class func static_test(){
print("This is Static Test")
}
}
if let c: NSObject.Type = NSClassFromString("TestPerformSelector.MyClass") as? NSObject.Type{
let c_tmp = c.init()
c_tmp.perform(Selector("test"))
c.perform(Selector("static_test"))
}