An Xcode project generates the following archive:
$ tree Yams-macosx.xcarchive
Yams-macosx.xcarchive
βββ Info.plist
βββ Products
β βββ Library
β βββ Frameworks
β βββ Yams.framework
# Xcode 10.2 | |
# please use within Xcode environment (Build Phases -> Run Script or Scheme -> Post Actions) | |
xcodebuild -version | |
UNIVERSAL_OUTPUTFOLDER=${BUILD_DIR}/${CONFIGURATION}-universal | |
# make sure the output directory exists | |
mkdir -p "${UNIVERSAL_OUTPUTFOLDER}" | |
env > env.txt | |
# Step 1. Build Device and Simulator versions | |
xcodebuild -project "${PROJECT_NAME}.xcodeproj" -target "${PROJECT_NAME}" ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" clean build |
import Foundation | |
@propertyWrapper | |
public struct Validate<Value> { | |
fileprivate let _isValid: (Value) -> Bool | |
public let asserts: Bool | |
public let useLastValid: Bool | |
public let message: (Value) -> String |
An Xcode project generates the following archive:
$ tree Yams-macosx.xcarchive
Yams-macosx.xcarchive
βββ Info.plist
βββ Products
β βββ Library
β βββ Frameworks
β βββ Yams.framework
/// Log the current filename and function, with an optional extra message. Call this with no arguments to simply print the current file and function. Log messages will include an Emoji selected from a list in the function, based on the hash of the filename, to make it easier to see which file a message comes from. | |
/// - Parameter message: Optional message to include | |
/// - file: Don't use; Swift will fill in the file name | |
/// - function: Don't use, Swift will fill in the function name | |
/// - line: Don't use, Swift will fill in the line number | |
func logMilestone(_ message: String? = nil, file: String = #file, function: String = #function, line: Int = #line) -> Void { | |
#if DEBUG | |
// Feel free to change the list of Emojis, but don't make it shorter, because a longer list is better. | |
let logEmojis = ["π","π","π±","π","πΊ","π½","πΎ","π€","π","π","π","π§ ","π","π§€","πΆ","π±","π","πΉ","π¦","π»","π¨","π΅","π¦","π¦","π","π₯","π₯","βοΈ","π","π₯","π½","π","πΏ","πΉ","π","β€οΈ","π§‘","π","π","π","π","π"] | |
let logEmoji = logEmojis[abs( |
If you work on a Swift project that follows the Model-View-ViewModel (MVVM) architecture or similar, you may want to jump to counterpart in Xcode from your view to your model, and then to your view model. (ie. by using Ctrl+Cmd+Up and Ctrl+Cmd+Down).
You can do this in recent versions of Xcode by setting a configuration default.
From a terminal, just type this command and press Enter:
defaults write com.apple.dt.Xcode IDEAdditionalCounterpartSuffixes -array-add "ViewModel" "View"
func testNotifications() { | |
// map all authorizationStatus with expected Result | |
let authorizationStatusMap: [UNAuthorizationStatus: Int] = [.authorized: 1, .denied: 0, .notDetermined: 0, .provisional: 1] | |
UNNotificationSettings.swizzleAuthorizationStatus() | |
authorizationStatusMap.forEach { (key: UNAuthorizationStatus, value: Int) in | |
UNNotificationSettings.fakeAuthorizationStatus = key | |
let mockCenter = UserNotificationCenterMock() | |
let mockCoder = MockNSCoder() |
@propertyWrapper | |
public struct AnyProxy<EnclosingSelf, Value> { | |
private let keyPath: ReferenceWritableKeyPath<EnclosingSelf, Value> | |
public init(_ keyPath: ReferenceWritableKeyPath<EnclosingSelf, Value>) { | |
self.keyPath = keyPath | |
} | |
@available(*, unavailable, message: "The wrapped value must be accessed from the enclosing instance property.") | |
public var wrappedValue: Value { |