• Stars
    star
    938
  • Rank 48,718 (Top 1.0 %)
  • Language
    Swift
  • License
    MIT License
  • Created almost 7 years ago
  • Updated over 2 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

๐Ÿ—‚ Never use NSSearchPathForDirectoriesInDomains again

logo

AppFolder

AppFolder is a lightweight framework that lets you design a friendly, strongly-typed representation of a directories inside your app's container. All the system directories like "Caches/" and "Application Support/" are already present, and you can add yours using just a few lines of code.

AppFolder has a simple and beautiful interface which was made possible with the help of Swift's dark magic: inheritance ๐Ÿ˜ฑ

If you want to learn more about the idea, check out Introducing AppFolder on Medium.

Usage

import AppFolder

let documents = AppFolder.Documents
let caches = AppFolder.Library.Caches
let cachesURL = caches.url

extension Library.Caches {
    
    class Images: Directory { }
    
    var Images: Images {
        return subdirectory()
    }
    
}

let imageCache = AppFolder.Library.Caches.Images
let imageCacheURL = imageCache.url

Guide

Your app's folder

let documents = AppFolder.Documents
let tmp = AppFolder.tmp
let applicationSupport = AppFolder.Library.Application_Support
let caches = AppFolder.Library.Caches

caches.url // full URL
caches.folderName // "Caches"
caches.subpath // "Library/Caches"

caches.baseURL
// the same as
AppFolder.baseURL

let fileURL = caches.url.appendingPathComponent("cached-file.json")

AppFolder represents a file structure of your app's container and gives you a better understanding of where your files are stored. AppFolder is a main entrance point to your folders. Inside you can find:

  • Documents (AppFolder.Documents). Inside this directory you should store "only documents and other data that is user-generated, or that cannot otherwise be recreated by your application." - iOS Data Storage Guidelines
  • Library/Application Support (AppFolder.Library.Application_Support). "The Application Support directory is a good place to store files that might be in your Documents directory but that shouldn't be seen by users. For example, a database that your app needs but that the user would never open manually." - iOS Storage Best Practices
  • Library/Caches (AppFolder.Library.Caches). Caches directory is the place for "...data that can be downloaded again or regenerated. ...Examples of files you should put in the Caches directory include database cache files and downloadable content, such as that used by magazine, newspaper, and map applications." - iOS Data Storage Guidelines
  • tmp (AppFolder.tmp). "Use this directory to write temporary files that do not need to persist between launches of your app. Your app should remove files from this directory when they are no longer needed; however, the system may purge this directory when your app is not running." - File System Programming Guide

Adding your own folders

Let's assume that we want to declare a "Files" folder inside our "Application Support" directory.

Turns out that each folder in AppFolder is represented by a concrete Directory sublcass. For example, "Application Support is of type Library.Application_Support. To declare our own folder, we need to create a new Directory subclass:

final class Files : Directory { }

By default, folder name will be automatically generated from the class name.

Now we can access our new folder in a very straightforward way:

let filesFolder = AppFolder.Library.Application_Support.appending(Files.self)

But if we want to get a little bit more type-safety, we should put this whole logic into an extension:

extension Library.Application_Support {
    
    final class Files : Directory { }
    
    var Files: Files {
        return subdirectory()
    }
    
}

Now, you may wonder: since var Files is a property, why is var Files... capitalized?

Well, it's an intentional AppFolder design decision. In order to represent a folder structure as accurate as possible, all properties must be written according to their real world names (with spaces substituted by _). So, for example, "Documents" is AppFolder.Documents, and "tmp" is AppFolder.tmp - just as in the "real world".

Naming your classes with _ (for example, class User_Files : Directory) will automically generate folder name with a space ("User Files" in this case)

So, this part should be clear. Now we can use our folder completely intuitively:

let files = AppFolder.Library.Application_Support.Files
let filesURL = files.url

IMPORTANT: Describing folders doesn't automatically create them. AppFolder provides a way to organize your folder structure in code, not to actively manage it on disk. In order to be used, all non-system directories should be explicitly created with FileManager.default.createDirectory(at:) or similar APIs.

Using AppFolder with app groups

AppFolder also supports containers shared with app groups via AppGroupContainer:

enum MyAppGroup : AppGroup {
    static var groupIdentifier: String {
        return "group.com.my-app.my-app-group"
    }
}

let sharedCaches = AppGroupContainer<MyAppGroup>.Library.Caches

This way you can, for example, simplify a creation of a shared Core Data stack without losing control over the process:

let applicationSupportURL = AppGroupContainer<MyAppGroup>.Library.Application_Support.url
let sqliteFileURL = applicationSupportURL.appendingPathComponent("db.sql")
let model = NSManagedObjectModel(contentsOf: sqliteFileURL)
let container = NSPersistentContainer(name: "my-app-db", managedObjectModel: model!)

