Search code examples
iosswiftconditional-compilationios-keyboard-extension

Define a section of code in a class that's configured for two targets to run only in one of the targets


I'm working on a custom keyboard project. In this project I have two targets (the App and the Keyboard targets). Now I build a class that's responsible for handling network data for both of the targets:

class FeedDataManager: URLManagerdelegate, ModelManagerDelegate {
//Class Variables....

func initForKeyboard() {
    self.mModelManager = ModelManager(aContext: self.managedObjectContext())
    self.mModelManager.delegate = self
    self.mModelManager.mDelegateHashString = hashString(self)

    self.mFeedsArray = Array<News>()
    mModelManager.getFeeds(&self.mFeedsArray)
    self.mURLManager = UrlManager()
    self.mURLManager.delegate = self
}

func initForApp() {
    self.mModelManager = ModelManager(aContext: self.managedObjectContext())
    self.mModelManager.delegate = self
    self.mModelManager.mDelegateHashString = hashString(self)

    let uuid: String? = UserDefaultsManager.sharedInstance.getObjectForKey("UUID") as? String
    self.mURLManager = UrlManager()
    self.mURLManager.delegate = self
    mURLManager.doGetLanguagesRequest()

    if uuid == nil {
        mURLManager.doRegistrationRequest()
    }
}

//MARK: - News Related Methods
func getNews() {
    self.mFeedsArray.removeAll(keepCapacity: false)
    self.mModelManager.getFeeds(&self.mFeedsArray)
    Logger.printLogToConsole(TAG, aMethodName: __FUNCTION__, aMessage: "Feeds Array Count: \(mFeedsArray.count)")
    self.mURLManager.doGetSourcesRequest()
}

func handleRequestResults(aActionCode: Int, aData: NSData? = nil) {
    if let val = aData {
        if aActionCode == KiboConstants.NetworkActionCodes.GET_NEWS_DONE {
            let currentTime: Double = NSDate().timeIntervalSince1970
            UserDefaultsManager.sharedInstance.setDouble(currentTime, aKey: KiboConstants.CommonStrings.USER_DEF_LAST_UPDATE_TIME_STAMP)
            var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(aData!, options: .MutableContainers, error: nil)
            var nextUpdate: AnyObject? = json.valueForKey(KiboConstants.CommonStrings.USER_DEF_NEXT_UPDATE)
            self.setTimeWithNextUpdateValue(nextUpdate)
            self.mModelManager.updateNews(json, aCallerHashString: hashString(self))

        } else if aActionCode == KiboConstants.NetworkActionCodes.GET_SOURCES_DONE {
            var jsonWrapped: AnyObject! = NSJSONSerialization.JSONObjectWithData(aData!, options: .MutableContainers, error: nil)
            if self.mModelManager == nil {
                self.mModelManager = ModelManager(aContext: self.managedObjectContext())
                self.mModelManager.delegate = self
                self.mModelManager.mDelegateHashString = hashString(self)
            }
            if let json: AnyObject = jsonWrapped {
                mModelManager.updateSources(json)
            }
        } else if aActionCode == KiboConstants.NetworkActionCodes.GET_LANGUAGES_DONE {
            #if APPLICATION
            var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(aData!, options: .MutableContainers, error: nil)
            if let val: AnyObject = json {
                let languages: AnyObject = json.objectForKey(KiboConstants.JsonKeys.JSON_KEY_DATA_LANGUAGES_LOWERCASE)!
                for item in languages as! Array<AnyObject> {
                    ApplicationLanguagesManager.sharedInstance.addLanguageToAvailableLanguagesArray(item)
                }
            }
            #endif
        }
    } else {
        self.setTimeWithNextUpdateValue(KiboConstants.UserDefaultsValues.DEFAULT_NEXT_NEWS_UPDATE_VAL)
    }
}
.....
}

If you look into the handleRequestResults method, you will see this section:

#if APPLICATION
var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(aData!, options: .MutableContainers, error: nil)
if let val: AnyObject = json {
    let languages: AnyObject = json.objectForKey(KiboConstants.JsonKeys.JSON_KEY_DATA_LANGUAGES_LOWERCASE)!
    for item in languages as! Array<AnyObject> {
        ApplicationLanguagesManager.sharedInstance.addLanguageToAvailableLanguagesArray(item)
    }
}
#endif

And in the Application target I have defined the following in the Preprocessor Macros section:

enter image description here

Now when I run the application in debug and use "po APPLICATION" at this point I get a relevant print, while in the keyboard extension I get the following error: error: <EXPR>:1:1: error: use of unresolved identifier 'APPLICATION'

Meaning the configuration is read correctly.

The problem/question is: In the application's run this code is still isn't executed. Does someone knows why? What am I missing here?


Solution

  • Actually, none of the answers here are right. I have achieved what I wanted using the following configuration:

    plist file: plist file

    And done the following in code:

    #if APPLICATION
            var json: AnyObject! = NSJSONSerialization.JSONObjectWithData(aData!, options: .MutableContainers, error: nil)
            if let val: AnyObject = json {
                let languages: AnyObject = json.objectForKey(KiboConstants.JsonKeys.JSON_KEY_DATA_LANGUAGES_LOWERCASE)!
                for item in languages as! Array<AnyObject> {
                    ApplicationLanguagesManager.sharedInstance.addLanguageToAvailableLanguagesArray(item)
                }
            }
            #endif
    

    The result is the this section of code is compiled only for the targets that have the APPLICATION flag.

    A link that cleared it all up for me: Build Configuration Management with Swift