Search code examples
iosswiftmodulebuild-errorproperty-wrapper

Cannot access property wrapper across modules in Swift


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?


Solution

  • 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.