├── FBTweaks+Macros.swift ├── LICENSE ├── ObjC-Briding-Header.h └── README.md /FBTweaks+Macros.swift: -------------------------------------------------------------------------------- 1 | // 2 | // FBTweaks+Macros.swift 3 | // 4 | // Created by Pierre Dulac on 16/09/2014. 5 | // Copyright (c) 2014 Pierre Dulac. All rights reserved. 6 | // 7 | 8 | import Foundation 9 | import UIKit 10 | 11 | private let _tweakIdentifier = "com.pierredulac.tweaks" 12 | 13 | 14 | func getTweakIdentifier(categoryName: String!, collectionName: String!, tweakName: String!) -> String { 15 | return "FBTweak:\(categoryName)-\(collectionName)-\(tweakName)" 16 | } 17 | 18 | func tweakBind(object: NSObject!, property: String!, categoryName: String!, collectionName: String!, tweakName: String!, defaultValue: T) { 19 | tweakBind(object, property, categoryName, collectionName, tweakName, defaultValue, nil, nil) 20 | } 21 | 22 | func tweakBind(object: NSObject!, property: String!, categoryName: String!, collectionName: String!, tweakName: String!, defaultValue: T, minValue: T?, maxValue: T?) { 23 | #if NDEBUG 24 | let tweak = _tweakInternal(categoryName, collectionName, tweakName, defaultValue, nil, nil) 25 | object.setValue(_tweakValueInternal(tweak, defaultValue), 26 | forKey: property) 27 | #else 28 | let tweak = _tweakInternal(categoryName, collectionName, tweakName, defaultValue, minValue, maxValue) 29 | _tweakBindInternal(object, property, defaultValue, tweak) 30 | #endif 31 | } 32 | 33 | func tweak(categoryName: String!, collectionName: String!, tweakName: String!, defaultValue: T, minValue: T?, maxValue: T?) -> T { 34 | #if NDEBUG 35 | return defaultValue 36 | #else 37 | let tweak = _tweakInternal(categoryName, collectionName, tweakName, defaultValue, minValue, maxValue) 38 | return _tweakValueUnpackedInternal(tweak!, defaultValue) 39 | #endif 40 | } 41 | 42 | // MARK: Internals 43 | 44 | func _tweakInternal(categoryName: String!, collectionName: String!, tweakName: String!, defaultValue: T, minValue: T?, maxValue: T?) -> FBTweak! { 45 | let store = FBTweakStore.sharedInstance() 46 | var category: FBTweakCategory? = store.tweakCategoryWithName(categoryName) 47 | if category == nil { 48 | category = FBTweakCategory(name: categoryName) 49 | store.addTweakCategory(category) 50 | } 51 | var collection: FBTweakCollection? = category!.tweakCollectionWithName(collectionName) 52 | if collection == nil { 53 | collection = FBTweakCollection(name: collectionName) 54 | category!.addTweakCollection(collection) 55 | } 56 | let identifier = getTweakIdentifier(categoryName, collectionName, tweakName) 57 | var tweak: FBTweak? = collection?.tweakWithIdentifier(identifier) 58 | if tweak == nil { 59 | tweak = FBTweak(identifier: identifier) 60 | tweak!.name = tweakName 61 | collection!.addTweak(tweak!) 62 | } 63 | 64 | tweak!.defaultValue = _tweakPackValue(defaultValue) 65 | if minValue != nil { 66 | tweak!.minimumValue = _tweakPackValue(minValue!) 67 | } 68 | if maxValue != nil { 69 | tweak!.maximumValue = _tweakPackValue(maxValue!) 70 | } 71 | 72 | return tweak! 73 | } 74 | 75 | func _tweakBindInternal(object: NSObject!, property: String!, defaultValue: T, tweak: FBTweak!) { 76 | object.setValue(_tweakValueInternal(tweak, defaultValue), 77 | forKey: property) 78 | 79 | let observer: _FBTweakBindObserver = _FBTweakBindObserver(tweak: tweak, { 80 | (obj: AnyObject!) in 81 | 82 | let _object = obj as? NSObject 83 | _object?.setValue(_tweakValueInternal(tweak, defaultValue), 84 | forKey: property) 85 | }) 86 | 87 | observer.attachToObject(object) 88 | } 89 | 90 | func _tweakValueInternal(tweak: FBTweak!, defaultValue: T) -> FBTweakValue? { 91 | let currentValue: FBTweakValue? = tweak.currentValue ?? tweak.defaultValue 92 | return currentValue 93 | } 94 | 95 | func _tweakValueUnpackedInternal(tweak: FBTweak!, defaultValue: T) -> T { 96 | return _tweakUnpackValue(_tweakValueInternal(tweak, defaultValue), defaultValue) 97 | } 98 | 99 | func _tweakPackValue(value: T) -> AnyObject? { 100 | 101 | // if the value is already an object we return it 102 | if let v = value as? NSNumber { 103 | return v 104 | } 105 | if let v = value as? NSValue { 106 | return v 107 | } 108 | 109 | // pack Int 110 | if let v = value as? Int { 111 | return NSNumber(long: v) 112 | } 113 | if let v = value as? Int8 { 114 | return NSNumber(char: v) 115 | } 116 | if let v = value as? Int16 { 117 | return NSNumber(short: v) 118 | } 119 | if let v = value as? Int32 { 120 | return NSNumber(int: v) 121 | } 122 | if let v = value as? Int64 { 123 | return NSNumber(longLong: v) 124 | } 125 | if let v = value as? UInt { 126 | return NSNumber(unsignedLong: v) 127 | } 128 | if let v = value as? UInt8 { 129 | return NSNumber(unsignedChar: v) 130 | } 131 | if let v = value as? UInt16 { 132 | return NSNumber(unsignedShort: v) 133 | } 134 | if let v = value as? UInt32 { 135 | return NSNumber(unsignedInt: v) 136 | } 137 | if let v = value as? UInt64 { 138 | return NSNumber(unsignedLongLong: v) 139 | } 140 | 141 | // pack Decimal 142 | if let v = value as? Float { 143 | return NSNumber(float: v) 144 | } 145 | if let v = value as? CGFloat { 146 | return NSNumber(double: Double(v)) 147 | } 148 | if let v = value as? Double { 149 | return NSNumber(double: v) 150 | } 151 | 152 | // pack Boolean 153 | if let v = value as? Bool { 154 | return NSNumber(bool: v) 155 | } 156 | 157 | println("Warning: Unknown value type \(value.dynamicType) for value \(value), can't be packed") 158 | return nil 159 | } 160 | 161 | func _tweakUnpackValue(value: AnyObject?, defaultValue: T) -> T { 162 | 163 | // unpack Int 164 | if defaultValue is Int { 165 | return value?.integerValue as T 166 | } 167 | if defaultValue is Int8 { 168 | return value?.charValue as T 169 | } 170 | if defaultValue is Int16 { 171 | return value?.shortValue as T 172 | } 173 | if defaultValue is Int32 { 174 | return value?.intValue as T 175 | } 176 | if defaultValue is Int64 { 177 | return value?.longLongValue as T 178 | } 179 | if defaultValue is UInt { 180 | return value?.unsignedIntegerValue as T 181 | } 182 | if defaultValue is UInt8 { 183 | return value?.unsignedCharValue as T 184 | } 185 | if defaultValue is UInt16 { 186 | return value?.unsignedShortValue as T 187 | } 188 | if defaultValue is UInt32 { 189 | return value?.unsignedIntValue as T 190 | } 191 | if defaultValue is UInt64 { 192 | return value?.unsignedLongLongValue as T 193 | } 194 | 195 | // unpack Decimal 196 | if defaultValue is Float { 197 | return value?.floatValue as T 198 | } 199 | if defaultValue is Double { 200 | return value?.doubleValue as T 201 | } 202 | 203 | // unpack Boolean 204 | if defaultValue is Bool { 205 | return value?.boolValue as T 206 | } 207 | 208 | return defaultValue as T 209 | } 210 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014 Pierre Dulac (http://dulaccc.me/) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. -------------------------------------------------------------------------------- /ObjC-Briding-Header.h: -------------------------------------------------------------------------------- 1 | // 2 | // ObjC-Bridging-Header.h 3 | // 4 | // Created by Pierre Dulac on 14/08/2014. 5 | // Copyright (c) 2014 Pierre Dulac. All rights reserved. 6 | // 7 | 8 | #ifndef ObjC_Briding_Header_h 9 | #define ObjC_Briding_Header_h 10 | 11 | #import "FBTweakEnabled.h" 12 | #import "FBTweak.h" 13 | #import "FBTweakStore.h" 14 | #import "FBTweakCategory.h" 15 | #import "FBTweakCollection.h" 16 | #import "_FBTweakBindObserver.h" 17 | #import "FBTweakShakeWindow.h" 18 | 19 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Tweaks *Macros* for Swift 2 | 3 | > Poetry cannot be translated; and, therefore, it is the poets that preserve the languages. 4 | > 5 | > *Samuel Johnson* 6 | 7 | 8 | ### Why this extension ? 9 | 10 | Because macros does not exists anymore in Swift, so we have to translate them into Swift functions `func`. 11 | 12 | ### Generics 13 | 14 | Swift brings the power of generics, so this extension use it pretty intensively. The major benefit is that tweaks are now checked at compile time. 15 | 16 | For instance, if you want to control the animation duration, you can do : 17 | 18 | ```swift 19 | let duration: Double = tweak("Advanced", "Animation", "Duration", Double(1.0), Double(0.3), Double(8.0)) 20 | ``` 21 | 22 | > NB: the `let duration: Double` is to prove to you that the `tweak(_:_:_:_:_:_:)` function is returining the right type, which is `Double` in this case. 23 | 24 | ## Installation 25 | 26 | Three simple steps : 27 | 28 | * of course, include the original `FBTweaks` project with one of the [two options](https://github.com/facebook/Tweaks#installation) they provide 29 | * include the `FBTweaks+Macros.swift` 30 | * add the content of the `ObjC-Briding-Header.h` file to your own Objective-C Briding Header file. 31 | 32 | And you're good to go. 33 | 34 | ## Known issues 35 | 36 | * tweaks are not statically stored during compile time in the `__FBTweak` section of the mach-o, as they are in the [objective-c macros implementation](https://github.com/facebook/Tweaks#how-it-works). If you figure out a way to do that with the Swift compiler, do not hesitate to make a PR. 37 | 38 | 39 | ## Contact 40 | 41 | [Pierre Dulac](http://github.com/dulaccc) 42 | [@dulaccc](https://twitter.com/dulaccc) 43 | 44 | ## License 45 | Tweaks-swift is available under the MIT license. See the LICENSE file for more info. 46 | --------------------------------------------------------------------------------