jbsf / blindside

Blindside provides dependency injection capabilities for Objective-C on iOS and OS X
MIT License
71 stars 43 forks source link

Enhanced Swift compatibility #39

Closed briancroom closed 9 years ago

briancroom commented 9 years ago

This exposes more core Blindside functionality to Swift clients. In particular, it allows for NSObject-derived classes defined in Swift to declare their dependencies using bsInitializer and bsProperties methods.

I expect some additional rough edges will be discovered once this starts getting used in real projects, but it should get things started.

CC @joemasilotti, #37

joemasilotti commented 9 years ago

I'm having trouble instantiating Swift objects with this PR. Is there something I'm missing?

import Blindside

@objc class AppleSearchIndexer: NSObject, SearchIndexer {
    let activityProvider: UserActivityProviderProtocol
    var activity: UserActivityProtocol!

    init(userActivityProvider: UserActivityProviderProtocol) {
        activityProvider = userActivityProvider
    }

    func indexBeer(beer: Beer) {
        activity = activityProvider.beerActivity()
        activity.becomeCurrent()
    }

    func indexPlace(place: FoursquarePlace) {
        activity = activityProvider.placeActivity()
        activity.becomeCurrent()
    }

    static override func bsInitializer() -> BSInitializer {
        let keys = [UserActivityProvider.self]
        return BSInitializer(withClass: self, selector: "initWithUserActivityProvider:", argumentKeysArray: keys)
    }
}

Running this raises a BSInvalidInitializerException exception stating:

selector initWithUserActivityProvider: not found on class .AppleSearchIndexer

briancroom commented 9 years ago

Hey @jmasilotti, I think I know what is going on. Is your UserActivityProviderProtocol also marked as @objc? If not, your Swift init method won't be exposed to the Obj-C runtime, leading to the error you're seeing. I was able to reproduce your issue and fix it by making that change. Yes, that does restrict what types you are able to reference in your injected interfaces. Welcome to the quirky world of Swift bridging!

To help understanding what is going on in these sorts of situations, take a look at the <YourAppName>-Swift.h bridging header that Xcode generates while building your Swift files (this is the same header that you'll want to import in any Objective-C files that need to reference symbols defined in Swift code). It will show you exactly what classes and methods are exposed to the Obj-C runtime and how they are named.

joemasilotti commented 9 years ago

That's exactly what was going on. After I marked everything relevant with @objc Blindside worked! Thanks for the help, @briancroom.

briancroom commented 9 years ago

Great! I'm glad it worked for you.

@jbsf @akitchen do you have any concerns about the changes made here?

akitchen commented 9 years ago

I don’t have any major concerns.  These look like useful changes.

Could you take a moment to resolve merge conflicts vs. newer changes on master?  Then let’s merge!

jbsf commented 9 years ago

No concerns thanks very much!

On Tue, Sep 15, 2015 at 11:27 PM, Andrew Kitchen notifications@github.com wrote:

I don’t have any major concerns. These look like useful changes.

Could you take a moment to resolve merge conflicts vs. newer changes on master? Then let’s merge!

Great! I'm glad it worked for you.

@jbsf @akitchen do you have any concerns about the changes made here?

— Reply to this email directly or view it on GitHub.

— Reply to this email directly or view it on GitHub https://github.com/jbsf/blindside/pull/39#issuecomment-140551873.

briancroom commented 9 years ago

I've just now rebased (hope this doesn't cause you trouble @joemasilotti!) this branch onto master. I also discovered one behavior that doesn't work properly under Xcode 6 and disabled the spec for it when building in that environment.

akitchen commented 9 years ago

Thanks Brian! This is super helpful

joemasilotti commented 9 years ago

Everything still works for me, this is a huge help @briancroom!