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
Related
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.
Is it possible to distribute the code of a class to several files?
Honestly, I think the best route is to break it up into different roles that you compose into your class.
After all, how are you planning on breaking up your class?
Are you going to group methods and attributes according to similarity?
At that point you've just about come up with a role, so you might as well make it a role.
If you look at the source for Rakudo you see things like this:
class Perl6::Metamodel::ClassHOW
does Perl6::Metamodel::Naming
does Perl6::Metamodel::Documenting
does Perl6::Metamodel::LanguageRevision
does Perl6::Metamodel::Stashing
does Perl6::Metamodel::AttributeContainer
does Perl6::Metamodel::MethodContainer
does Perl6::Metamodel::PrivateMethodContainer
does Perl6::Metamodel::MultiMethodContainer
does Perl6::Metamodel::MetaMethodContainer
does Perl6::Metamodel::RoleContainer
does Perl6::Metamodel::MultipleInheritance
does Perl6::Metamodel::DefaultParent
does Perl6::Metamodel::C3MRO
does Perl6::Metamodel::MROBasedMethodDispatch
does Perl6::Metamodel::MROBasedTypeChecking
does Perl6::Metamodel::Trusting
does Perl6::Metamodel::BUILDPLAN
does Perl6::Metamodel::Mixins
does Perl6::Metamodel::ArrayType
does Perl6::Metamodel::BoolificationProtocol
does Perl6::Metamodel::REPRComposeProtocol
does Perl6::Metamodel::InvocationProtocol
does Perl6::Metamodel::ContainerSpecProtocol
does Perl6::Metamodel::Finalization
does Perl6::Metamodel::Concretization
does Perl6::Metamodel::ConcretizationCache
{
… # only 300 lines of code
}
If you do a good job of splitting up your roles, you should be able to use them in many classes.
How many classes in the Rakudo code base do you think compose in the Perl6::Metamodel::Naming role?
That role only provides a few things, and is only 45 lines long.
Here is an abbreviated version.
(All of the code in the methods has been deleted here for brevity.)
role Perl6::Metamodel::Naming {
has $!name;
has $!shortname;
method name($obj) {
…
}
method set_name($obj, $name) {
…
}
method shortname($obj) {
…
}
method set_shortname($obj, $shortname) {
…
}
}
Yes, there always is. But there us no standard supported way (yet anyway).
You can take the approach that Raku takes itself when creating the core settings: concatenate the files into a single file, and compile that. When you're building Rakudo from scratch, that's what's happening when you see the line:
+++ Generating gen/moar/foo
The generated files can be inspected in the gen/moar directory. At one point, I brought this up in a problem solving issue, but that never went anywhere. Perhaps that should be revisited.
You can use augment class. But that currently only makes sense inside a single file, because with multiple files it is creating multiple versions of the same "module" in pre-compilation. And the system is not able to determine what to resolve to what. This is when you realize that pre-compilation of Raku modules currently is creating libraries that need to be statically linkable at runtime.
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?
My goal is to create (find if exist) a tool which can produce swift files from templates.
For example, let’s say I need to create new ViewController with UITableView. It should be based on MVVM architecture with dependency injection. Let’s name this View “PersonsList”.
So, for this task I need to produce:
PersonListViewController
PersonListViewModel
PersonListViewModelProtocol
PersonCell
VM for cell and protocol for VM
Lots of files.
I want to say to my tool something like that
create tableview-template Person
and as a result get generated files. Files should contain empty implementation of each classes.
How should I do that? I am thinking about simple console app but I don’t know which language I should use. Maybe there is a better idea? Maybe there is a ready tool? Any help? :)
You could manually create the templates yourself and then write a short script (in Python / bash / swift etc) that goes through and replaces keywords with arguments you've passed in.
#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: