1

In my Common module (framework project) have below property wrapper for user defaults,

@propertyWrapper
public class MyUserDefaultWrapper<T> {
    let key: String
    let defaultValue: T

    public init(_ key: String, defaultValue: T) {
        self.key = key
        self.defaultValue = defaultValue
    }

    public var wrappedValue: T {
       get {
           let suite = UserDefaults(suiteName: "MySuite")
           return suite?.object(forKey: key) as? T ?? defaultValue
       }
       set {
           let suite = UserDefaults(suiteName: "MySuite")
           suite?.set(newValue, forKey: key)
       }
    }
}

In my App module (main project), I am declaring the client to use MyUserDefaultWrapper

import Common

public class MyUserDefaultsCommon: NSObject {
    @objc static let shared = MyUserDefaultsCommon()
    @MyUserDefaultWrapper("yearOfBirth", defaultValue: 1980)
    static var yearOfBirth: Int
}

And using like,

MyUserDefaultsCommon.shared.yearOfBirth = 2001

Its producing build error.

Unknown attribute 'MyUserDefaultWrapper'

How to get rid of this issue?

Sazzad Hissain Khan
  • 37,929
  • 33
  • 189
  • 256

1 Answers1

2

I used your code and some modifications were needed for it to work. My final solutions looks as following:

@propertyWrapper
public class MyUserDefaultWrapper<T> {
    let key: String
    let defaultValue: T

    public init(_ key: String, defaultValue: T) {
        self.key = key
        self.defaultValue = defaultValue
    }

    public var wrappedValue: T {
        get {
            let suit = UserDefaults.standard
            return suit.object(forKey: key) as? T ?? defaultValue
        }
        set {
            let suit = UserDefaults.standard
            suit.set(newValue, forKey: key)
        }
    }
}

Mostly some public keywords were missing. But I am confused on how you are implementing your framework so that you are not getting correct errors.

How I did it was:

First create a new project. Modify ViewController to:

import UIKit
import PropertyWrapperFramework

class ViewController: UIViewController {

    struct MyUserDefaultsCommon{
        @MyUserDefaultWrapper("yearOfBirth", defaultValue: 1980)
        static var yearOfBirth: Int
    }

}

Second create a new workspace. Preferably where the project file is and with same name (different extension). Close all projects. Open workspace. Drag your project file into your workspace project navigator.

Third create a new project and select Framework. When selecting folder also select "Add to:" at the bottom to insert it into your workspace.

Fourth drag your Product wrapper into your project under "Framework, Libraries, and Embedded Content" (see screenshot). You simply grab the ".framework" file under "Products" and drag it all the way down. Make sure that you have selected your main project -> target as shown on screenshot. enter image description here

Fifth add code to your framework. Create a new file and add logic to it:

@propertyWrapper
public class MyUserDefaultWrapper<T> {
    let key: String
    let defaultValue: T

    public init(_ key: String, defaultValue: T) {
        self.key = key
        self.defaultValue = defaultValue
    }

    public var wrappedValue: T {
        get {
            let suit = UserDefaults.standard
            return suit.object(forKey: key) as? T ?? defaultValue
        }
        set {
            let suit = UserDefaults.standard
            suit.set(newValue, forKey: key)
        }
    }
}

And finally build and run your app.

Matic Oblak
  • 16,318
  • 3
  • 24
  • 43
  • Did not solve my problem. I have linked the framework correctly because other public apis are accessible without any issue. – Sazzad Hissain Khan Dec 02 '19 at 09:10
  • @SazzadHissainKhan unfortunately without extra information this may not be solvable. I used all the code you posted and managed to run it in my application. Perhaps your framework needs to be rebuilt explicitly? – Matic Oblak Dec 02 '19 at 09:12
  • I am sorry for the wrong code snippet in my old post. Please try with new code snippet updated in my original post. Could you please try to make this buildable now? – Sazzad Hissain Khan Dec 02 '19 at 09:25
  • @SazzadHissainKhan do you not get any errors? The 2 calls to `suit` report an error because `suit` is not an optional. It should be `suit.` instead of `suit?.` in 2 cases. – Matic Oblak Dec 02 '19 at 09:29
  • I have updated the code. I was trying to add minimal example without my production code. Thanks for pointing out. Please see I use `let suite = UserDefaults(suiteName: "MySuite")` now. – Sazzad Hissain Khan Dec 02 '19 at 09:33
  • @SazzadHissainKhan yes, still. The issue is in the line after this one. Remove the `?` symbols. – Matic Oblak Dec 02 '19 at 09:54
  • @SazzadHissainKhan actually wait, no. Now you have a typo. In one case you have `suite` and in the other `suit`. Note an extra `e` at the end of the first one. Make them both the same. – Matic Oblak Dec 02 '19 at 09:56
  • Corrected. Sorry for my typo. – Sazzad Hissain Khan Dec 02 '19 at 10:07
  • @SazzadHissainKhan so this code now works for me perfectly. – Matic Oblak Dec 02 '19 at 10:34