├── .swift-version ├── .codecov.yml ├── Tests ├── LinuxMain.swift └── OnceTests │ ├── Utils.swift │ ├── XCTestManifests.swift │ ├── TimesPredicateTests.swift │ ├── TokenTests.swift │ └── PersistentTokenTests.swift ├── Once.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist ├── xcshareddata │ └── xcschemes │ │ ├── Once-watchOS.xcscheme │ │ ├── Once-iOS.xcscheme │ │ ├── Once-tvOS.xcscheme │ │ └── Once-macOS.xcscheme └── project.pbxproj ├── Sources └── Once │ ├── Scope.swift │ ├── TimesPredicate.swift │ ├── Token.swift │ ├── Lock.swift │ ├── Atom.swift │ └── PersistentToken.swift ├── Package.swift ├── Once.podspec ├── Configs ├── OnceTests.plist └── Once.plist ├── LICENSE ├── .travis.yml ├── .gitignore ├── README.zh_cn.md └── README.md /.swift-version: -------------------------------------------------------------------------------- 1 | 5.0 -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "Tests/" 3 | 4 | comment: 5 | layout: header, changes, diff 6 | -------------------------------------------------------------------------------- /Tests/LinuxMain.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import OnceTests 3 | 4 | XCTMain([ 5 | testCase(OnceTests.allTests) 6 | ]) 7 | -------------------------------------------------------------------------------- /Once.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Sources/Once/Scope.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public enum Scope { 4 | 5 | case install 6 | 7 | case version 8 | 9 | case session 10 | 11 | case since(Date) 12 | 13 | case until(Date) 14 | } 15 | -------------------------------------------------------------------------------- /Tests/OnceTests/Utils.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | func asyncAndWait(concurrent: Int, block: @escaping () -> Void) { 4 | 5 | let g = DispatchGroup() 6 | for _ in 0.. [XCTestCaseEntry] { 5 | return [ 6 | testCase(TokenTests.allTests), 7 | testCase(TimesPredicateTests.allTests), 8 | testCase(PersistentTokenTests.allTests) 9 | ] 10 | } 11 | #endif 12 | -------------------------------------------------------------------------------- /Once.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Package.swift: -------------------------------------------------------------------------------- 1 | // swift-tools-version:5.0 2 | 3 | import PackageDescription 4 | 5 | let package = Package( 6 | name: "Once", 7 | products: [ 8 | .library(name: "Once", targets: ["Once"]) 9 | ], 10 | targets: [ 11 | .target(name: "Once", dependencies: []), 12 | .testTarget(name: "OnceTests", dependencies: ["Once"]) 13 | ] 14 | ) 15 | -------------------------------------------------------------------------------- /Once.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = "Once" 3 | s.version = "1.0.0" 4 | s.summary = "Once allows you to manage the number of executions of a task using an intuitive API." 5 | s.homepage = "https://github.com/luoxiu/Once" 6 | s.license = { :type => "MIT", :file => "LICENSE" } 7 | s.author = { "Quentin Jin" => "luoxiustm@gmail.com" } 8 | s.source = { :git => "https://github.com/luoxiu/Once.git", :tag => s.version.to_s } 9 | s.source_files = "Sources/**/*" 10 | s.swift_version = "5.0" 11 | 12 | s.ios.deployment_target = "10.0" 13 | s.osx.deployment_target = "10.12" 14 | s.watchos.deployment_target = "3.0" 15 | s.tvos.deployment_target = "10.0" 16 | end 17 | -------------------------------------------------------------------------------- /Tests/OnceTests/TimesPredicateTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import Once 3 | 4 | class TimesPredicateTests: XCTestCase { 5 | 6 | func testTimesChecker() { 7 | 8 | XCTAssertTrue(TimesPredicate.equalTo(1).evaluate(1)) 9 | XCTAssertTrue(TimesPredicate.lessThan(1).evaluate(0)) 10 | XCTAssertTrue(TimesPredicate.moreThan(1).evaluate(2)) 11 | 12 | XCTAssertFalse(TimesPredicate.lessThan(1).evaluate(2)) 13 | XCTAssertFalse(TimesPredicate.moreThan(1).evaluate(0)) 14 | 15 | XCTAssertTrue(TimesPredicate.moreThanOrEqualTo(0).evaluate(0)) 16 | XCTAssertTrue(TimesPredicate.lessThanOrEqualTo(1).evaluate(0)) 17 | } 18 | 19 | static var allTests = [ 20 | ("testTimesChecker", testTimesChecker) 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /Configs/OnceTests.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /Sources/Once/TimesPredicate.swift: -------------------------------------------------------------------------------- 1 | public struct TimesPredicate { 2 | 3 | private let contains: (Int) -> Bool 4 | 5 | public static func equalTo(_ n: Int) -> TimesPredicate { 6 | return TimesPredicate { $0 == n } 7 | } 8 | 9 | public static func lessThan(_ n: Int) -> TimesPredicate { 10 | return TimesPredicate { $0 < n } 11 | } 12 | 13 | public static func moreThan(_ n: Int) -> TimesPredicate { 14 | return TimesPredicate { $0 > n } 15 | } 16 | 17 | public static func moreThanOrEqualTo(_ n: Int) -> TimesPredicate { 18 | return TimesPredicate { $0 > n || $0 == n } 19 | } 20 | 21 | public static func lessThanOrEqualTo(_ n: Int) -> TimesPredicate { 22 | return TimesPredicate { $0 < n || $0 == n } 23 | } 24 | 25 | public func evaluate(_ times: Int) -> Bool { 26 | return contains(times) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Once/Token.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public final class Token { 4 | 5 | private let done = Atom(value: false) 6 | 7 | private init() { } 8 | 9 | public func `do`(_ task: () -> Void) { 10 | done.once_run(task) 11 | } 12 | 13 | public static func `do`(file: String = #file, line: Int = #line, column: Int = #column, _ task: () -> Void) { 14 | Token.makeStatic(file: file, line: line, column: column).do(task) 15 | } 16 | } 17 | 18 | extension Token { 19 | 20 | public static func make() -> Token { 21 | return Token() 22 | } 23 | } 24 | 25 | extension Token { 26 | 27 | private static let registry = Atom<[String: Token]>(value: [:]) 28 | 29 | public static func makeStatic( 30 | file: String = #file, 31 | line: Int = #line, 32 | column: Int = #column 33 | ) 34 | -> Token 35 | { 36 | let key = "\(file)-\(line)-\(column))" 37 | return registry.once_get(key, Token()) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /Configs/Once.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | FMWK 17 | CFBundleShortVersionString 18 | 0.0.1 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | NSHumanReadableCopyright 24 | Copyright © 2018 Quentin Jin. All rights reserved. 25 | NSPrincipalClass 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /Tests/OnceTests/TokenTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import Once 3 | 4 | class TokenTests: XCTestCase { 5 | 6 | let count = 10_000 7 | 8 | func testMake() { 9 | let counter = Atom(value: 0) 10 | let token = Token.make() 11 | 12 | var i = 0 13 | asyncAndWait(concurrent: count) { 14 | counter.add(1) 15 | token.do { i += 1 } 16 | } 17 | 18 | XCTAssertEqual(counter.get(), count) 19 | XCTAssertEqual(i, 1) 20 | } 21 | 22 | func testStaticMake() { 23 | let tokens = Atom<[Token]>(value: []) 24 | 25 | asyncAndWait(concurrent: count) { 26 | tokens.append(Token.makeStatic()) 27 | } 28 | 29 | var i = 0 30 | tokens.get().forEach { 31 | $0.do { i += 1 } 32 | } 33 | 34 | XCTAssertTrue(tokens.get().count == count) 35 | XCTAssertTrue(i == 1) 36 | } 37 | 38 | static var allTests = [ 39 | ("testMake", testMake), 40 | ("testStaticMake", testStaticMake) 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 Quentin Jin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Sources/Once/Lock.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | #if canImport(os) 4 | private final class OSUnfairLock: NSLocking { 5 | 6 | private var s = os_unfair_lock_s() 7 | 8 | func lock() { 9 | os_unfair_lock_lock(&s) 10 | } 11 | 12 | func unlock() { 13 | os_unfair_lock_unlock(&s) 14 | } 15 | } 16 | #endif 17 | 18 | final class DispatchSemaphoreLock: NSLocking { 19 | 20 | private let semaphore = DispatchSemaphore(value: 1) 21 | 22 | func lock() { 23 | semaphore.wait() 24 | } 25 | 26 | func unlock() { 27 | semaphore.signal() 28 | } 29 | } 30 | 31 | final class Lock: NSLocking { 32 | 33 | private let locking: NSLocking 34 | 35 | init() { 36 | #if canImport(os) 37 | locking = OSUnfairLock() 38 | #else 39 | locking = NSLock() 40 | #endif 41 | } 42 | 43 | func lock() { 44 | locking.lock() 45 | } 46 | 47 | func unlock() { 48 | locking.unlock() 49 | } 50 | } 51 | 52 | extension NSLocking { 53 | 54 | func withLock(_ body: () -> T) -> T { 55 | lock() 56 | defer { unlock() } 57 | return body() 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | branches: 2 | only: 3 | - master 4 | 5 | language: objective-c 6 | osx_image: xcode10 7 | 8 | matrix: 9 | include: 10 | - os: osx 11 | env: 12 | - SCHEME="Once-iOS" 13 | - SDK="iphonesimulator12.0" 14 | - DESTINATION="OS=12.0,name=iPhone X" 15 | - os: osx 16 | env: 17 | - SCHEME="Once-macOS" 18 | - SDK="macosx10.13" 19 | - DESTINATION="arch=x86_64" 20 | - os: osx 21 | env: 22 | - SCHEME="Once-tvOS" 23 | - SDK="appletvsimulator12.0" 24 | - DESTINATION="OS=12.0,name=Apple TV 4K" 25 | - os: linux 26 | sudo: required 27 | dist: trusty 28 | 29 | before_install: 30 | - if [[ $TRAVIS_OS_NAME == 'osx' ]]; then 31 | gem install xcpretty --no-rdoc --no-ri --no-document --quiet; 32 | fi 33 | - if [[ $TRAVIS_OS_NAME == 'linux' ]]; then 34 | eval "$(curl -sL https://swiftenv.fuller.li/install.sh)"; 35 | fi 36 | 37 | script: 38 | - if [[ $TRAVIS_OS_NAME == 'osx' ]]; then 39 | xcodebuild clean build test -project Once.xcodeproj -scheme "$SCHEME" -sdk "$SDK" -destination "$DESTINATION" -enableCodeCoverage YES | xcpretty; 40 | fi 41 | - if [[ $TRAVIS_OS_NAME == 'linux' ]]; then 42 | swift build; 43 | swift test; 44 | fi 45 | 46 | after_success: 47 | if [[ $TRAVIS_OS_NAME == 'osx' ]]; then 48 | bash <(curl -s https://codecov.io/bash) -J 'Once'; 49 | fi -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xccheckout 23 | *.xcscmblueprint 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | *.ipa 28 | *.dSYM.zip 29 | *.dSYM 30 | 31 | ## Playgrounds 32 | timeline.xctimeline 33 | playground.xcworkspace 34 | 35 | # Swift Package Manager 36 | # 37 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 38 | # Packages/ 39 | # Package.pins 40 | .build/ 41 | 42 | # CocoaPods 43 | # 44 | # We recommend against adding the Pods directory to your .gitignore. However 45 | # you should judge for yourself, the pros and cons are mentioned at: 46 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 47 | # 48 | # Pods/ 49 | 50 | # Carthage 51 | # 52 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 53 | # Carthage/Checkouts 54 | 55 | Carthage/Build 56 | 57 | # fastlane 58 | # 59 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 60 | # screenshots whenever they are needed. 61 | # For more information about the recommended setup visit: 62 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 63 | 64 | fastlane/report.xml 65 | fastlane/Preview.html 66 | fastlane/screenshots 67 | fastlane/test_output 68 | -------------------------------------------------------------------------------- /Sources/Once/Atom.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | final class Atom { 4 | 5 | private let lock: NSLocking 6 | private var value: Value 7 | 8 | init(value: Value, lock: NSLocking = Lock()) { 9 | self.lock = lock 10 | self.value = value 11 | } 12 | 13 | func withLock(_ body: (Value) throws -> Result) rethrows -> Result { 14 | lock.lock() 15 | defer { lock.unlock() } 16 | return try body(value) 17 | } 18 | 19 | func withLockMutating(_ body: (inout Value) throws -> Result) rethrows -> Result { 20 | lock.lock() 21 | defer { lock.unlock() } 22 | return try body(&value) 23 | } 24 | 25 | func get() -> Value { 26 | return withLock { $0 } 27 | } 28 | 29 | func set(_ new: Value) { 30 | return withLockMutating { $0 = new } 31 | } 32 | 33 | func exchange(with new: Value) -> Value { 34 | return withLockMutating { 35 | let old = $0 36 | $0 = new 37 | return old 38 | } 39 | } 40 | } 41 | 42 | extension Atom where Value: AdditiveArithmetic { // Int 43 | 44 | @discardableResult 45 | func add(_ i: Value) -> Value { 46 | return withLockMutating { 47 | let old = $0 48 | $0 += i 49 | return old 50 | } 51 | } 52 | } 53 | 54 | extension Atom where Value: RangeReplaceableCollection { // Array 55 | 56 | func append(_ new: Value.Element) { 57 | withLockMutating { 58 | $0.append(new) 59 | } 60 | } 61 | } 62 | 63 | // MARK: Bool + Once 64 | 65 | extension Atom where Value == Bool { 66 | 67 | func once_run(_ task: () -> Void) { 68 | if value { return } 69 | 70 | withLockMutating { 71 | if $0 { return } 72 | task() 73 | $0 = true 74 | } 75 | } 76 | } 77 | 78 | // MARK: Dictionary + Once 79 | 80 | protocol DictionaryProtocol { 81 | associatedtype K: Hashable 82 | associatedtype V 83 | 84 | var dict: Dictionary { 85 | get set 86 | } 87 | } 88 | 89 | extension Dictionary: DictionaryProtocol { 90 | 91 | var dict: Dictionary { 92 | get { return self } 93 | set { self = newValue } 94 | } 95 | } 96 | 97 | extension Atom where Value: DictionaryProtocol { 98 | 99 | func once_get(_ key: Value.K, _ make: @autoclosure () -> Value.V) -> Value.V { 100 | if let v = value.dict[key] { 101 | return v 102 | } 103 | 104 | return withLockMutating { 105 | if let v = $0.dict[key] { return v } 106 | let v = make() 107 | $0.dict[key] = v 108 | return v 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /Once.xcodeproj/xcshareddata/xcschemes/Once-watchOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 33 | 34 | 35 | 36 | 46 | 47 | 53 | 54 | 55 | 56 | 57 | 58 | 64 | 65 | 71 | 72 | 73 | 74 | 76 | 77 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /README.zh_cn.md: -------------------------------------------------------------------------------- 1 | # Once 2 | 3 |

4 | 5 | [![Build Status](https://travis-ci.org/luoxiu/Once.svg?branch=master)](https://travis-ci.org/luoxiu/Once) 6 | ![release](https://img.shields.io/github/v/release/luoxiu/Once?include_prereleases) 7 | ![install](https://img.shields.io/badge/install-spm%20%7C%20cocoapods%20%7C%20carthage-ff69b4) 8 | ![platform](https://img.shields.io/badge/platform-ios%20%7C%20macos%20%7C%20watchos%20%7C%20tvos%20%7C%20linux-lightgrey) 9 | ![license](https://img.shields.io/github/license/luoxiu/combinex?color=black) 10 | 11 |

12 | 13 | Once 可以让你用直观的 API 管理任务的执行次数。 14 | 15 | ## Highlight 16 | 17 | - [x] 安全 18 | - [x] 高效 19 | - [x] 持久化 20 | 21 | ## Usage 22 | 23 | ### Token 24 | 25 | `Token` 在内存中记录任务的执行次数,它可以让任务在整个 app 生命期内只执行一次。 26 | 27 | 你可以把它看作 OC 中 `dispatch_once` 的替代品: 28 | 29 | ```objectivec 30 | static dispatch_once_t token; 31 | dispatch_once(&token, ^{ 32 | // do something only once 33 | }); 34 | ``` 35 | 36 | 使用 `Token` 的 swift 代码如下: 37 | 38 | ```swift 39 | let token = Token.makeStatic() 40 | token.do { 41 | // do something only once 42 | } 43 | ``` 44 | 45 | 或者,更简单一点: 46 | 47 | ```swift 48 | Token.do { 49 | // do something only once 50 | } 51 | ``` 52 | 53 | 你也可以不用 `static`: 54 | 55 | ```swift 56 | class Manager { 57 | let loadToken = Token.make() 58 | 59 | func ensureLoad() { 60 | loadToken.do { 61 | // do something only once per manager. 62 | } 63 | } 64 | } 65 | ``` 66 | 67 | ### PersistentToken 68 | 69 | 不同于 `Token`,`PersistentToken` 会持久化任务的执行历史(使用 `UserDefault`)。 70 | 71 | `PersistentToken` 根据 `Scope` 和 `TimesPredicate` 判断是否应该执行本次任务。 72 | 73 | #### Scope 74 | 75 | `Scope` 表示时间范围。它是一个枚举: 76 | 77 | - `.install`: 从应用安装到现在 78 | - `.version`: 从应用升级到现在 79 | - `.session`: 从应用启动到现在 80 | - `.since(let since)`: 从 since 到现在 81 | - `.until(let until)`: 从开始到 until 82 | 83 | #### TimesPredicate 84 | 85 | `TimesPredicate` 表示次数范围。 86 | 87 | ```swift 88 | let p0 = TimesPredicate.equalTo(1) 89 | let p1 = TimesPredicate.lessThan(1) 90 | let p2 = TimesPredicate.moreThan(1) 91 | let p3 = TimesPredicate.lessThanOrEqualTo(1) 92 | let p4 = TimesPredicate.moreThanOrEqualTo(1) 93 | ``` 94 | 95 | #### do 96 | 97 | 你可以使用 `Scope` 和 `TimesPredicate` 组合成任意你想要的计划,而这,同样是线程安全的。 98 | 99 | ```swift 100 | let token = PersistentToken.make("showTutorial") 101 | token.do(in: .version, if: .equalTo(0)) { 102 | app.showTutorial() 103 | } 104 | 105 | // or 106 | let later = 2.days.later 107 | token.do(in: .until(later), if: .lessThan(5)) { 108 | app.showTutorial() 109 | } 110 | ``` 111 | 112 | #### done 113 | 114 | 有时,你的异步任务可能会失败,你并不想把失败的任务标记为 done,你可以: 115 | 116 | ```swift 117 | let token = PersistentToken.make("showAD") 118 | token.do(in: .install, if: .equalTo(0)) { task in 119 | networkService.fetchAD { result in 120 | if result.isSuccess { 121 | showAD(result) 122 | task.done() 123 | } 124 | } 125 | } 126 | ``` 127 | 128 | 要提醒的是,这时的判断就不再是绝对安全的了——如果有多个线程同时检查该 token 的话,但这应该很少发生,😉。 129 | 130 | #### reset 131 | 132 | 你还可以清除一个任务的执行历史: 133 | 134 | ```swift 135 | token.reset() 136 | ``` 137 | 138 | 清除所有任务的执行历史也是允许的,但要后果自负: 139 | 140 | ```swift 141 | PersistentToken.resetAll() 142 | ``` 143 | 144 | ## 安装 145 | 146 | ### CocoaPods 147 | 148 | ```ruby 149 | pod 'Once', '~> 1.0.0' 150 | ``` 151 | 152 | ### Carthage 153 | 154 | ```ruby 155 | github "luoxiu/Once" ~> 1.0.0 156 | ``` 157 | 158 | ### Swift Package Manager 159 | 160 | ```swift 161 | dependencies: [ 162 | .package(url: "https://github.com/luoxiu/Once", .upToNextMinor(from: "1.0.0")) 163 | ] 164 | ``` 165 | 166 | ## 贡献 167 | 168 | 遇到一个 bug?想要更多的功能?尽管开一个 issue 或者直接提交一个 pr 吧! -------------------------------------------------------------------------------- /Once.xcodeproj/xcshareddata/xcschemes/Once-iOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /Once.xcodeproj/xcshareddata/xcschemes/Once-tvOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /Once.xcodeproj/xcshareddata/xcschemes/Once-macOS.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 31 | 32 | 34 | 40 | 41 | 42 | 43 | 44 | 50 | 51 | 52 | 53 | 54 | 55 | 65 | 66 | 72 | 73 | 74 | 75 | 76 | 77 | 83 | 84 | 90 | 91 | 92 | 93 | 95 | 96 | 99 | 100 | 101 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Once([简体中文](README.zh_cn.md)) 2 | 3 |

4 | 5 | [![Build Status](https://travis-ci.org/luoxiu/Once.svg?branch=master)](https://travis-ci.org/luoxiu/Once) 6 | ![release](https://img.shields.io/github/v/release/luoxiu/Once?include_prereleases) 7 | ![install](https://img.shields.io/badge/install-spm%20%7C%20cocoapods%20%7C%20carthage-ff69b4) 8 | ![platform](https://img.shields.io/badge/platform-ios%20%7C%20macos%20%7C%20watchos%20%7C%20tvos%20%7C%20linux-lightgrey) 9 | ![license](https://img.shields.io/github/license/luoxiu/combinex?color=black) 10 | 11 | 12 | 13 | Once allows you to manage the number of executions of a task using an intuitive API. 14 | 15 | 16 | ## Highlight 17 | 18 | - [x] Safe 19 | - [x] Efficient 20 | - [x] Persistent 21 | 22 | ## Usage 23 | 24 | ### Token 25 | 26 | `Token` records the number of times the task is executed in memory, which allows the task to be executed only once during the entire lifetime of the app. 27 | 28 | You can think of it as an alternative to `dispatch_once` in OC: 29 | 30 | ```objectivec 31 | static dispatch_once_t token; 32 | dispatch_once(&token, ^{ 33 | // do something only once 34 | }); 35 | ``` 36 | 37 | The swift code using `Token` is as follows: 38 | 39 | ```swift 40 | let token = Token.makeStatic() 41 | token.do { 42 | // do something only once 43 | } 44 | ``` 45 | 46 | Or, more simple: 47 | 48 | ```swift 49 | Token.do { 50 | // do something only once 51 | } 52 | ``` 53 | 54 | You can also don't use `static`: 55 | 56 | ```swift 57 | class Manager { 58 | let loadToken = Token.make() 59 | 60 | func ensureLoad() { 61 | loadToken.do { 62 | // do something only once per manager. 63 | } 64 | } 65 | } 66 | ``` 67 | 68 | #### PersistentToken 69 | 70 | Unlike `run`, `do` will persist the execution history of the task (using `UserDefault`). 71 | 72 | `PersistentToken` determines whether this task should be executed based on `Scope` and `TimesPredicate`. 73 | 74 | #### Scope 75 | 76 | `Scope` represents a time range, it is an enum: 77 | 78 | - `.install`: from app installation 79 | - `.version`: from app update 80 | - `.session`: from app launch 81 | - `.since(let since)`: from `since(Date)` 82 | - `.until(let until)`: to `until(Date)` 83 | 84 | #### TimesPredicate 85 | 86 | `TimesPredicate` represents a range of times. 87 | 88 | ```swift 89 | let p0 = TimesPredicate.equalTo(1) 90 | let p1 = TimesPredicate.lessThan(1) 91 | let p2 = TimesPredicate.moreThan(1) 92 | let p3 = TimesPredicate.lessThanOrEqualTo(1) 93 | let p4 = TimesPredicate.moreThanOrEqualTo(1) 94 | ``` 95 | 96 | #### do 97 | 98 | You can use `Scope` and `TimesPredicate` to make any plan you want, and, yes, it is thread-safe. 99 | 100 | ```swift 101 | let token = PersistentToken.make("showTutorial") 102 | token.do(in: .version, if: .equalTo(0)) { 103 | app.showTutorial() 104 | } 105 | 106 | // or 107 | let later = 2.days.later 108 | token.do(in: .until(later), if: .lessThan(5)) { 109 | app.showTutorial() 110 | } 111 | ``` 112 | 113 | #### done 114 | 115 | Sometimes your asynchronous task may fail. You don't want to mark the failed task as done. You can: 116 | 117 | ```swift 118 | let token = PersistentToken.make("showAD") 119 | token.do(in: .install, if: .equalTo(0)) { task in 120 | networkService.fetchAD { result in 121 | if result.isSuccess { 122 | showAD(result) 123 | task.done() 124 | } 125 | } 126 | } 127 | ``` 128 | 129 | But at this time, the judgment is no longer absolutely safe - if there are multiple threads checking the token at the same time, but it should rarely happen, 😉. 130 | 131 | #### reset 132 | 133 | You can also clear the execution history of a task: 134 | 135 | ```swift 136 | token.reset() 137 | ``` 138 | 139 | It is also permissible to clear the execution history of all tasks, but at your own risk: 140 | 141 | ```swift 142 | PersistentToken.resetAll() 143 | ``` 144 | 145 | ## Installation 146 | 147 | ### CocoaPods 148 | 149 | ```ruby 150 | pod 'Once', '~> 1.0.0' 151 | ``` 152 | 153 | ### Carthage 154 | 155 | ```ruby 156 | github "luoxiu/Once" ~> 1.0.0 157 | ``` 158 | 159 | ### Swift Package Manager 160 | 161 | ```swift 162 | dependencies: [ 163 | .package(url: "https://github.com/luoxiu/Once", .upToNextMinor(from: "1.0.0")) 164 | ] 165 | ``` 166 | 167 | ## Contributing 168 | 169 | Encounter a bug? want more features? Feel free to open an issue or submit a pr directly! 170 | -------------------------------------------------------------------------------- /Sources/Once/PersistentToken.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | public final class PersistentToken { 4 | 5 | private enum Key { 6 | static let version = "com.v2ambition.once.version" 7 | static let versionUpdateDate = "com.v2ambition.once.versionUpdateDate" 8 | 9 | static let context = "com.v2ambition.once.context" 10 | static let timestamps = "timestamps" 11 | } 12 | 13 | private static let registry = Atom<[String: PersistentToken]>(value: [:]) 14 | private static let isInitialized = Atom(value: false, lock: DispatchSemaphoreLock()) 15 | 16 | private static var sessionStartDate = Date() 17 | private static var versionUpdateDate: Date? 18 | 19 | public let name: String 20 | 21 | private let lock = NSRecursiveLock() 22 | private let contextKey: String 23 | private var context: [String: Any] 24 | 25 | private init(_ name: String) { 26 | self.name = name 27 | self.contextKey = Key.context + "." + name 28 | self.context = UserDefaults.standard.object(forKey: self.contextKey) as? [String: Any] ?? [:] 29 | } 30 | 31 | public static func make(_ name: String) -> PersistentToken { 32 | return registry.once_get(name, PersistentToken(name)) 33 | } 34 | 35 | private func flushContext() { 36 | UserDefaults.standard.set(context, forKey: contextKey) 37 | } 38 | 39 | static func initialize() { 40 | sessionStartDate = Date() 41 | 42 | let currentVersion = appVersion() 43 | if UserDefaults.standard.string(forKey: Key.version) == currentVersion { 44 | versionUpdateDate = UserDefaults.standard.object(forKey: Key.versionUpdateDate) as? Date 45 | } else { 46 | UserDefaults.standard.set(currentVersion, forKey: Key.version) 47 | UserDefaults.standard.set(Date(), forKey: Key.versionUpdateDate) 48 | versionUpdateDate = Date() 49 | } 50 | } 51 | 52 | private static func ensureInitialized() { 53 | isInitialized.once_run(initialize) 54 | } 55 | 56 | private var timestamps: [Date] { 57 | get { 58 | return context[Key.timestamps] as? [Date] ?? [] 59 | } 60 | set { 61 | context[Key.timestamps] = newValue 62 | } 63 | } 64 | } 65 | 66 | extension PersistentToken { 67 | 68 | private func filteredTimestamps(in scope: Scope) -> [Date] { 69 | let timestamps = self.timestamps 70 | return timestamps.filter { date in 71 | switch scope { 72 | case .install: return true 73 | case .version: 74 | guard let versionUpdateDate = PersistentToken.versionUpdateDate else { return true } 75 | return date > versionUpdateDate 76 | case .session: return date > PersistentToken.sessionStartDate 77 | case .since(let since): return date > since 78 | case .until(let until): return date < until 79 | } 80 | } 81 | } 82 | 83 | public func hasBeenDone(in scope: Scope, _ timesPredicate: TimesPredicate) -> Bool { 84 | return timesPredicate.evaluate(filteredTimestamps(in: scope).count) 85 | } 86 | } 87 | 88 | extension PersistentToken { 89 | 90 | public func `do`(in scope: Scope, if timesPredicate: TimesPredicate, _ task: (PersistentToken) -> Void) { 91 | PersistentToken.ensureInitialized() 92 | lock.withLock { 93 | if hasBeenDone(in: scope, timesPredicate) { 94 | task(self) 95 | } 96 | } 97 | } 98 | 99 | public func `do`(in scope: Scope, if timesPredicate: TimesPredicate, _ task: () -> Void) { 100 | PersistentToken.ensureInitialized() 101 | lock.withLock { 102 | if hasBeenDone(in: scope, timesPredicate) { 103 | task() 104 | timestamps.append(Date()) 105 | } 106 | } 107 | flushContext() 108 | } 109 | 110 | public func done() { 111 | lock.withLock { 112 | timestamps.append(Date()) 113 | } 114 | flushContext() 115 | } 116 | 117 | public var lastDone: Date? { 118 | return lock.withLock { 119 | timestamps.last 120 | } 121 | } 122 | 123 | public func reset() { 124 | lock.withLock { 125 | self.context = [:] 126 | } 127 | UserDefaults.standard.set(nil, forKey: contextKey) 128 | } 129 | 130 | public static func resetAll() { 131 | for (_, token) in self.registry.get() { 132 | token.reset() 133 | } 134 | } 135 | } 136 | 137 | extension PersistentToken { 138 | 139 | private static func appVersion() -> String { 140 | guard 141 | let version = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String, 142 | let build = Bundle.main.infoDictionary?["CFBundleVersion"] as? String 143 | else { 144 | return "0.0.0" 145 | } 146 | return "\(version) (\(build))" 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /Tests/OnceTests/PersistentTokenTests.swift: -------------------------------------------------------------------------------- 1 | import XCTest 2 | @testable import Once 3 | 4 | class PersistentTokenTests: XCTestCase { 5 | 6 | let count = 100 7 | 8 | func testMake() { 9 | let tokens = Atom<[PersistentToken]>(value: []) 10 | let name = UUID().uuidString 11 | 12 | asyncAndWait(concurrent: count) { 13 | tokens.append(PersistentToken.make(name)) 14 | } 15 | 16 | let ts = tokens.get().reduce(into: [PersistentToken]()) { (r, t) in 17 | if !r.contains(where: { $0 === t }) { r.append(t) } 18 | } 19 | XCTAssertEqual(ts.count, 1) 20 | } 21 | 22 | func testIfEqualTo_Install() { 23 | let token = PersistentToken.make(UUID().uuidString) 24 | var i = 0 25 | asyncAndWait(concurrent: count) { 26 | token.do(in: .install, if: .equalTo(0)) { 27 | i += 1 28 | } 29 | } 30 | XCTAssertEqual(i, 1) 31 | } 32 | 33 | func testIfLessThan_Install() { 34 | let token = PersistentToken.make(UUID().uuidString) 35 | var i = 0 36 | asyncAndWait(concurrent: count) { 37 | token.do(in: .install, if: .lessThan(3)) { 38 | i += 1 39 | } 40 | } 41 | XCTAssertEqual(i, 3) 42 | } 43 | 44 | func testVersion() { 45 | func resetVersion() { 46 | UserDefaults.standard.set(nil, forKey: "com.v2ambition.once.version") 47 | } 48 | 49 | let token = PersistentToken.make(UUID().uuidString) 50 | var i = 0 51 | 52 | asyncAndWait(concurrent: count) { 53 | token.do(in: .version, if: .equalTo(0)) { 54 | i += 1 55 | } 56 | } 57 | XCTAssertEqual(i, 1) 58 | 59 | resetVersion() 60 | PersistentToken.initialize() 61 | 62 | asyncAndWait(concurrent: count) { 63 | token.do(in: .version, if: .equalTo(0)) { 64 | i += 1 65 | } 66 | } 67 | XCTAssertEqual(i, 2) 68 | } 69 | 70 | func testSession() { 71 | let token = PersistentToken.make(UUID().uuidString) 72 | var i = 0 73 | asyncAndWait(concurrent: count) { 74 | token.do(in: .session, if: .lessThan(3)) { 75 | i += 1 76 | } 77 | } 78 | XCTAssertEqual(i, 3) 79 | } 80 | 81 | func testReset() { 82 | let token = PersistentToken.make(UUID().uuidString) 83 | var i = 0 84 | asyncAndWait(concurrent: count) { 85 | token.do(in: .session, if: .equalTo(0)) { 86 | i += 1 87 | } 88 | } 89 | XCTAssertEqual(i, 1) 90 | 91 | token.reset() 92 | 93 | asyncAndWait(concurrent: count) { 94 | token.do(in: .session, if: .equalTo(0)) { 95 | i += 1 96 | } 97 | } 98 | XCTAssertEqual(i, 2) 99 | } 100 | 101 | func testResetAll() { 102 | let tokens = Atom<[PersistentToken]>(value: []) 103 | let num = Atom(value: 0) 104 | asyncAndWait(concurrent: count) { 105 | let token = PersistentToken.make(UUID().uuidString) 106 | tokens.append(token) 107 | token.do(in: .session, if: .equalTo(0)) { 108 | num.add(1) 109 | } 110 | } 111 | XCTAssertEqual(num.get(), count) 112 | 113 | PersistentToken.resetAll() 114 | 115 | tokens.get().forEach { 116 | $0.do(in: .session, if: .equalTo(0)) { 117 | num.add(1) 118 | } 119 | } 120 | XCTAssertEqual(num.get(), count + count) 121 | } 122 | 123 | func testSince() { 124 | let token = PersistentToken.make(UUID().uuidString) 125 | var i = 0 126 | asyncAndWait(concurrent: count) { 127 | token.do(in: .since(Date() - 0.5), if: .lessThan(3)) { 128 | i += 1 129 | } 130 | } 131 | XCTAssertEqual(i, 3) 132 | 133 | Thread.sleep(forTimeInterval: 0.5) 134 | asyncAndWait(concurrent: count) { 135 | token.do(in: .since(Date() - 0.5), if: .lessThan(3)) { 136 | i += 1 137 | } 138 | } 139 | XCTAssertEqual(i, 6) 140 | } 141 | 142 | func testUntil() { 143 | let token = PersistentToken.make(UUID().uuidString) 144 | var i = 0 145 | asyncAndWait(concurrent: count) { 146 | token.do(in: .until(Date() + 0.5), if: .lessThan(3)) { 147 | i += 1 148 | } 149 | } 150 | XCTAssertEqual(i, 3) 151 | 152 | token.reset() 153 | 154 | asyncAndWait(concurrent: count) { 155 | token.do(in: .until(Date() + 0.5), if: .lessThan(3)) { 156 | i += 1 157 | } 158 | } 159 | XCTAssertEqual(i, 6) 160 | } 161 | 162 | func testHasBeenDone() { 163 | let token = PersistentToken.make(UUID().uuidString) 164 | var i = 0 165 | asyncAndWait(concurrent: 10) { 166 | token.do(in: .session, if: .lessThan(3)) { 167 | i += 1 168 | } 169 | } 170 | XCTAssertEqual(i, 3) 171 | XCTAssertTrue(token.hasBeenDone(in: .session, .equalTo(3))) 172 | } 173 | 174 | static var allTests = [ 175 | "testMake": testMake, 176 | "testIfEqualTo_Install": testIfEqualTo_Install, 177 | "testIfLessThan_Install": testIfLessThan_Install, 178 | "testVersion": testVersion, 179 | "testSession": testSession, 180 | "testReset": testReset, 181 | "testResetAll": testResetAll, 182 | "testSince": testSince, 183 | "testUntil": testUntil, 184 | "testHasBeenDone": testHasBeenDone 185 | ] 186 | } 187 | -------------------------------------------------------------------------------- /Once.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 47; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 52D6D9871BEFF229002C0205 /* Once.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D97C1BEFF229002C0205 /* Once.framework */; }; 11 | 6211B25D2160BC76004358F2 /* PersistentToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6211B25C2160BC76004358F2 /* PersistentToken.swift */; }; 12 | 6211B25E2160BC76004358F2 /* PersistentToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6211B25C2160BC76004358F2 /* PersistentToken.swift */; }; 13 | 6211B25F2160BC76004358F2 /* PersistentToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6211B25C2160BC76004358F2 /* PersistentToken.swift */; }; 14 | 6211B2602160BC76004358F2 /* PersistentToken.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6211B25C2160BC76004358F2 /* PersistentToken.swift */; }; 15 | 66145EA7215E6A8300A8E10E /* Scope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66145EA6215E6A8300A8E10E /* Scope.swift */; }; 16 | 66145EA8215E6A8300A8E10E /* Scope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66145EA6215E6A8300A8E10E /* Scope.swift */; }; 17 | 66145EA9215E6A8300A8E10E /* Scope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66145EA6215E6A8300A8E10E /* Scope.swift */; }; 18 | 66145EAA215E6A8300A8E10E /* Scope.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66145EA6215E6A8300A8E10E /* Scope.swift */; }; 19 | 6625AA3C2317F5EE00423CE9 /* Atom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6625AA3B2317F5EE00423CE9 /* Atom.swift */; }; 20 | 6625AA3D2317F5EE00423CE9 /* Atom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6625AA3B2317F5EE00423CE9 /* Atom.swift */; }; 21 | 6625AA3E2317F5EE00423CE9 /* Atom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6625AA3B2317F5EE00423CE9 /* Atom.swift */; }; 22 | 6625AA3F2317F5EE00423CE9 /* Atom.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6625AA3B2317F5EE00423CE9 /* Atom.swift */; }; 23 | 6625AA412317F6E300423CE9 /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6625AA402317F6E300423CE9 /* Lock.swift */; }; 24 | 6625AA422317F6E300423CE9 /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6625AA402317F6E300423CE9 /* Lock.swift */; }; 25 | 6625AA432317F6E300423CE9 /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6625AA402317F6E300423CE9 /* Lock.swift */; }; 26 | 6625AA442317F6E300423CE9 /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 6625AA402317F6E300423CE9 /* Lock.swift */; }; 27 | 66D8B43521678CD10059A3EF /* TimesPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B43421678CD10059A3EF /* TimesPredicate.swift */; }; 28 | 66D8B43621678CD10059A3EF /* TimesPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B43421678CD10059A3EF /* TimesPredicate.swift */; }; 29 | 66D8B43721678CD10059A3EF /* TimesPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B43421678CD10059A3EF /* TimesPredicate.swift */; }; 30 | 66D8B43821678CD10059A3EF /* TimesPredicate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B43421678CD10059A3EF /* TimesPredicate.swift */; }; 31 | 66D8B4402167B1C90059A3EF /* Token.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B43F2167B1C90059A3EF /* Token.swift */; }; 32 | 66D8B4412167B1C90059A3EF /* Token.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B43F2167B1C90059A3EF /* Token.swift */; }; 33 | 66D8B4422167B1C90059A3EF /* Token.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B43F2167B1C90059A3EF /* Token.swift */; }; 34 | 66D8B4432167B1C90059A3EF /* Token.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B43F2167B1C90059A3EF /* Token.swift */; }; 35 | 66D8B44C2167B8360059A3EF /* TokenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B4472167B82C0059A3EF /* TokenTests.swift */; }; 36 | 66D8B44D2167B8370059A3EF /* TokenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B4472167B82C0059A3EF /* TokenTests.swift */; }; 37 | 66D8B44E2167B8370059A3EF /* TokenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B4472167B82C0059A3EF /* TokenTests.swift */; }; 38 | 66D8B4502167BAB30059A3EF /* XCTestManifests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B44F2167BAB30059A3EF /* XCTestManifests.swift */; }; 39 | 66D8B4512167BAB30059A3EF /* XCTestManifests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B44F2167BAB30059A3EF /* XCTestManifests.swift */; }; 40 | 66D8B4522167BAB30059A3EF /* XCTestManifests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B44F2167BAB30059A3EF /* XCTestManifests.swift */; }; 41 | 66D8B4542167BB390059A3EF /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B4532167BB390059A3EF /* Utils.swift */; }; 42 | 66D8B4552167BB390059A3EF /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B4532167BB390059A3EF /* Utils.swift */; }; 43 | 66D8B4562167BB390059A3EF /* Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B4532167BB390059A3EF /* Utils.swift */; }; 44 | 66D8B45B2167BCA00059A3EF /* TimesPredicateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B45A2167BCA00059A3EF /* TimesPredicateTests.swift */; }; 45 | 66D8B45C2167BCA00059A3EF /* TimesPredicateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B45A2167BCA00059A3EF /* TimesPredicateTests.swift */; }; 46 | 66D8B45D2167BCA00059A3EF /* TimesPredicateTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66D8B45A2167BCA00059A3EF /* TimesPredicateTests.swift */; }; 47 | 66EC2C1E2168A50500DCAE9F /* PersistentTokenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66EC2C192168A4FF00DCAE9F /* PersistentTokenTests.swift */; }; 48 | 66EC2C1F2168A50600DCAE9F /* PersistentTokenTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 66EC2C192168A4FF00DCAE9F /* PersistentTokenTests.swift */; }; 49 | DD7502881C68FEDE006590AF /* Once.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6DA0F1BF000BD002C0205 /* Once.framework */; }; 50 | DD7502921C690C7A006590AF /* Once.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52D6D9F01BEFFFBE002C0205 /* Once.framework */; }; 51 | /* End PBXBuildFile section */ 52 | 53 | /* Begin PBXContainerItemProxy section */ 54 | 52D6D9881BEFF229002C0205 /* PBXContainerItemProxy */ = { 55 | isa = PBXContainerItemProxy; 56 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */; 57 | proxyType = 1; 58 | remoteGlobalIDString = 52D6D97B1BEFF229002C0205; 59 | remoteInfo = Once; 60 | }; 61 | DD7502801C68FCFC006590AF /* PBXContainerItemProxy */ = { 62 | isa = PBXContainerItemProxy; 63 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */; 64 | proxyType = 1; 65 | remoteGlobalIDString = 52D6DA0E1BF000BD002C0205; 66 | remoteInfo = "Once-macOS"; 67 | }; 68 | DD7502931C690C7A006590AF /* PBXContainerItemProxy */ = { 69 | isa = PBXContainerItemProxy; 70 | containerPortal = 52D6D9731BEFF229002C0205 /* Project object */; 71 | proxyType = 1; 72 | remoteGlobalIDString = 52D6D9EF1BEFFFBE002C0205; 73 | remoteInfo = "Once-tvOS"; 74 | }; 75 | /* End PBXContainerItemProxy section */ 76 | 77 | /* Begin PBXFileReference section */ 78 | 52D6D97C1BEFF229002C0205 /* Once.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Once.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 79 | 52D6D9861BEFF229002C0205 /* Once-iOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Once-iOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 80 | 52D6D9E21BEFFF6E002C0205 /* Once.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Once.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 81 | 52D6D9F01BEFFFBE002C0205 /* Once.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Once.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 82 | 52D6DA0F1BF000BD002C0205 /* Once.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Once.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 83 | 6211B25C2160BC76004358F2 /* PersistentToken.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentToken.swift; sourceTree = ""; }; 84 | 66145EA6215E6A8300A8E10E /* Scope.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Scope.swift; sourceTree = ""; }; 85 | 6625AA3B2317F5EE00423CE9 /* Atom.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Atom.swift; sourceTree = ""; }; 86 | 6625AA402317F6E300423CE9 /* Lock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lock.swift; sourceTree = ""; }; 87 | 66D8B43421678CD10059A3EF /* TimesPredicate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimesPredicate.swift; sourceTree = ""; }; 88 | 66D8B43F2167B1C90059A3EF /* Token.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Token.swift; sourceTree = ""; }; 89 | 66D8B4472167B82C0059A3EF /* TokenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TokenTests.swift; sourceTree = ""; }; 90 | 66D8B44F2167BAB30059A3EF /* XCTestManifests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = XCTestManifests.swift; sourceTree = ""; }; 91 | 66D8B4532167BB390059A3EF /* Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Utils.swift; sourceTree = ""; }; 92 | 66D8B45A2167BCA00059A3EF /* TimesPredicateTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TimesPredicateTests.swift; sourceTree = ""; }; 93 | 66EC2C192168A4FF00DCAE9F /* PersistentTokenTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PersistentTokenTests.swift; sourceTree = ""; }; 94 | AD2FAA261CD0B6D800659CF4 /* Once.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Once.plist; sourceTree = ""; }; 95 | AD2FAA281CD0B6E100659CF4 /* OnceTests.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = OnceTests.plist; sourceTree = ""; }; 96 | DD75027A1C68FCFC006590AF /* Once-macOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Once-macOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 97 | DD75028D1C690C7A006590AF /* Once-tvOS Tests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "Once-tvOS Tests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; }; 98 | /* End PBXFileReference section */ 99 | 100 | /* Begin PBXFrameworksBuildPhase section */ 101 | 52D6D9781BEFF229002C0205 /* Frameworks */ = { 102 | isa = PBXFrameworksBuildPhase; 103 | buildActionMask = 2147483647; 104 | files = ( 105 | ); 106 | runOnlyForDeploymentPostprocessing = 0; 107 | }; 108 | 52D6D9831BEFF229002C0205 /* Frameworks */ = { 109 | isa = PBXFrameworksBuildPhase; 110 | buildActionMask = 2147483647; 111 | files = ( 112 | 52D6D9871BEFF229002C0205 /* Once.framework in Frameworks */, 113 | ); 114 | runOnlyForDeploymentPostprocessing = 0; 115 | }; 116 | 52D6D9DE1BEFFF6E002C0205 /* Frameworks */ = { 117 | isa = PBXFrameworksBuildPhase; 118 | buildActionMask = 2147483647; 119 | files = ( 120 | ); 121 | runOnlyForDeploymentPostprocessing = 0; 122 | }; 123 | 52D6D9EC1BEFFFBE002C0205 /* Frameworks */ = { 124 | isa = PBXFrameworksBuildPhase; 125 | buildActionMask = 2147483647; 126 | files = ( 127 | ); 128 | runOnlyForDeploymentPostprocessing = 0; 129 | }; 130 | 52D6DA0B1BF000BD002C0205 /* Frameworks */ = { 131 | isa = PBXFrameworksBuildPhase; 132 | buildActionMask = 2147483647; 133 | files = ( 134 | ); 135 | runOnlyForDeploymentPostprocessing = 0; 136 | }; 137 | DD7502771C68FCFC006590AF /* Frameworks */ = { 138 | isa = PBXFrameworksBuildPhase; 139 | buildActionMask = 2147483647; 140 | files = ( 141 | DD7502881C68FEDE006590AF /* Once.framework in Frameworks */, 142 | ); 143 | runOnlyForDeploymentPostprocessing = 0; 144 | }; 145 | DD75028A1C690C7A006590AF /* Frameworks */ = { 146 | isa = PBXFrameworksBuildPhase; 147 | buildActionMask = 2147483647; 148 | files = ( 149 | DD7502921C690C7A006590AF /* Once.framework in Frameworks */, 150 | ); 151 | runOnlyForDeploymentPostprocessing = 0; 152 | }; 153 | /* End PBXFrameworksBuildPhase section */ 154 | 155 | /* Begin PBXGroup section */ 156 | 52D6D9721BEFF229002C0205 = { 157 | isa = PBXGroup; 158 | children = ( 159 | 8933C7811EB5B7E0000D00A4 /* Sources */, 160 | 8933C7831EB5B7EB000D00A4 /* Tests */, 161 | 52D6D99C1BEFF38C002C0205 /* Configs */, 162 | 52D6D97D1BEFF229002C0205 /* Products */, 163 | ); 164 | sourceTree = ""; 165 | }; 166 | 52D6D97D1BEFF229002C0205 /* Products */ = { 167 | isa = PBXGroup; 168 | children = ( 169 | 52D6D97C1BEFF229002C0205 /* Once.framework */, 170 | 52D6D9861BEFF229002C0205 /* Once-iOS Tests.xctest */, 171 | 52D6D9E21BEFFF6E002C0205 /* Once.framework */, 172 | 52D6D9F01BEFFFBE002C0205 /* Once.framework */, 173 | 52D6DA0F1BF000BD002C0205 /* Once.framework */, 174 | DD75027A1C68FCFC006590AF /* Once-macOS Tests.xctest */, 175 | DD75028D1C690C7A006590AF /* Once-tvOS Tests.xctest */, 176 | ); 177 | name = Products; 178 | sourceTree = ""; 179 | }; 180 | 52D6D99C1BEFF38C002C0205 /* Configs */ = { 181 | isa = PBXGroup; 182 | children = ( 183 | DD7502721C68FC1B006590AF /* Frameworks */, 184 | DD7502731C68FC20006590AF /* Tests */, 185 | ); 186 | path = Configs; 187 | sourceTree = ""; 188 | }; 189 | 6625AA2B2317F07000423CE9 /* utils */ = { 190 | isa = PBXGroup; 191 | children = ( 192 | 6625AA3B2317F5EE00423CE9 /* Atom.swift */, 193 | 6625AA402317F6E300423CE9 /* Lock.swift */, 194 | ); 195 | name = utils; 196 | sourceTree = ""; 197 | }; 198 | 6685EDC5215D13A800E6CBE2 /* Once */ = { 199 | isa = PBXGroup; 200 | children = ( 201 | 6211B25C2160BC76004358F2 /* PersistentToken.swift */, 202 | 66145EA6215E6A8300A8E10E /* Scope.swift */, 203 | 66D8B43421678CD10059A3EF /* TimesPredicate.swift */, 204 | 66D8B43F2167B1C90059A3EF /* Token.swift */, 205 | 6625AA2B2317F07000423CE9 /* utils */, 206 | ); 207 | path = Once; 208 | sourceTree = ""; 209 | }; 210 | 8933C7811EB5B7E0000D00A4 /* Sources */ = { 211 | isa = PBXGroup; 212 | children = ( 213 | 6685EDC5215D13A800E6CBE2 /* Once */, 214 | ); 215 | path = Sources; 216 | sourceTree = ""; 217 | }; 218 | 8933C7831EB5B7EB000D00A4 /* Tests */ = { 219 | isa = PBXGroup; 220 | children = ( 221 | 66D8B4472167B82C0059A3EF /* TokenTests.swift */, 222 | 66D8B45A2167BCA00059A3EF /* TimesPredicateTests.swift */, 223 | 66EC2C192168A4FF00DCAE9F /* PersistentTokenTests.swift */, 224 | 66D8B44F2167BAB30059A3EF /* XCTestManifests.swift */, 225 | 66D8B4532167BB390059A3EF /* Utils.swift */, 226 | ); 227 | name = Tests; 228 | path = Tests/OnceTests; 229 | sourceTree = ""; 230 | }; 231 | DD7502721C68FC1B006590AF /* Frameworks */ = { 232 | isa = PBXGroup; 233 | children = ( 234 | AD2FAA261CD0B6D800659CF4 /* Once.plist */, 235 | ); 236 | name = Frameworks; 237 | sourceTree = ""; 238 | }; 239 | DD7502731C68FC20006590AF /* Tests */ = { 240 | isa = PBXGroup; 241 | children = ( 242 | AD2FAA281CD0B6E100659CF4 /* OnceTests.plist */, 243 | ); 244 | name = Tests; 245 | sourceTree = ""; 246 | }; 247 | /* End PBXGroup section */ 248 | 249 | /* Begin PBXHeadersBuildPhase section */ 250 | 52D6D9791BEFF229002C0205 /* Headers */ = { 251 | isa = PBXHeadersBuildPhase; 252 | buildActionMask = 2147483647; 253 | files = ( 254 | ); 255 | runOnlyForDeploymentPostprocessing = 0; 256 | }; 257 | 52D6D9DF1BEFFF6E002C0205 /* Headers */ = { 258 | isa = PBXHeadersBuildPhase; 259 | buildActionMask = 2147483647; 260 | files = ( 261 | ); 262 | runOnlyForDeploymentPostprocessing = 0; 263 | }; 264 | 52D6D9ED1BEFFFBE002C0205 /* Headers */ = { 265 | isa = PBXHeadersBuildPhase; 266 | buildActionMask = 2147483647; 267 | files = ( 268 | ); 269 | runOnlyForDeploymentPostprocessing = 0; 270 | }; 271 | 52D6DA0C1BF000BD002C0205 /* Headers */ = { 272 | isa = PBXHeadersBuildPhase; 273 | buildActionMask = 2147483647; 274 | files = ( 275 | ); 276 | runOnlyForDeploymentPostprocessing = 0; 277 | }; 278 | /* End PBXHeadersBuildPhase section */ 279 | 280 | /* Begin PBXNativeTarget section */ 281 | 52D6D97B1BEFF229002C0205 /* Once-iOS */ = { 282 | isa = PBXNativeTarget; 283 | buildConfigurationList = 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "Once-iOS" */; 284 | buildPhases = ( 285 | 52D6D9771BEFF229002C0205 /* Sources */, 286 | 52D6D9781BEFF229002C0205 /* Frameworks */, 287 | 52D6D9791BEFF229002C0205 /* Headers */, 288 | 52D6D97A1BEFF229002C0205 /* Resources */, 289 | ); 290 | buildRules = ( 291 | ); 292 | dependencies = ( 293 | ); 294 | name = "Once-iOS"; 295 | productName = Once; 296 | productReference = 52D6D97C1BEFF229002C0205 /* Once.framework */; 297 | productType = "com.apple.product-type.framework"; 298 | }; 299 | 52D6D9851BEFF229002C0205 /* Once-iOS Tests */ = { 300 | isa = PBXNativeTarget; 301 | buildConfigurationList = 52D6D9931BEFF229002C0205 /* Build configuration list for PBXNativeTarget "Once-iOS Tests" */; 302 | buildPhases = ( 303 | 52D6D9821BEFF229002C0205 /* Sources */, 304 | 52D6D9831BEFF229002C0205 /* Frameworks */, 305 | 52D6D9841BEFF229002C0205 /* Resources */, 306 | ); 307 | buildRules = ( 308 | ); 309 | dependencies = ( 310 | 52D6D9891BEFF229002C0205 /* PBXTargetDependency */, 311 | ); 312 | name = "Once-iOS Tests"; 313 | productName = OnceTests; 314 | productReference = 52D6D9861BEFF229002C0205 /* Once-iOS Tests.xctest */; 315 | productType = "com.apple.product-type.bundle.unit-test"; 316 | }; 317 | 52D6D9E11BEFFF6E002C0205 /* Once-watchOS */ = { 318 | isa = PBXNativeTarget; 319 | buildConfigurationList = 52D6D9E71BEFFF6E002C0205 /* Build configuration list for PBXNativeTarget "Once-watchOS" */; 320 | buildPhases = ( 321 | 52D6D9DD1BEFFF6E002C0205 /* Sources */, 322 | 52D6D9DE1BEFFF6E002C0205 /* Frameworks */, 323 | 52D6D9DF1BEFFF6E002C0205 /* Headers */, 324 | 52D6D9E01BEFFF6E002C0205 /* Resources */, 325 | ); 326 | buildRules = ( 327 | ); 328 | dependencies = ( 329 | ); 330 | name = "Once-watchOS"; 331 | productName = "Once-watchOS"; 332 | productReference = 52D6D9E21BEFFF6E002C0205 /* Once.framework */; 333 | productType = "com.apple.product-type.framework"; 334 | }; 335 | 52D6D9EF1BEFFFBE002C0205 /* Once-tvOS */ = { 336 | isa = PBXNativeTarget; 337 | buildConfigurationList = 52D6DA011BEFFFBE002C0205 /* Build configuration list for PBXNativeTarget "Once-tvOS" */; 338 | buildPhases = ( 339 | 52D6D9EB1BEFFFBE002C0205 /* Sources */, 340 | 52D6D9EC1BEFFFBE002C0205 /* Frameworks */, 341 | 52D6D9ED1BEFFFBE002C0205 /* Headers */, 342 | 52D6D9EE1BEFFFBE002C0205 /* Resources */, 343 | ); 344 | buildRules = ( 345 | ); 346 | dependencies = ( 347 | ); 348 | name = "Once-tvOS"; 349 | productName = "Once-tvOS"; 350 | productReference = 52D6D9F01BEFFFBE002C0205 /* Once.framework */; 351 | productType = "com.apple.product-type.framework"; 352 | }; 353 | 52D6DA0E1BF000BD002C0205 /* Once-macOS */ = { 354 | isa = PBXNativeTarget; 355 | buildConfigurationList = 52D6DA201BF000BD002C0205 /* Build configuration list for PBXNativeTarget "Once-macOS" */; 356 | buildPhases = ( 357 | 52D6DA0A1BF000BD002C0205 /* Sources */, 358 | 52D6DA0B1BF000BD002C0205 /* Frameworks */, 359 | 52D6DA0C1BF000BD002C0205 /* Headers */, 360 | 52D6DA0D1BF000BD002C0205 /* Resources */, 361 | ); 362 | buildRules = ( 363 | ); 364 | dependencies = ( 365 | ); 366 | name = "Once-macOS"; 367 | productName = "Once-macOS"; 368 | productReference = 52D6DA0F1BF000BD002C0205 /* Once.framework */; 369 | productType = "com.apple.product-type.framework"; 370 | }; 371 | DD7502791C68FCFC006590AF /* Once-macOS Tests */ = { 372 | isa = PBXNativeTarget; 373 | buildConfigurationList = DD7502821C68FCFC006590AF /* Build configuration list for PBXNativeTarget "Once-macOS Tests" */; 374 | buildPhases = ( 375 | DD7502761C68FCFC006590AF /* Sources */, 376 | DD7502771C68FCFC006590AF /* Frameworks */, 377 | DD7502781C68FCFC006590AF /* Resources */, 378 | ); 379 | buildRules = ( 380 | ); 381 | dependencies = ( 382 | DD7502811C68FCFC006590AF /* PBXTargetDependency */, 383 | ); 384 | name = "Once-macOS Tests"; 385 | productName = "Once-OS Tests"; 386 | productReference = DD75027A1C68FCFC006590AF /* Once-macOS Tests.xctest */; 387 | productType = "com.apple.product-type.bundle.unit-test"; 388 | }; 389 | DD75028C1C690C7A006590AF /* Once-tvOS Tests */ = { 390 | isa = PBXNativeTarget; 391 | buildConfigurationList = DD7502951C690C7A006590AF /* Build configuration list for PBXNativeTarget "Once-tvOS Tests" */; 392 | buildPhases = ( 393 | DD7502891C690C7A006590AF /* Sources */, 394 | DD75028A1C690C7A006590AF /* Frameworks */, 395 | DD75028B1C690C7A006590AF /* Resources */, 396 | ); 397 | buildRules = ( 398 | ); 399 | dependencies = ( 400 | DD7502941C690C7A006590AF /* PBXTargetDependency */, 401 | ); 402 | name = "Once-tvOS Tests"; 403 | productName = "Once-tvOS Tests"; 404 | productReference = DD75028D1C690C7A006590AF /* Once-tvOS Tests.xctest */; 405 | productType = "com.apple.product-type.bundle.unit-test"; 406 | }; 407 | /* End PBXNativeTarget section */ 408 | 409 | /* Begin PBXProject section */ 410 | 52D6D9731BEFF229002C0205 /* Project object */ = { 411 | isa = PBXProject; 412 | attributes = { 413 | LastSwiftUpdateCheck = 0720; 414 | LastUpgradeCheck = 1030; 415 | ORGANIZATIONNAME = v2ambition; 416 | TargetAttributes = { 417 | 52D6D97B1BEFF229002C0205 = { 418 | CreatedOnToolsVersion = 7.1; 419 | LastSwiftMigration = 1000; 420 | }; 421 | 52D6D9851BEFF229002C0205 = { 422 | CreatedOnToolsVersion = 7.1; 423 | LastSwiftMigration = 1000; 424 | }; 425 | 52D6D9E11BEFFF6E002C0205 = { 426 | CreatedOnToolsVersion = 7.1; 427 | LastSwiftMigration = 1000; 428 | }; 429 | 52D6D9EF1BEFFFBE002C0205 = { 430 | CreatedOnToolsVersion = 7.1; 431 | LastSwiftMigration = 1000; 432 | }; 433 | 52D6DA0E1BF000BD002C0205 = { 434 | CreatedOnToolsVersion = 7.1; 435 | LastSwiftMigration = 1000; 436 | }; 437 | DD7502791C68FCFC006590AF = { 438 | CreatedOnToolsVersion = 7.2.1; 439 | LastSwiftMigration = 0800; 440 | }; 441 | DD75028C1C690C7A006590AF = { 442 | CreatedOnToolsVersion = 7.2.1; 443 | LastSwiftMigration = 0800; 444 | }; 445 | }; 446 | }; 447 | buildConfigurationList = 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "Once" */; 448 | compatibilityVersion = "Xcode 6.3"; 449 | developmentRegion = en; 450 | hasScannedForEncodings = 0; 451 | knownRegions = ( 452 | en, 453 | Base, 454 | ); 455 | mainGroup = 52D6D9721BEFF229002C0205; 456 | productRefGroup = 52D6D97D1BEFF229002C0205 /* Products */; 457 | projectDirPath = ""; 458 | projectRoot = ""; 459 | targets = ( 460 | 52D6D97B1BEFF229002C0205 /* Once-iOS */, 461 | 52D6DA0E1BF000BD002C0205 /* Once-macOS */, 462 | 52D6D9E11BEFFF6E002C0205 /* Once-watchOS */, 463 | 52D6D9EF1BEFFFBE002C0205 /* Once-tvOS */, 464 | 52D6D9851BEFF229002C0205 /* Once-iOS Tests */, 465 | DD7502791C68FCFC006590AF /* Once-macOS Tests */, 466 | DD75028C1C690C7A006590AF /* Once-tvOS Tests */, 467 | ); 468 | }; 469 | /* End PBXProject section */ 470 | 471 | /* Begin PBXResourcesBuildPhase section */ 472 | 52D6D97A1BEFF229002C0205 /* Resources */ = { 473 | isa = PBXResourcesBuildPhase; 474 | buildActionMask = 2147483647; 475 | files = ( 476 | ); 477 | runOnlyForDeploymentPostprocessing = 0; 478 | }; 479 | 52D6D9841BEFF229002C0205 /* Resources */ = { 480 | isa = PBXResourcesBuildPhase; 481 | buildActionMask = 2147483647; 482 | files = ( 483 | ); 484 | runOnlyForDeploymentPostprocessing = 0; 485 | }; 486 | 52D6D9E01BEFFF6E002C0205 /* Resources */ = { 487 | isa = PBXResourcesBuildPhase; 488 | buildActionMask = 2147483647; 489 | files = ( 490 | ); 491 | runOnlyForDeploymentPostprocessing = 0; 492 | }; 493 | 52D6D9EE1BEFFFBE002C0205 /* Resources */ = { 494 | isa = PBXResourcesBuildPhase; 495 | buildActionMask = 2147483647; 496 | files = ( 497 | ); 498 | runOnlyForDeploymentPostprocessing = 0; 499 | }; 500 | 52D6DA0D1BF000BD002C0205 /* Resources */ = { 501 | isa = PBXResourcesBuildPhase; 502 | buildActionMask = 2147483647; 503 | files = ( 504 | ); 505 | runOnlyForDeploymentPostprocessing = 0; 506 | }; 507 | DD7502781C68FCFC006590AF /* Resources */ = { 508 | isa = PBXResourcesBuildPhase; 509 | buildActionMask = 2147483647; 510 | files = ( 511 | ); 512 | runOnlyForDeploymentPostprocessing = 0; 513 | }; 514 | DD75028B1C690C7A006590AF /* Resources */ = { 515 | isa = PBXResourcesBuildPhase; 516 | buildActionMask = 2147483647; 517 | files = ( 518 | ); 519 | runOnlyForDeploymentPostprocessing = 0; 520 | }; 521 | /* End PBXResourcesBuildPhase section */ 522 | 523 | /* Begin PBXSourcesBuildPhase section */ 524 | 52D6D9771BEFF229002C0205 /* Sources */ = { 525 | isa = PBXSourcesBuildPhase; 526 | buildActionMask = 2147483647; 527 | files = ( 528 | 66D8B4402167B1C90059A3EF /* Token.swift in Sources */, 529 | 66145EA7215E6A8300A8E10E /* Scope.swift in Sources */, 530 | 6625AA3C2317F5EE00423CE9 /* Atom.swift in Sources */, 531 | 66D8B43521678CD10059A3EF /* TimesPredicate.swift in Sources */, 532 | 6211B25D2160BC76004358F2 /* PersistentToken.swift in Sources */, 533 | 6625AA412317F6E300423CE9 /* Lock.swift in Sources */, 534 | ); 535 | runOnlyForDeploymentPostprocessing = 0; 536 | }; 537 | 52D6D9821BEFF229002C0205 /* Sources */ = { 538 | isa = PBXSourcesBuildPhase; 539 | buildActionMask = 2147483647; 540 | files = ( 541 | 66D8B4542167BB390059A3EF /* Utils.swift in Sources */, 542 | 66EC2C1E2168A50500DCAE9F /* PersistentTokenTests.swift in Sources */, 543 | 66D8B45B2167BCA00059A3EF /* TimesPredicateTests.swift in Sources */, 544 | 66D8B4502167BAB30059A3EF /* XCTestManifests.swift in Sources */, 545 | 66D8B44C2167B8360059A3EF /* TokenTests.swift in Sources */, 546 | ); 547 | runOnlyForDeploymentPostprocessing = 0; 548 | }; 549 | 52D6D9DD1BEFFF6E002C0205 /* Sources */ = { 550 | isa = PBXSourcesBuildPhase; 551 | buildActionMask = 2147483647; 552 | files = ( 553 | 66D8B4422167B1C90059A3EF /* Token.swift in Sources */, 554 | 66145EA9215E6A8300A8E10E /* Scope.swift in Sources */, 555 | 6625AA3E2317F5EE00423CE9 /* Atom.swift in Sources */, 556 | 66D8B43721678CD10059A3EF /* TimesPredicate.swift in Sources */, 557 | 6211B25F2160BC76004358F2 /* PersistentToken.swift in Sources */, 558 | 6625AA432317F6E300423CE9 /* Lock.swift in Sources */, 559 | ); 560 | runOnlyForDeploymentPostprocessing = 0; 561 | }; 562 | 52D6D9EB1BEFFFBE002C0205 /* Sources */ = { 563 | isa = PBXSourcesBuildPhase; 564 | buildActionMask = 2147483647; 565 | files = ( 566 | 66D8B4432167B1C90059A3EF /* Token.swift in Sources */, 567 | 66145EAA215E6A8300A8E10E /* Scope.swift in Sources */, 568 | 6625AA3F2317F5EE00423CE9 /* Atom.swift in Sources */, 569 | 66D8B43821678CD10059A3EF /* TimesPredicate.swift in Sources */, 570 | 6211B2602160BC76004358F2 /* PersistentToken.swift in Sources */, 571 | 6625AA442317F6E300423CE9 /* Lock.swift in Sources */, 572 | ); 573 | runOnlyForDeploymentPostprocessing = 0; 574 | }; 575 | 52D6DA0A1BF000BD002C0205 /* Sources */ = { 576 | isa = PBXSourcesBuildPhase; 577 | buildActionMask = 2147483647; 578 | files = ( 579 | 66D8B4412167B1C90059A3EF /* Token.swift in Sources */, 580 | 66145EA8215E6A8300A8E10E /* Scope.swift in Sources */, 581 | 6625AA3D2317F5EE00423CE9 /* Atom.swift in Sources */, 582 | 66D8B43621678CD10059A3EF /* TimesPredicate.swift in Sources */, 583 | 6211B25E2160BC76004358F2 /* PersistentToken.swift in Sources */, 584 | 6625AA422317F6E300423CE9 /* Lock.swift in Sources */, 585 | ); 586 | runOnlyForDeploymentPostprocessing = 0; 587 | }; 588 | DD7502761C68FCFC006590AF /* Sources */ = { 589 | isa = PBXSourcesBuildPhase; 590 | buildActionMask = 2147483647; 591 | files = ( 592 | 66D8B4552167BB390059A3EF /* Utils.swift in Sources */, 593 | 66EC2C1F2168A50600DCAE9F /* PersistentTokenTests.swift in Sources */, 594 | 66D8B45C2167BCA00059A3EF /* TimesPredicateTests.swift in Sources */, 595 | 66D8B4512167BAB30059A3EF /* XCTestManifests.swift in Sources */, 596 | 66D8B44D2167B8370059A3EF /* TokenTests.swift in Sources */, 597 | ); 598 | runOnlyForDeploymentPostprocessing = 0; 599 | }; 600 | DD7502891C690C7A006590AF /* Sources */ = { 601 | isa = PBXSourcesBuildPhase; 602 | buildActionMask = 2147483647; 603 | files = ( 604 | 66D8B4562167BB390059A3EF /* Utils.swift in Sources */, 605 | 66D8B45D2167BCA00059A3EF /* TimesPredicateTests.swift in Sources */, 606 | 66D8B4522167BAB30059A3EF /* XCTestManifests.swift in Sources */, 607 | 66D8B44E2167B8370059A3EF /* TokenTests.swift in Sources */, 608 | ); 609 | runOnlyForDeploymentPostprocessing = 0; 610 | }; 611 | /* End PBXSourcesBuildPhase section */ 612 | 613 | /* Begin PBXTargetDependency section */ 614 | 52D6D9891BEFF229002C0205 /* PBXTargetDependency */ = { 615 | isa = PBXTargetDependency; 616 | target = 52D6D97B1BEFF229002C0205 /* Once-iOS */; 617 | targetProxy = 52D6D9881BEFF229002C0205 /* PBXContainerItemProxy */; 618 | }; 619 | DD7502811C68FCFC006590AF /* PBXTargetDependency */ = { 620 | isa = PBXTargetDependency; 621 | target = 52D6DA0E1BF000BD002C0205 /* Once-macOS */; 622 | targetProxy = DD7502801C68FCFC006590AF /* PBXContainerItemProxy */; 623 | }; 624 | DD7502941C690C7A006590AF /* PBXTargetDependency */ = { 625 | isa = PBXTargetDependency; 626 | target = 52D6D9EF1BEFFFBE002C0205 /* Once-tvOS */; 627 | targetProxy = DD7502931C690C7A006590AF /* PBXContainerItemProxy */; 628 | }; 629 | /* End PBXTargetDependency section */ 630 | 631 | /* Begin XCBuildConfiguration section */ 632 | 52D6D98E1BEFF229002C0205 /* Debug */ = { 633 | isa = XCBuildConfiguration; 634 | buildSettings = { 635 | ALWAYS_SEARCH_USER_PATHS = NO; 636 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 637 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 638 | CLANG_CXX_LIBRARY = "libc++"; 639 | CLANG_ENABLE_MODULES = YES; 640 | CLANG_ENABLE_OBJC_ARC = YES; 641 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 642 | CLANG_WARN_BOOL_CONVERSION = YES; 643 | CLANG_WARN_COMMA = YES; 644 | CLANG_WARN_CONSTANT_CONVERSION = YES; 645 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 646 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 647 | CLANG_WARN_EMPTY_BODY = YES; 648 | CLANG_WARN_ENUM_CONVERSION = YES; 649 | CLANG_WARN_INFINITE_RECURSION = YES; 650 | CLANG_WARN_INT_CONVERSION = YES; 651 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 652 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 653 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 654 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 655 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 656 | CLANG_WARN_STRICT_PROTOTYPES = YES; 657 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 658 | CLANG_WARN_UNREACHABLE_CODE = YES; 659 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 660 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 661 | COPY_PHASE_STRIP = NO; 662 | CURRENT_PROJECT_VERSION = 1; 663 | DEBUG_INFORMATION_FORMAT = dwarf; 664 | ENABLE_STRICT_OBJC_MSGSEND = YES; 665 | ENABLE_TESTABILITY = YES; 666 | GCC_C_LANGUAGE_STANDARD = gnu99; 667 | GCC_DYNAMIC_NO_PIC = NO; 668 | GCC_NO_COMMON_BLOCKS = YES; 669 | GCC_OPTIMIZATION_LEVEL = 0; 670 | GCC_PREPROCESSOR_DEFINITIONS = ( 671 | "DEBUG=1", 672 | "$(inherited)", 673 | ); 674 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 675 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 676 | GCC_WARN_UNDECLARED_SELECTOR = YES; 677 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 678 | GCC_WARN_UNUSED_FUNCTION = YES; 679 | GCC_WARN_UNUSED_VARIABLE = YES; 680 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 681 | MACOSX_DEPLOYMENT_TARGET = 10.12; 682 | MTL_ENABLE_DEBUG_INFO = YES; 683 | ONLY_ACTIVE_ARCH = YES; 684 | SDKROOT = iphoneos; 685 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 686 | SWIFT_VERSION = 4.0; 687 | TARGETED_DEVICE_FAMILY = "1,2"; 688 | VERSIONING_SYSTEM = "apple-generic"; 689 | VERSION_INFO_PREFIX = ""; 690 | }; 691 | name = Debug; 692 | }; 693 | 52D6D98F1BEFF229002C0205 /* Release */ = { 694 | isa = XCBuildConfiguration; 695 | buildSettings = { 696 | ALWAYS_SEARCH_USER_PATHS = NO; 697 | CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; 698 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 699 | CLANG_CXX_LIBRARY = "libc++"; 700 | CLANG_ENABLE_MODULES = YES; 701 | CLANG_ENABLE_OBJC_ARC = YES; 702 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 703 | CLANG_WARN_BOOL_CONVERSION = YES; 704 | CLANG_WARN_COMMA = YES; 705 | CLANG_WARN_CONSTANT_CONVERSION = YES; 706 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 707 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 708 | CLANG_WARN_EMPTY_BODY = YES; 709 | CLANG_WARN_ENUM_CONVERSION = YES; 710 | CLANG_WARN_INFINITE_RECURSION = YES; 711 | CLANG_WARN_INT_CONVERSION = YES; 712 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 713 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 714 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 715 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 716 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 717 | CLANG_WARN_STRICT_PROTOTYPES = YES; 718 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 719 | CLANG_WARN_UNREACHABLE_CODE = YES; 720 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 721 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 722 | COPY_PHASE_STRIP = NO; 723 | CURRENT_PROJECT_VERSION = 1; 724 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 725 | ENABLE_NS_ASSERTIONS = NO; 726 | ENABLE_STRICT_OBJC_MSGSEND = YES; 727 | GCC_C_LANGUAGE_STANDARD = gnu99; 728 | GCC_NO_COMMON_BLOCKS = YES; 729 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 730 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 731 | GCC_WARN_UNDECLARED_SELECTOR = YES; 732 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 733 | GCC_WARN_UNUSED_FUNCTION = YES; 734 | GCC_WARN_UNUSED_VARIABLE = YES; 735 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 736 | MACOSX_DEPLOYMENT_TARGET = 10.12; 737 | MTL_ENABLE_DEBUG_INFO = NO; 738 | SDKROOT = iphoneos; 739 | SWIFT_VERSION = 4.0; 740 | TARGETED_DEVICE_FAMILY = "1,2"; 741 | VALIDATE_PRODUCT = YES; 742 | VERSIONING_SYSTEM = "apple-generic"; 743 | VERSION_INFO_PREFIX = ""; 744 | }; 745 | name = Release; 746 | }; 747 | 52D6D9911BEFF229002C0205 /* Debug */ = { 748 | isa = XCBuildConfiguration; 749 | buildSettings = { 750 | APPLICATION_EXTENSION_API_ONLY = YES; 751 | CLANG_ENABLE_MODULES = YES; 752 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 753 | DEFINES_MODULE = YES; 754 | DYLIB_COMPATIBILITY_VERSION = 1; 755 | DYLIB_CURRENT_VERSION = 1; 756 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 757 | INFOPLIST_FILE = Configs/Once.plist; 758 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 759 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 760 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 761 | ONLY_ACTIVE_ARCH = NO; 762 | PRODUCT_BUNDLE_IDENTIFIER = "com.Once.Once-iOS"; 763 | PRODUCT_NAME = Once; 764 | SKIP_INSTALL = YES; 765 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 766 | SWIFT_VERSION = 5.0; 767 | }; 768 | name = Debug; 769 | }; 770 | 52D6D9921BEFF229002C0205 /* Release */ = { 771 | isa = XCBuildConfiguration; 772 | buildSettings = { 773 | APPLICATION_EXTENSION_API_ONLY = YES; 774 | CLANG_ENABLE_MODULES = YES; 775 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; 776 | DEFINES_MODULE = YES; 777 | DYLIB_COMPATIBILITY_VERSION = 1; 778 | DYLIB_CURRENT_VERSION = 1; 779 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 780 | INFOPLIST_FILE = Configs/Once.plist; 781 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 782 | IPHONEOS_DEPLOYMENT_TARGET = 10.0; 783 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 784 | PRODUCT_BUNDLE_IDENTIFIER = "com.Once.Once-iOS"; 785 | PRODUCT_NAME = Once; 786 | SKIP_INSTALL = YES; 787 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 788 | SWIFT_VERSION = 5.0; 789 | }; 790 | name = Release; 791 | }; 792 | 52D6D9941BEFF229002C0205 /* Debug */ = { 793 | isa = XCBuildConfiguration; 794 | buildSettings = { 795 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 796 | CLANG_ENABLE_MODULES = YES; 797 | INFOPLIST_FILE = Configs/OnceTests.plist; 798 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 799 | PRODUCT_BUNDLE_IDENTIFIER = "com.Once.Once-iOS-Tests"; 800 | PRODUCT_NAME = "$(TARGET_NAME)"; 801 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 802 | SWIFT_VERSION = 5.0; 803 | TVOS_DEPLOYMENT_TARGET = 10.0; 804 | }; 805 | name = Debug; 806 | }; 807 | 52D6D9951BEFF229002C0205 /* Release */ = { 808 | isa = XCBuildConfiguration; 809 | buildSettings = { 810 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 811 | CLANG_ENABLE_MODULES = YES; 812 | INFOPLIST_FILE = Configs/OnceTests.plist; 813 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 814 | PRODUCT_BUNDLE_IDENTIFIER = "com.Once.Once-iOS-Tests"; 815 | PRODUCT_NAME = "$(TARGET_NAME)"; 816 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 817 | SWIFT_VERSION = 5.0; 818 | TVOS_DEPLOYMENT_TARGET = 10.0; 819 | }; 820 | name = Release; 821 | }; 822 | 52D6D9E81BEFFF6E002C0205 /* Debug */ = { 823 | isa = XCBuildConfiguration; 824 | buildSettings = { 825 | APPLICATION_EXTENSION_API_ONLY = YES; 826 | CLANG_ENABLE_MODULES = YES; 827 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 828 | DEFINES_MODULE = YES; 829 | DYLIB_COMPATIBILITY_VERSION = 1; 830 | DYLIB_CURRENT_VERSION = 1; 831 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 832 | INFOPLIST_FILE = Configs/Once.plist; 833 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 834 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 835 | PRODUCT_BUNDLE_IDENTIFIER = "com.Once.Once-watchOS"; 836 | PRODUCT_NAME = Once; 837 | SDKROOT = watchos; 838 | SKIP_INSTALL = YES; 839 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 840 | SWIFT_VERSION = 5.0; 841 | TARGETED_DEVICE_FAMILY = 4; 842 | TVOS_DEPLOYMENT_TARGET = 10.0; 843 | WATCHOS_DEPLOYMENT_TARGET = 3.0; 844 | }; 845 | name = Debug; 846 | }; 847 | 52D6D9E91BEFFF6E002C0205 /* Release */ = { 848 | isa = XCBuildConfiguration; 849 | buildSettings = { 850 | APPLICATION_EXTENSION_API_ONLY = YES; 851 | CLANG_ENABLE_MODULES = YES; 852 | "CODE_SIGN_IDENTITY[sdk=watchos*]" = ""; 853 | DEFINES_MODULE = YES; 854 | DYLIB_COMPATIBILITY_VERSION = 1; 855 | DYLIB_CURRENT_VERSION = 1; 856 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 857 | INFOPLIST_FILE = Configs/Once.plist; 858 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 859 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 860 | PRODUCT_BUNDLE_IDENTIFIER = "com.Once.Once-watchOS"; 861 | PRODUCT_NAME = Once; 862 | SDKROOT = watchos; 863 | SKIP_INSTALL = YES; 864 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 865 | SWIFT_VERSION = 5.0; 866 | TARGETED_DEVICE_FAMILY = 4; 867 | TVOS_DEPLOYMENT_TARGET = 10.0; 868 | WATCHOS_DEPLOYMENT_TARGET = 3.0; 869 | }; 870 | name = Release; 871 | }; 872 | 52D6DA021BEFFFBE002C0205 /* Debug */ = { 873 | isa = XCBuildConfiguration; 874 | buildSettings = { 875 | APPLICATION_EXTENSION_API_ONLY = YES; 876 | CLANG_ENABLE_MODULES = YES; 877 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 878 | DEFINES_MODULE = YES; 879 | DYLIB_COMPATIBILITY_VERSION = 1; 880 | DYLIB_CURRENT_VERSION = 1; 881 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 882 | INFOPLIST_FILE = Configs/Once.plist; 883 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 884 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 885 | PRODUCT_BUNDLE_IDENTIFIER = "com.Once.Once-tvOS"; 886 | PRODUCT_NAME = Once; 887 | SDKROOT = appletvos; 888 | SKIP_INSTALL = YES; 889 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 890 | SWIFT_VERSION = 5.0; 891 | TARGETED_DEVICE_FAMILY = 3; 892 | TVOS_DEPLOYMENT_TARGET = 10.0; 893 | }; 894 | name = Debug; 895 | }; 896 | 52D6DA031BEFFFBE002C0205 /* Release */ = { 897 | isa = XCBuildConfiguration; 898 | buildSettings = { 899 | APPLICATION_EXTENSION_API_ONLY = YES; 900 | CLANG_ENABLE_MODULES = YES; 901 | "CODE_SIGN_IDENTITY[sdk=appletvos*]" = ""; 902 | DEFINES_MODULE = YES; 903 | DYLIB_COMPATIBILITY_VERSION = 1; 904 | DYLIB_CURRENT_VERSION = 1; 905 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 906 | INFOPLIST_FILE = Configs/Once.plist; 907 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 908 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 909 | PRODUCT_BUNDLE_IDENTIFIER = "com.Once.Once-tvOS"; 910 | PRODUCT_NAME = Once; 911 | SDKROOT = appletvos; 912 | SKIP_INSTALL = YES; 913 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 914 | SWIFT_VERSION = 5.0; 915 | TARGETED_DEVICE_FAMILY = 3; 916 | TVOS_DEPLOYMENT_TARGET = 10.0; 917 | }; 918 | name = Release; 919 | }; 920 | 52D6DA211BF000BD002C0205 /* Debug */ = { 921 | isa = XCBuildConfiguration; 922 | buildSettings = { 923 | APPLICATION_EXTENSION_API_ONLY = YES; 924 | CLANG_ENABLE_MODULES = YES; 925 | CODE_SIGN_IDENTITY = "-"; 926 | COMBINE_HIDPI_IMAGES = YES; 927 | DEFINES_MODULE = YES; 928 | DYLIB_COMPATIBILITY_VERSION = 1; 929 | DYLIB_CURRENT_VERSION = 1; 930 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 931 | FRAMEWORK_VERSION = A; 932 | INFOPLIST_FILE = Configs/Once.plist; 933 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 934 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 935 | MACOSX_DEPLOYMENT_TARGET = 10.12; 936 | PRODUCT_BUNDLE_IDENTIFIER = "com.Once.Once-macOS"; 937 | PRODUCT_NAME = Once; 938 | SDKROOT = macosx; 939 | SKIP_INSTALL = YES; 940 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 941 | SWIFT_VERSION = 5.0; 942 | }; 943 | name = Debug; 944 | }; 945 | 52D6DA221BF000BD002C0205 /* Release */ = { 946 | isa = XCBuildConfiguration; 947 | buildSettings = { 948 | APPLICATION_EXTENSION_API_ONLY = YES; 949 | CLANG_ENABLE_MODULES = YES; 950 | CODE_SIGN_IDENTITY = "-"; 951 | COMBINE_HIDPI_IMAGES = YES; 952 | DEFINES_MODULE = YES; 953 | DYLIB_COMPATIBILITY_VERSION = 1; 954 | DYLIB_CURRENT_VERSION = 1; 955 | DYLIB_INSTALL_NAME_BASE = "@rpath"; 956 | FRAMEWORK_VERSION = A; 957 | INFOPLIST_FILE = Configs/Once.plist; 958 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; 959 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/Frameworks"; 960 | MACOSX_DEPLOYMENT_TARGET = 10.12; 961 | PRODUCT_BUNDLE_IDENTIFIER = "com.Once.Once-macOS"; 962 | PRODUCT_NAME = Once; 963 | SDKROOT = macosx; 964 | SKIP_INSTALL = YES; 965 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 966 | SWIFT_VERSION = 5.0; 967 | }; 968 | name = Release; 969 | }; 970 | DD7502831C68FCFC006590AF /* Debug */ = { 971 | isa = XCBuildConfiguration; 972 | buildSettings = { 973 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 974 | CODE_SIGN_IDENTITY = "-"; 975 | COMBINE_HIDPI_IMAGES = YES; 976 | INFOPLIST_FILE = Configs/OnceTests.plist; 977 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 978 | MACOSX_DEPLOYMENT_TARGET = 10.12; 979 | PRODUCT_BUNDLE_IDENTIFIER = "com.Once.Once-macOS-Tests"; 980 | PRODUCT_NAME = "$(TARGET_NAME)"; 981 | SDKROOT = macosx; 982 | SWIFT_VERSION = 5.0; 983 | TVOS_DEPLOYMENT_TARGET = 10.0; 984 | }; 985 | name = Debug; 986 | }; 987 | DD7502841C68FCFC006590AF /* Release */ = { 988 | isa = XCBuildConfiguration; 989 | buildSettings = { 990 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 991 | CODE_SIGN_IDENTITY = "-"; 992 | COMBINE_HIDPI_IMAGES = YES; 993 | INFOPLIST_FILE = Configs/OnceTests.plist; 994 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks"; 995 | MACOSX_DEPLOYMENT_TARGET = 10.12; 996 | PRODUCT_BUNDLE_IDENTIFIER = "com.Once.Once-macOS-Tests"; 997 | PRODUCT_NAME = "$(TARGET_NAME)"; 998 | SDKROOT = macosx; 999 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 1000 | SWIFT_VERSION = 5.0; 1001 | TVOS_DEPLOYMENT_TARGET = 10.0; 1002 | }; 1003 | name = Release; 1004 | }; 1005 | DD7502961C690C7A006590AF /* Debug */ = { 1006 | isa = XCBuildConfiguration; 1007 | buildSettings = { 1008 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 1009 | INFOPLIST_FILE = Configs/OnceTests.plist; 1010 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1011 | PRODUCT_BUNDLE_IDENTIFIER = "com.Once.Once-tvOS-Tests"; 1012 | PRODUCT_NAME = "$(TARGET_NAME)"; 1013 | SDKROOT = appletvos; 1014 | SWIFT_VERSION = 5.0; 1015 | TVOS_DEPLOYMENT_TARGET = 10.0; 1016 | }; 1017 | name = Debug; 1018 | }; 1019 | DD7502971C690C7A006590AF /* Release */ = { 1020 | isa = XCBuildConfiguration; 1021 | buildSettings = { 1022 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; 1023 | INFOPLIST_FILE = Configs/OnceTests.plist; 1024 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 1025 | PRODUCT_BUNDLE_IDENTIFIER = "com.Once.Once-tvOS-Tests"; 1026 | PRODUCT_NAME = "$(TARGET_NAME)"; 1027 | SDKROOT = appletvos; 1028 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 1029 | SWIFT_VERSION = 5.0; 1030 | TVOS_DEPLOYMENT_TARGET = 10.0; 1031 | }; 1032 | name = Release; 1033 | }; 1034 | /* End XCBuildConfiguration section */ 1035 | 1036 | /* Begin XCConfigurationList section */ 1037 | 52D6D9761BEFF229002C0205 /* Build configuration list for PBXProject "Once" */ = { 1038 | isa = XCConfigurationList; 1039 | buildConfigurations = ( 1040 | 52D6D98E1BEFF229002C0205 /* Debug */, 1041 | 52D6D98F1BEFF229002C0205 /* Release */, 1042 | ); 1043 | defaultConfigurationIsVisible = 0; 1044 | defaultConfigurationName = Release; 1045 | }; 1046 | 52D6D9901BEFF229002C0205 /* Build configuration list for PBXNativeTarget "Once-iOS" */ = { 1047 | isa = XCConfigurationList; 1048 | buildConfigurations = ( 1049 | 52D6D9911BEFF229002C0205 /* Debug */, 1050 | 52D6D9921BEFF229002C0205 /* Release */, 1051 | ); 1052 | defaultConfigurationIsVisible = 0; 1053 | defaultConfigurationName = Release; 1054 | }; 1055 | 52D6D9931BEFF229002C0205 /* Build configuration list for PBXNativeTarget "Once-iOS Tests" */ = { 1056 | isa = XCConfigurationList; 1057 | buildConfigurations = ( 1058 | 52D6D9941BEFF229002C0205 /* Debug */, 1059 | 52D6D9951BEFF229002C0205 /* Release */, 1060 | ); 1061 | defaultConfigurationIsVisible = 0; 1062 | defaultConfigurationName = Release; 1063 | }; 1064 | 52D6D9E71BEFFF6E002C0205 /* Build configuration list for PBXNativeTarget "Once-watchOS" */ = { 1065 | isa = XCConfigurationList; 1066 | buildConfigurations = ( 1067 | 52D6D9E81BEFFF6E002C0205 /* Debug */, 1068 | 52D6D9E91BEFFF6E002C0205 /* Release */, 1069 | ); 1070 | defaultConfigurationIsVisible = 0; 1071 | defaultConfigurationName = Release; 1072 | }; 1073 | 52D6DA011BEFFFBE002C0205 /* Build configuration list for PBXNativeTarget "Once-tvOS" */ = { 1074 | isa = XCConfigurationList; 1075 | buildConfigurations = ( 1076 | 52D6DA021BEFFFBE002C0205 /* Debug */, 1077 | 52D6DA031BEFFFBE002C0205 /* Release */, 1078 | ); 1079 | defaultConfigurationIsVisible = 0; 1080 | defaultConfigurationName = Release; 1081 | }; 1082 | 52D6DA201BF000BD002C0205 /* Build configuration list for PBXNativeTarget "Once-macOS" */ = { 1083 | isa = XCConfigurationList; 1084 | buildConfigurations = ( 1085 | 52D6DA211BF000BD002C0205 /* Debug */, 1086 | 52D6DA221BF000BD002C0205 /* Release */, 1087 | ); 1088 | defaultConfigurationIsVisible = 0; 1089 | defaultConfigurationName = Release; 1090 | }; 1091 | DD7502821C68FCFC006590AF /* Build configuration list for PBXNativeTarget "Once-macOS Tests" */ = { 1092 | isa = XCConfigurationList; 1093 | buildConfigurations = ( 1094 | DD7502831C68FCFC006590AF /* Debug */, 1095 | DD7502841C68FCFC006590AF /* Release */, 1096 | ); 1097 | defaultConfigurationIsVisible = 0; 1098 | defaultConfigurationName = Release; 1099 | }; 1100 | DD7502951C690C7A006590AF /* Build configuration list for PBXNativeTarget "Once-tvOS Tests" */ = { 1101 | isa = XCConfigurationList; 1102 | buildConfigurations = ( 1103 | DD7502961C690C7A006590AF /* Debug */, 1104 | DD7502971C690C7A006590AF /* Release */, 1105 | ); 1106 | defaultConfigurationIsVisible = 0; 1107 | defaultConfigurationName = Release; 1108 | }; 1109 | /* End XCConfigurationList section */ 1110 | }; 1111 | rootObject = 52D6D9731BEFF229002C0205 /* Project object */; 1112 | } 1113 | --------------------------------------------------------------------------------