To learn more about app groups, check out the App Extension Programming Guide: Handling Common Scenarios (section "Sharing Data with Your Containing App").

Customizing folder name

If you're not happy with automatically generated name, you can provide your own:

final class CustomNamedFolder : Directory {
    override var folderName: String {
        return "Custom"
    }
}

Using AppFolder on macOS

AppFolder uses NSHomeDirectory() under the hood, so, depending on your macOS app, it might just locate you to the user's home directory, as documentation states:

In macOS, it is the applicationโ€™s sandbox directory or the current userโ€™s home directory (if the application is not in a sandbox)

NSHomeDirectory() reference

AppFolder.tmp is also deprecated on macOS because it may give results different from NSTemporaryDirectory(). To use temporary directory on macOS, we recommend using FileManager.default.temporaryDirectory.

Disclaimer

AppFolder is in a very early stage. Some stuff will probably be broken at some point.

Installation

Swift Package Manager

Starting with Xcode 11, AppFolder is officially available only via Swift Package Manager.

In Xcode 11 or greater, in you project, select: File > Swift Packages > Add Pacakage Dependency

In the search bar type

https://github.com/dreymonde/AppFolder

Then proceed with installation.

If you can't find anything in the panel of the Swift Packages you probably haven't added yet your github account. You can do that under the Preferences panel of your Xcode, in the Accounts section.

For command-line based apps, you can just add this directly to your Package.swift file:

dependencies: [
    .package(url: "https://github.com/dreymonde/AppFolder", from: "0.2.0"),
]

Manual

Of course, you always have an option of just copying-and-pasting the code - AppFolder is just a few files, so feel free.

Deprecated dependency managers

Last AppFolder version to support Carthage and Cocoapods is 0.2.0. Carthage and Cocoapods will no longer be officially supported.

Carthage:

github "dreymonde/AppFolder" ~> 0.2.0

Cocoapods:

pod 'AppFolder', '~> 0.2.0'

More Repositories

1

Time

๐Ÿ•ฐ Type-safe time calculations in Swift
Swift
1,073
star
2

Delegated

๐Ÿ‘ทโ€โ™€๏ธ Closure-based delegation without memory leaks
Swift
703
star
3

Shallows

๐Ÿ›ถ Your lightweight persistence toolbox
Swift
622
star
4

NiceNotifications

๐Ÿ”” Create rich local notifications experiences on iOS with incredible ease
Swift
269
star
5

Placeholders

๐Ÿ…ฟ๏ธ Define multiple placeholders for UITextField and animate their change
Swift
199
star
6

ScheduledNotificationsViewController

See all your scheduled local notifications in one place
Swift
170
star
7

DateBuilder

๐Ÿ“† Create dates and date components easily (e.g. "first Thursday of the next month")
Swift
136
star
8

TheGreatGame

๐Ÿ† Open-source first-class iOS & watchOS app dedicated to Womenโ€™s Euro 2017
Swift
135
star
9

Paperville

๐Ÿ™ Design a city in Swift code (๏ฃฟWWDC 2018 submission, ACCEPTED)
Swift
51
star
10

TelegraphKit

๐Ÿ“œ The ultimate solution for showing ad hoc, server-editable web content (FAQs, Tutorials, Privacy Policy, etc.) in your iOS apps
Swift
51
star
11

DonateToUkraine

๐Ÿ‡บ๐Ÿ‡ฆ Implement "donate to Ukraine" inside your app, with Apple Pay
Swift
25
star
12

Alba

๐ŸŽ™ Stateful event observing engine [DEPRECATED]
Swift
19
star
13

Avenues

๐ŸŒ… [WIP] Idiomatic image fetching and caching in Swift.
Swift
13
star
14

Subviews

๐Ÿงฉ @โ€‹Subview and other ways of making UIKit more fun to use
Swift
9
star
15

Timers

โฒ๏ธ Intuitive Swift timers with automatic memory management
Swift
8
star
16

SwiftyNURE

Swift framework for NURE API (CIST)
Swift
3
star
17

Operacjas

๐Ÿ›  [DEPRECATED] Unlocking the full glory of NSOperations
Swift
2
star
18

Swift-hints

1
star
19

DynamicInstance

Swift
1
star
20

Operations

[WIP] NSOperations for 2018
Swift
1
star
21

uahelp-js-scripts

JavaScript
1
star
22

Avenues-Shallows

Making caching even better
Swift
1
star
23

SofarKit

Access Sofar admin data with Swift [WIP]
Swift
1
star
24

Light

๐Ÿ•Š Super thin networking layer built on top of Shallows
Swift
1
star