Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Dividing a Swift application's components into Swift modules

I'm writing an iOS application in Swift, and I'm trying to figure out how to organize the project into separate modules. I'm using an MVVM architecture, and I want to make the Model, ViewModel, and View components separate Swift modules that make only subsets of themselves accessible to the modules that import them. The files in the View would import the ViewModel, and files in the ViewModel would import the Model. How can I accomplish this? Note that I'm not trying to create libraries that multiple applications can share. I'm just trying to enforce separation of components using modules.

EDIT: Maybe the question is, "What mechanism should I use to create modules aside from the one that comes with the initial iOS application project?"

One of the answers in "How do you use Namespaces in Swift?" https://stackoverflow.com/a/24032860/215400 says, "classes (etc) are implicitly scoped by the module (Xcode target) they are in." From that, one might conclude that targets correspond to modules and that the answer is to create separate targets within an Xcode project, but I tried that earlier, and tskulbru is saying that I need multiple Xcode projects.

Regarding multiple Xcode projects, the File > New > Project > iOS Framework & Library > Cocoa Touch Framework option didn't look right because it's supposed to be for things that use UIKit, and two of the modules I want to create shouldn't depend on UIKit. The other "Framework & Library" option, Cocoa Touch static library, isn't an option with Swift.

Another StackOverflow post mentioned using private Pods. After spending an hour working on that, I concluded that it wasn't the right solution because I shouldn't have to edit these modules in different workspaces.

like image 789
Christopher Simmons Avatar asked Jan 01 '16 18:01

Christopher Simmons


2 Answers

This isn't possible without creating separate projects for the modules you want to create. This is because the way Swift handles namespacing.

Eonil answered this better than me: https://stackoverflow.com/a/24032860/215400 (Copy below)

Answered by SevenTenEleven in the Apple dev forum:

Namespaces are not per-file; they're per-target (based on the "Product Module Name" build setting). So you'd end up with something like this:

import FrameworkA
import FrameworkB

FrameworkA.foo()

All Swift declarations are considered to be part of some module, so even when you say "NSLog" (yes, it still exists) you're getting what Swift thinks of as "Foundation.NSLog".

Also Chris Lattner tweeted about namespacing.

Namespacing is implicit in swift, all classes (etc) are implicitly scoped by the module (Xcode target) they are in. no class prefixes needed

like image 170
tskulbru Avatar answered Oct 17 '22 15:10

tskulbru


From my perspective if you want to encapsulate your components, probably you have two solutions:

  • Framework
  • Internal cocoapods

Both solutions will give you fully encapsulated modules, where you can define API that will be available in project through public keyword. All other things will be not visible in your core project.

Managing your project will cost you a lot more time, but if you write this using SOLID principles, probably you will get more reusable code and those frameworks could be imported to other project just using import definition.

like image 41
user3292998 Avatar answered Oct 17 '22 15:10

user3292998