Swift extensions that apply only when you import them
Asked Answered
D

3

7

I have some swift extensions I want to across projects.

I'd like to avoid category pollution though, unless those extensions are requested.

Is it possible to write them so that they only apply if I've done a certain import, like:

import MySwiftExtensions

// Use custom extensions
let x = [1,3,5,7].average()
let y = [1,3,5,7].firstWhere { $0 > 3 }
let z = "campervan".make1337()

I could write these as static methods wrapped in a single letter class (eg: ø.average([1,3,5,7]), like lodash) to achieve the same thing but sometimes you get much more concise usage from instance methods.

Dissident answered 29/4, 2016 at 17:32 Comment(1)
Have you tried putting the extensions into a separate framework and import as needed?Weslee
W
2

You wrote:

I have some swift extensions I want to across projects...

When I have code that I want to use across projects I create a separate framework to hold that code. Then, when I want to use that code in a new project, I embed the framework in that project. Or, for development purposes, I create a workspace that includes the project and the framework. That allows me to work on both at the same time, and then only embed the framework in the final product when it is time to export it.

Once the framework is either embedded or in the same workspace, then you should be able to import it into any individual file in your project with:

import MySwiftExtensions

Any file that does not have the import statement will not have access to the extensions.

EDIT:

Here is a link to a blog that describes how to create a Cocoa Touch Framework. And here is another link that describes in detail how to use workspaces to use frameworks in development projects.

Weslee answered 29/4, 2016 at 19:7 Comment(8)
This sounds like exactly what I want. How to manage this in xcode is new to me. Do you have a link that explains the idea of creating a framework, including it in the workspace, and embedding it in the final product (maybe this?)Dissident
Im sorry, just an osservation. I don't understand the need. In my project usually I've a single file with all extensions, what is the advantage to import a framework to another prj based to 1 file for my case? Isnt fastest to copy it?Steady
@AlessandroOrnano If all you have is a single file, then a framework may be overkill. I have used your approach, too, and it works. But often I have multiple files in my framework, and I don't want to copy them all into my project. I would rather just link against the framework. Also, if you use the framework, you can choose where to import it. And, if you make changes to your framework code, perhaps by adding another extension method, those changes will appear in all projects that use the framework - you won't have to cut and paste. Also, you can create unit tests for just the framework.Weslee
@AlessandroOrnano But you should do what works for you :) For me, frameworks provide greater flexibility and reusability of code.Weslee
For me it make sense wherever you have custom classes with their derivated extensions, but this is only a particular case in front of daily necessities. If you add an extension to your framework your must copy your new version of framework to all projects where you use it !! so what is the difference? However thank you for these commentsSteady
Same thing happened for example to Alamofire, you must re-import framework everytime you need to update to a new available version, just to explain me.Steady
@AlessandroOrnano I'm not familiar with Alamofire, but in the frameworks I create for myself I don't have to cut and paste code to every project that uses the framework. I have to rebuild the framework, but I don't have to manually update the code. Also, only a framework's public classes, methods, etc., will be visible outside the framework, giving me the ability to declare a well-defined public interface. But seriously, do what works best for you :)Weslee
If you have all your projects inside a workspace or with pods sure, what do you speak about is real and work.But if you have many differents separated prj without pods , each of them have a specific framew vers. If you want to update a framework embedded or not you must copy and paste the new package verSteady
S
2

I would like to focus attention on what you reported: "..only apply if I've done a certain import.." It would also mean you want these extensions can be applyed only to a specific class

As reported in this interesting Apple blog chapter and in the official Apple doc you can handle the "Access Control" of your extension

You can extend a class, structure, or enumeration in any access context in which the class, structure, or enumeration is available. Any type members added in an extension have the same default access level as type members declared in the original type being extended. If you extend a public or internal type, any new type members you add will have a default access level of internal. If you extend a private type, any new type members you add will have a default access level of private.

Alternatively, you can mark an extension with an explicit access level modifier (for example, private extension) to set a new default access level for all members defined within the extension. This new default can still be overridden within the extension for individual type members.

/* no access level modifier: default access level will be 'internal' */
    extension UIViewSubClass
    {
        // default access level used: internal
        var helloWorld : String { 
            get {
                return "helloWorld"
            }
        }
    }
    
    // modify default access level to public
    public extension UIViewSubClass
    {
        // default access level used: public
        var helloWorld : String { 
            get {
                return "helloWorld"
            }
        }
    }

The members of extensions marked private are available within the file where they’re defined, and are not available outside that file. Outside the file where the private extension members were defined, any attempt to use them results in an error, and auto-complete wouldn’t even list them

// modify default access level to private
private extension UIViewSubClass
{
    
    var helloWorld : String { 
        get {
            return "helloWorld"
        }
    }
}
Steady answered 29/4, 2016 at 18:24 Comment(0)
W
2

You wrote:

I have some swift extensions I want to across projects...

When I have code that I want to use across projects I create a separate framework to hold that code. Then, when I want to use that code in a new project, I embed the framework in that project. Or, for development purposes, I create a workspace that includes the project and the framework. That allows me to work on both at the same time, and then only embed the framework in the final product when it is time to export it.

Once the framework is either embedded or in the same workspace, then you should be able to import it into any individual file in your project with:

import MySwiftExtensions

Any file that does not have the import statement will not have access to the extensions.

EDIT:

Here is a link to a blog that describes how to create a Cocoa Touch Framework. And here is another link that describes in detail how to use workspaces to use frameworks in development projects.

Weslee answered 29/4, 2016 at 19:7 Comment(8)
This sounds like exactly what I want. How to manage this in xcode is new to me. Do you have a link that explains the idea of creating a framework, including it in the workspace, and embedding it in the final product (maybe this?)Dissident
Im sorry, just an osservation. I don't understand the need. In my project usually I've a single file with all extensions, what is the advantage to import a framework to another prj based to 1 file for my case? Isnt fastest to copy it?Steady
@AlessandroOrnano If all you have is a single file, then a framework may be overkill. I have used your approach, too, and it works. But often I have multiple files in my framework, and I don't want to copy them all into my project. I would rather just link against the framework. Also, if you use the framework, you can choose where to import it. And, if you make changes to your framework code, perhaps by adding another extension method, those changes will appear in all projects that use the framework - you won't have to cut and paste. Also, you can create unit tests for just the framework.Weslee
@AlessandroOrnano But you should do what works for you :) For me, frameworks provide greater flexibility and reusability of code.Weslee
For me it make sense wherever you have custom classes with their derivated extensions, but this is only a particular case in front of daily necessities. If you add an extension to your framework your must copy your new version of framework to all projects where you use it !! so what is the difference? However thank you for these commentsSteady
Same thing happened for example to Alamofire, you must re-import framework everytime you need to update to a new available version, just to explain me.Steady
@AlessandroOrnano I'm not familiar with Alamofire, but in the frameworks I create for myself I don't have to cut and paste code to every project that uses the framework. I have to rebuild the framework, but I don't have to manually update the code. Also, only a framework's public classes, methods, etc., will be visible outside the framework, giving me the ability to declare a well-defined public interface. But seriously, do what works best for you :)Weslee
If you have all your projects inside a workspace or with pods sure, what do you speak about is real and work.But if you have many differents separated prj without pods , each of them have a specific framew vers. If you want to update a framework embedded or not you must copy and paste the new package verSteady
R
0

I don't believe you can do what you want per se, but I've used the following approach to provide functionality to only the specific class that implements an interface:

protocol ExampleProtocol {

}

extension ExampleProtocol where Self: UIViewController{

    // extend what you need to here
}
Retrograde answered 29/4, 2016 at 18:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.