I'm learning the swift programming language and recently came across the concept of extensions, where you can extend the functionality of an existing class or struct. For example (source):
extension String {
func trimmed() -> String {
self.trimmingCharacters(in: .whitespacesAndNewlines)
}
}
My question is, other than the file where I write this, what other code does this modification impact?
For example, if I declare an extension to String in one file, will it affect the behavior of String in libraries I import? Or if I declare this extension in one file, will it be visible in other files in the same project?
Relatedly, I don't understand how Swift resolves conflicts between extensions. Say for example, I import two libraries which both extend String. Which one takes effect?
I have tried Googling for terms like "swift extensions scope" and "swift conflicting extensions", and haven't found anything that describes fully how it works. I have also noticed Swift doesn't let me redeclare an extension within a single file, but that doesn't answer my question about how extensions from imports affect each other.
The scope of an extension follows the same rules as when creating structs, classes and other types and variables in swift.
By default the extension is internal to the module it is created in and so accessible to all files in that module.
You can change that to public or private if you wish to.
The collisions you reference would occur if two extensions of the same were visible to each other and added a function with the same signature.
So, if you wanted to create your trimmed() extension in several files and give it a different implementation in each file you would need to make them all private to avoid any conflict.
Although… that might not be a good idea as it could be quite confusing with several of these in your project.
Related
It might be basic and wrong but after understanding structures I can't understand where to practically put it.
Inside some class call it Main, I would like to encapsulate a set of variables for dimensions.
I know I can just do :
struct Dimensions{
var w:Int
var h:Int
}
class Main
{
//do things using the structure
}
But since i have a lot of variables and i want it clean , I would like to create a new Swift file and put it inside
So inside a file called Dimensions or else :
import Foundation
struct Dimensions{
var w:Int
var h:Int
}
then the structure is visible to anyone, without even using the Swift file name.
A few questions to ask :
It seems like a bad idea - why ?
How is it different from a Singeltone to share data between classes? (value type?)
What is the right place to put the structure outside the Main class to get some clear code ?
Should I make one file with many not related Structs ?
then the structure is visible to anyone
That is not true. Since your struct is not marked public, only code in your module can access it. Even if you write it in one single file, it is still accessible anywhere in your module.
without even using the Swift file name.
The reason why you are saying this might be because in other languages, you need to import a header file or something like that if you want to use something from another file (I'm not an expert in "other languages"). But Swift organises its code in units of modules, not files.
It seems like a bad idea - why ?
It is not a bad idea. Putting different types in different files is a good way to organise your code. When I go to Car.swift I wouldn't expect to see the class Game.
How is it different from a Singeltone to share data between classes? (value type?)
Here you are just writing things in different files. As far as the compiler is concerned, this is not much different from writing everything in a single file because Swift organises code in modules, not files. The Singleton pattern is something completely different. It is when you only have one shared instance of a type.
What is the right place to put the structure outside the Main class to get some clear code ?
In another file, because Main should really be in its own file.
Should I make one file with many not related Structs ?
No. That is a bad way of organising your code. When you want to find a particular struct, how do you know which file it is in?
This question already has answers here:
Private var is accessible from outside the class
(2 answers)
Closed 6 years ago.
I seem to be misunderstanding something about access control modifiers in Swift. Here is my code from a playground:
class Something {
private (set) var name :String {
get { return "" }
set {}
}
}
var thing = Something();
thing.name = "";
My intuition and experience from other languages tells me that there should be a compiler error on the last line.
The book I'm learning from however states that private means the member being modified is only accessible from the same source file.
Am I safe to assume this scenario would generally be an error in most projects, and this is only because I'm running this code in a playground?
Is the statement that private members can only be accessed from the same source file totally accurate?
This rule is valid for all versions of Swift 2. It is valid for your example as well, and worked because your setter code is in the same file (if I understand your example correctly) in which the setter was invoked.
The top-level assignment expression thing.name = ""; was allowed because it is running in a playground. Outside playgrounds, this particular top-level assignment would be illegal in most cases (there are exceptions!).
Bonus explanation of what constitutes as "top-level code" and where it is applicable; from the official Swift blog here:
However, top-level code is not allowed in most of your Swift source
files. For clarity, any executable statement not written within a
function body, within a class, or otherwise encapsulated is considered
top-level. We have this rule because if top-level code were allowed in
all your files, it would be hard to determine where to start the
program.
...
You’ll notice that earlier we said top-level code isn’t allowed in
most of your app’s source files. The exception is a special file named
“main.swift”, which behaves much like a playground file, but is built
with your app’s source code. The “main.swift” file can contain
top-level code, and the order-dependent rules apply as well. In
effect, the first line of code to run in “main.swift” is implicitly
defined as the main entrypoint for the program. This allows the
minimal Swift program to be a single line — as long as that line is in
“main.swift”.
The book I'm learning from however states that private means the member being modified is only accessible from the same source file.
And your example is accessing it from the same source file. What's the issue?
In Swift 3, private becomes fileprivate, wherein access is allowed anywhere from the same file. private in Swift 3 has the behavior you expect, where access is only allowed within the class/struct/enum itself.
I opened an XCode project produced as a tutorial by Apple ("Auto Layout Cookbook"), when I found two files with a strange naming:
Recipe+Loading.swift
Recipe+Storyboards.swift
Both contain an extension called Recipe. I was not able to find any docs about this kind of naming.
Is there any reason why they named the files this way?
The naming comes from Objective-C where every extension for a class needed a name. For example, a class Recipe could have extension:
#interface Recipe (Loading)
#end
which contained methods related to "Loading".
Such extensions were commonly put into files named Recipe+Loading.h (that is, class Recipe extended with Loading methods).
In Swift extensions don't have a name but old habits die hard. They used the same naming for files.
This is a common naming convention from Objective-C. As you surmised it basically contains extensions to Recipe that pertain to loading and storyboards respectively. It's primarily a way to break up large source files or label extensions to system classes (String, Array, etc.)
For example, I want to use this extension:
import Foundation
extension String {
func exec (str: String) -> Array<String> {
....
}
}
Where should I save it? Should I create a new file extensions.swift?
For global extensions such as the one above I think it would be best to put it in an extensions.swift file. If your extending one of your own classes I find it best to keep it in the same file as the original class so that other developers know about it.
If you have multiple extensions for a particular global class such as String, you could group them into a StringExtensions.swift file.
I'd recommend keeping a group in the project and then creating Files called [Class]Extension. If you store all extension in the same file as mentioned in the other answers you might end up having a lot of issues finding the extension you are looking for and you end up with a file full of different responsibilities. In a small project that might not matter but its better to force good organisation early in a project because you never know which project might grow.
The old-way on objective-c was to name like:
UIView+FrameUtils.h
NSMutableArray+Sort.h
UIColor+HEX.h
NSDictionary+Nil.h
So it's clear what is extended (categorized in objective-c) and what new functional implemented. So you may use this style in Swift too
#import "whatever.h"
...wasn't perfect, but it was very handy for diagnosing circular dependencies, not to mention enforcing modularity.
You could be certain which classes knew about other classes--with the flick of a finger.
If you had to, you could comment out all the import statements, and add them back one at a time, in order to diagnose a dependency issue. It wasn't necessarily fast but it was dead simple.
And if a class didn't import anything other than the obligatory headers, Son, that's one modular class you had there!
If your project had ten classes that didn't import anything, then you knew that they were ten modular classes--you didn't have to package each class into its own Framework or anything like that. Easy.
But now, with Swift's policy of "everybody knows about everything all the time", it seems like it's just down to personal vigilance to sustain modularity. Personal vigilance is the worst kind!
Am I missing something? Is there a way to do these things easily in Swift?
If you want to modularize your Swift code, you should be using modules!
Creating a new module is pretty simple.
Add a new target to your project by clicking the plus sign here:
Select "Framework & Library" for the appropriate platform (iOS/OS X):
Choose "Cocoa Framework" (or Cocoa Touch, platform dependent) and click Next:
Give your module a name and change the language to Swift (or leave it as Objective-C, it doesn't matter, you can use both).
Add a Swift file to your module:
Add some code to your Swift file. Note, the default access level for Swift is internal which means it can be accessed from anywhere within the module but not from outside the module. Any code which we want to use outside the module must be given the public access level.
public class ModularSwift {
public init(){}
public var foo: Int = 0
}
Be sure to build your module (Cmd+B):
Go back to your original target, import the module and start using its code:
import MyModularSwiftCode
let foo = ModularSwift()
Xcode is perfectly happy:
Now, comment out the import statement and notice the errors: