Quellcode durchsuchen

Added support for XCode Version 8.0 beta and Swift 3.0 Preview 1.
Merge branch 'ipv6_with_ipv4_option'.

Damian Kołakowski vor 10 Jahren
Ursprung
Commit
d19aeea9ad

+ 5 - 3
Sources/Swifter/App.swift

@@ -13,6 +13,7 @@ public class App {
 
     public init() { }
     
+    @available(OSX 10.10, *)
     public func run(port: in_port_t = 9080, _ databasePath: String) throws -> Void {
         
         // Open database connection.
@@ -51,10 +52,11 @@ public class App {
         try self.server.start(port)
         
         print("Server started. Waiting for requests....")
+        
         #if os(Linux)
     	    while true { }
-	#else
-    	    NSRunLoop.current().run()
-	#endif
+        #else
+    	    RunLoop.current().run()
+        #endif
     }
 }

+ 15 - 15
Sources/Swifter/HttpResponse.swift

@@ -15,6 +15,7 @@ public enum SerializationError: ErrorProtocol {
 public protocol HttpResponseBodyWriter {
     func write(_ data: [UInt8])
     func write(_ data: ArraySlice<UInt8>)
+    func write(_ data: Data)
 }
 
 public enum HttpResponseBody {
@@ -29,21 +30,20 @@ public enum HttpResponseBody {
         do {
             switch self {
             case .Json(let object):
-		#if os(Linux)
-    	    	let data = [UInt8]("Not ready for Linux.".utf8)
-		return (data.count, {
-		    $0.write(data)
-		})
-		#else
-		        guard NSJSONSerialization.isValidJSONObject(object) else {
-		            throw SerializationError.InvalidObject
-		        }
-		        let json = try NSJSONSerialization.data(withJSONObject: object, options: NSJSONWritingOptions.prettyPrinted)
-		        let data = Array(UnsafeBufferPointer(start: UnsafePointer<UInt8>(json.bytes), count: json.length))
-		        return (data.count, {
-		            $0.write(data)
-		        })
-		#endif
+                #if os(Linux)
+                    let data = [UInt8]("Not ready for Linux.".utf8)
+                    return (data.count, {
+                        $0.write(data)
+                    })
+                #else
+                    guard JSONSerialization.isValidJSONObject(object) else {
+                        throw SerializationError.InvalidObject
+                    }
+                    let json = try JSONSerialization.data(withJSONObject: object, options: JSONSerialization.WritingOptions.prettyPrinted)
+                    return (json.count, {
+                        $0.write(json)
+                    })
+                #endif
             case .Text(let body):
                 let data = [UInt8](body.utf8)
                 return (data.count, {

+ 1 - 1
Sources/Swifter/HttpServer.swift

@@ -81,4 +81,4 @@ public class HttpServer: HttpServerIO {
             get { return nil }
         }
     }
-}
+}

+ 40 - 25
Sources/Swifter/HttpServerIO.swift

@@ -5,36 +5,41 @@
 //  Copyright (c) 2014-2016 Damian Kołakowski. All rights reserved.
 //
 
-import Foundation
+
+#if os(Linux)
+    import Glibc
+#else
+    import Foundation
+#endif
 
 public class HttpServerIO {
     
     private var listenSocket: Socket = Socket(socketFileDescriptor: -1)
     private var clientSockets: Set<Socket> = []
-    private let clientSocketsLock = NSLock()
+    private let clientSocketsLock = Lock()
     
     public typealias MiddlewareCallback = (HttpRequest) -> HttpResponse?
     
     public var middleware = [MiddlewareCallback]()
     
-    public func start(_ listenPort: in_port_t = 8080) throws {
+    @available(OSX 10.10, *)
+    public func start(_ listenPort: in_port_t = 8080, forceIPv4: Bool = false) throws {
         stop()
-        listenSocket = try Socket.tcpSocketForListen(listenPort)
-        dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0)) {
+        listenSocket = try Socket.tcpSocketForListen(listenPort, forceIPv4: forceIPv4)
+        DispatchQueue.global(attributes: DispatchQueue.GlobalAttributes.qosBackground).async {
             while let socket = try? self.listenSocket.acceptClientSocket() {
                 self.lock(self.clientSocketsLock) {
                     self.clientSockets.insert(socket)
                 }
-                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {
+                DispatchQueue.global(attributes: DispatchQueue.GlobalAttributes.qosBackground).async {
                     self.handleConnection(socket)
                     self.lock(self.clientSocketsLock) {
                         self.clientSockets.remove(socket)
                     }
-                })
+                }
             }
             self.stop()
         }
-        
     }
     
     public func stop() {
@@ -53,6 +58,7 @@ public class HttpServerIO {
     
     private func handleConnection(_ socket: Socket) {
         let address = try? socket.peername()
+        print(address)
         let parser = HttpParser()
         while let request = try? parser.readHttpRequest(socket) {
             request.address = address
@@ -87,7 +93,7 @@ public class HttpServerIO {
         return nil
     }
     
-    private func lock(_ handle: NSLock, closure: () -> ()) {
+    private func lock(_ handle: Lock, closure: () -> ()) {
         handle.lock()
         closure()
         handle.unlock();
@@ -98,6 +104,9 @@ public class HttpServerIO {
         func write(_ data: [UInt8]) {
             write(ArraySlice(data))
         }
+        func write(_ data: Data) {
+            data.withUnsafeBytes { write(Array(UnsafeBufferPointer(start: $0, count: data.count))) }
+        }
         func write(_ data: ArraySlice<UInt8>) {
             do {
                 try socket.writeUInt8(data)
@@ -137,31 +146,37 @@ public class HttpServerIO {
 
 #if os(Linux)
     
-    import Glibc
+import Glibc
+
+public class DispatchQueue {
     
-    let DISPATCH_QUEUE_PRIORITY_BACKGROUND = 0
+    private static let instance = DispatchQueue()
     
-    private class dispatch_context {
+    public struct GlobalAttributes {
+        public static let qosBackground: DispatchQueue.GlobalAttributes = GlobalAttributes()
+    }
+    
+    public class func global(attributes: DispatchQueue.GlobalAttributes) -> DispatchQueue {
+        return instance
+    }
+    
+    private class DispatchContext {
         let block: ((Void) -> Void)
         init(_ block: ((Void) -> Void)) {
             self.block = block
         }
     }
     
-    func dispatch_get_global_queue(_ queueId: Int, _ arg: Int) -> Int { return 0 }
-    
-    func dispatch_async(_ queueId: Int, _ block: ((Void) -> Void)) {
-        let unmanagedDispatchContext = Unmanaged.passRetained(dispatch_context(block))
-        let context = UnsafeMutablePointer<Void>(unmanagedDispatchContext.toOpaque())
+    public func async(execute work: @convention(block) () -> Swift.Void) {
+        let context = UnsafeMutablePointer<Void>(OpaquePointer(bitPattern: Unmanaged.passRetained(DispatchContext(work))))
         var pthread: pthread_t = 0
-        pthread_create(&pthread, nil, { (context: UnsafeMutablePointer<Void>?) -> UnsafeMutablePointer<Void>! in
-            if let context = context {
-                let unmanaged = Unmanaged<dispatch_context>.fromOpaque(context)
-                unmanaged.takeUnretainedValue().block()
-                unmanaged.release()
-            }
-            return context
+        pthread_create(&pthread, nil, { (context: UnsafeMutablePointer<Swift.Void>) -> UnsafeMutablePointer<Swift.Void>? in
+            let unmanaged = Unmanaged<DispatchContext>.fromOpaque(OpaquePointer(context))
+            unmanaged.takeUnretainedValue().block()
+            unmanaged.release()
+            return nil
         }, context)
     }
-    
+}
+
 #endif

+ 45 - 27
Sources/Swifter/Socket.swift

@@ -28,12 +28,14 @@ public enum SocketError: ErrorProtocol {
 
 public class Socket: Hashable, Equatable {
     
-    public class func tcpSocketForListen(_ port: in_port_t, maxPendingConnection: Int32 = SOMAXCONN) throws -> Socket {
-        
+
+    
+    public class func tcpSocketForListen(_ port: in_port_t, forceIPv4: Bool = false, maxPendingConnection: Int32 = SOMAXCONN) throws -> Socket {
+
         #if os(Linux)
-            let socketFileDescriptor = socket(AF_INET, Int32(SOCK_STREAM.rawValue), 0)
+            let socketFileDescriptor = socket(forceIPv4 ? AF_INET : AF_INET6, Int32(SOCK_STREAM.rawValue), 0)
         #else
-            let socketFileDescriptor = socket(AF_INET6, SOCK_STREAM, 0)
+            let socketFileDescriptor = socket(forceIPv4 ? AF_INET : AF_INET6, SOCK_STREAM, 0)
         #endif
         
         if socketFileDescriptor == -1 {
@@ -49,32 +51,48 @@ public class Socket: Hashable, Equatable {
         Socket.setNoSigPipe(socketFileDescriptor)
         
         #if os(Linux)
-            var addr = sockaddr_in()
-            addr.sin_family = sa_family_t(AF_INET)
-            addr.sin_port = Socket.htonsPort(port)
-            addr.sin_addr = in_addr(s_addr: in_addr_t(0))
-            addr.sin_zero = (0, 0, 0, 0, 0, 0, 0, 0)
+            var bindResult: Int32 = -1
+            if forceIPv4 {
+                var addr = sockaddr_in(sin_family: sa_family_t(AF_INET),
+                    sin_port: Socket.htonsPort(port),
+                    sin_addr: in_addr(s_addr: in_addr_t(0)),
+                    sin_zero:(0, 0, 0, 0, 0, 0, 0, 0))
+                
+                bindResult = withUnsafePointer(&addr) { bind(socketFileDescriptor, UnsafePointer<sockaddr>($0), socklen_t(sizeof(sockaddr_in))) }
+            } else {
+                var addr = sockaddr_in6(sin6_family: sa_family_t(AF_INET6),
+                    sin6_port: Socket.htonsPort(port),
+                    sin6_flowinfo: 0,
+                    sin6_addr: in6addr_any,
+                    sin6_scope_id: 0)
+                
+                bindResult = withUnsafePointer(&addr) { bind(socketFileDescriptor, UnsafePointer<sockaddr>($0), socklen_t(sizeof(sockaddr_in6))) }
+            }
         #else
-          // “Apple recommends always making an IPv6 socket to listen on.  The OS will automatically 
-          // “downgrade” it to an IPv4 socket if necessary, so there is no need to listen on two different sockets”.
-          var addr = sockaddr_in6(
-            sin6_len: UInt8(strideof(sockaddr_in6)),
-            sin6_family: UInt8(AF_INET6),
-            sin6_port: Socket.htonsPort(port),
-            sin6_flowinfo: 0,
-            sin6_addr: in6addr_any,
-            sin6_scope_id: 0
-          )
+            var bindResult: Int32 = -1
+            if forceIPv4 {
+                var addr = sockaddr_in(sin_len: UInt8(strideof(sockaddr_in)),
+                    sin_family: UInt8(AF_INET),
+                    sin_port: Socket.htonsPort(port),
+                    sin_addr: in_addr(s_addr: in_addr_t(0)),
+                    sin_zero:(0, 0, 0, 0, 0, 0, 0, 0))
+             
+                bindResult = withUnsafePointer(&addr) { bind(socketFileDescriptor, UnsafePointer<sockaddr>($0), socklen_t(sizeof(sockaddr_in))) }
+            } else {
+                // “Apple recommends always making an IPv6 socket to listen on.  The OS will automatically
+                // “downgrade” it to an IPv4 socket if necessary, so there is no need to listen on two different sockets”.
+                var addr = sockaddr_in6(sin6_len: UInt8(strideof(sockaddr_in6)),
+                    sin6_family: UInt8(AF_INET6),
+                    sin6_port: Socket.htonsPort(port),
+                    sin6_flowinfo: 0,
+                    sin6_addr: in6addr_any,
+                    sin6_scope_id: 0)
+                
+                bindResult = withUnsafePointer(&addr) { bind(socketFileDescriptor, UnsafePointer<sockaddr>($0), socklen_t(sizeof(sockaddr_in6))) }
+            }
         #endif
-        
-        var bind_addr = sockaddr_in6()
-        memcpy(&bind_addr, &addr, Int(sizeof(sockaddr_in6)))
-
-        let bind_result = withUnsafePointer(&bind_addr) { addr in
-          return bind(socketFileDescriptor, UnsafePointer<sockaddr>(addr), socklen_t(sizeof(sockaddr_in6)))
-        }
 
-        if bind_result == -1 {
+        if bindResult == -1 {
             let details = Socket.descriptionOfLastError()
             Socket.release(socketFileDescriptor)
             throw SocketError.BindFailed(details)

+ 30 - 0
SwifterSampleOSX/main.swift

@@ -0,0 +1,30 @@
+//
+//  main.swift
+//  SwifterOSX
+//  Copyright (c) 2015 Damian Kołakowski. All rights reserved.
+//
+
+import Foundation
+import Swifter
+
+
+do {
+    let server = demoServer(try File.currentWorkingDirectory())
+    server["/SwiftyJSON"] = { request in
+        let js: JSON = ["return": "OK", "isItAJSON": true, "code" : 200]
+        return .OK(.Custom(js, { object in
+            guard let obj = object as? JSON, let rawString = obj.rawString() else {
+                throw SerializationError.InvalidObject
+            }
+            return rawString
+        }))
+    }
+    server["/testAfterBaseRoute"] = { request in
+        return .OK(.Html("ok !"))
+    }
+    try server.start(9080, forceIPv4: true)
+    print("Server has started ( port = 9080 ). Try to connect now...")
+    NSRunLoop.mainRunLoop().run()
+} catch {
+    print("Server start error: \(error)")
+}

+ 30 - 9
XCode/Swifter.xcodeproj/project.pbxproj

@@ -663,7 +663,7 @@
 			isa = PBXProject;
 			attributes = {
 				LastSwiftUpdateCheck = 0720;
-				LastUpgradeCheck = 0700;
+				LastUpgradeCheck = 0800;
 				ORGANIZATIONNAME = "Damian Kołakowski";
 				TargetAttributes = {
 					7AE893E61C05127900A29F63 = {
@@ -671,6 +671,7 @@
 					};
 					7AE893FA1C0512C400A29F63 = {
 						CreatedOnToolsVersion = 7.1;
+						ProvisioningStyle = Manual;
 					};
 					7C839B6D19422CFF003A6950 = {
 						CreatedOnToolsVersion = 6.0;
@@ -968,6 +969,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				CLANG_ENABLE_MODULES = YES;
+				COMBINE_HIDPI_IMAGES = YES;
 				CURRENT_PROJECT_VERSION = 1.1.3;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DEFINES_MODULE = YES;
@@ -993,6 +995,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				CLANG_ENABLE_MODULES = YES;
+				COMBINE_HIDPI_IMAGES = YES;
 				COPY_PHASE_STRIP = NO;
 				CURRENT_PROJECT_VERSION = 1.1.3;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
@@ -1009,6 +1012,7 @@
 				PRODUCT_BUNDLE_IDENTIFIER = pl.kolakowski.SwifteriOS;
 				PRODUCT_NAME = Swifter;
 				SKIP_INSTALL = YES;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
 				VERSIONING_SYSTEM = "apple-generic";
 				VERSION_INFO_PREFIX = "";
 			};
@@ -1035,6 +1039,7 @@
 				MTL_ENABLE_DEBUG_INFO = YES;
 				PRODUCT_BUNDLE_IDENTIFIER = pl.kolakowski.SwifterMac;
 				PRODUCT_NAME = Swifter;
+				PROVISIONING_PROFILE_SPECIFIER = JHSX9UH35H/;
 				SDKROOT = macosx;
 				SKIP_INSTALL = YES;
 				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -1065,8 +1070,10 @@
 				MTL_ENABLE_DEBUG_INFO = NO;
 				PRODUCT_BUNDLE_IDENTIFIER = pl.kolakowski.SwifterMac;
 				PRODUCT_NAME = Swifter;
+				PROVISIONING_PROFILE_SPECIFIER = JHSX9UH35H/;
 				SDKROOT = macosx;
 				SKIP_INSTALL = YES;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
 				VERSIONING_SYSTEM = "apple-generic";
 				VERSION_INFO_PREFIX = "";
 			};
@@ -1075,6 +1082,7 @@
 		7C839B8819422D00003A6950 /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
 				CLANG_CXX_LIBRARY = "libc++";
@@ -1092,11 +1100,11 @@
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				COPY_PHASE_STRIP = NO;
 				CURRENT_PROJECT_VERSION = 1.1.3;
-				EMBEDDED_CONTENT_CONTAINS_SWIFT = NO;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				ENABLE_TESTABILITY = YES;
 				GCC_C_LANGUAGE_STANDARD = gnu99;
 				GCC_DYNAMIC_NO_PIC = NO;
+				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_OPTIMIZATION_LEVEL = 0;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"DEBUG=1",
@@ -1110,11 +1118,11 @@
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
-				MACOSX_DEPLOYMENT_TARGET = 10.9;
+				MACOSX_DEPLOYMENT_TARGET = 10.10;
 				METAL_ENABLE_DEBUG_INFO = YES;
 				ONLY_ACTIVE_ARCH = YES;
 				OTHER_SWIFT_FLAGS = "";
-				SDKROOT = appletvos;
+				SDKROOT = macosx;
 				SWIFT_INCLUDE_PATHS = "\"$(SRCROOT)/../Sources/CSQLite/\"";
 				SWIFT_OBJC_BRIDGING_HEADER = "";
 				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
@@ -1125,6 +1133,7 @@
 		7C839B8919422D00003A6950 /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				ALWAYS_SEARCH_USER_PATHS = NO;
 				CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
 				CLANG_CXX_LIBRARY = "libc++";
@@ -1142,10 +1151,10 @@
 				"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
 				COPY_PHASE_STRIP = YES;
 				CURRENT_PROJECT_VERSION = 1.1.3;
-				EMBEDDED_CONTENT_CONTAINS_SWIFT = NO;
 				ENABLE_NS_ASSERTIONS = NO;
 				ENABLE_STRICT_OBJC_MSGSEND = YES;
 				GCC_C_LANGUAGE_STANDARD = gnu99;
+				GCC_NO_COMMON_BLOCKS = YES;
 				GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
 				GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
 				GCC_WARN_UNDECLARED_SELECTOR = YES;
@@ -1153,11 +1162,11 @@
 				GCC_WARN_UNUSED_FUNCTION = YES;
 				GCC_WARN_UNUSED_VARIABLE = YES;
 				IPHONEOS_DEPLOYMENT_TARGET = 8.0;
-				MACOSX_DEPLOYMENT_TARGET = 10.9;
+				MACOSX_DEPLOYMENT_TARGET = 10.10;
 				METAL_ENABLE_DEBUG_INFO = NO;
 				ONLY_ACTIVE_ARCH = NO;
 				OTHER_SWIFT_FLAGS = "";
-				SDKROOT = appletvos;
+				SDKROOT = macosx;
 				SWIFT_INCLUDE_PATHS = "\"$(SRCROOT)/../Sources/CSQLite/\"";
 				SWIFT_OBJC_BRIDGING_HEADER = "";
 				TARGETED_DEVICE_FAMILY = "1,2";
@@ -1170,6 +1179,7 @@
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
 				CLANG_ENABLE_MODULES = YES;
+				COMBINE_HIDPI_IMAGES = YES;
 				INFOPLIST_FILE = "$(SRCROOT)/SwifterSampleiOS/Info.plist";
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = "pl.kolakowski.${PRODUCT_NAME:rfc1034identifier}";
@@ -1184,19 +1194,21 @@
 			buildSettings = {
 				ASSETCATALOG_COMPILER_APPICON_NAME = "App Icon & Top Shelf Image";
 				CLANG_ENABLE_MODULES = YES;
+				COMBINE_HIDPI_IMAGES = YES;
 				INFOPLIST_FILE = "$(SRCROOT)/SwifterSampleiOS/Info.plist";
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
 				PRODUCT_BUNDLE_IDENTIFIER = "pl.kolakowski.${PRODUCT_NAME:rfc1034identifier}";
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SWIFT_OBJC_BRIDGING_HEADER = "";
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
 			};
 			name = Release;
 		};
 		7CA4813F19A2EA8D0030B30D /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				CLANG_ENABLE_MODULES = YES;
-				EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
 				GCC_PREPROCESSOR_DEFINITIONS = (
 					"DEBUG=1",
 					"$(inherited)",
@@ -1215,15 +1227,16 @@
 		7CA4814019A2EA8D0030B30D /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				CLANG_ENABLE_MODULES = YES;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
-				EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
 				LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
 				MACOSX_DEPLOYMENT_TARGET = 10.9;
 				MTL_ENABLE_DEBUG_INFO = NO;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SDKROOT = macosx;
 				SWIFT_OBJC_BRIDGING_HEADER = "";
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
 			};
 			name = Release;
 		};
@@ -1261,6 +1274,7 @@
 				PRODUCT_BUNDLE_IDENTIFIER = pl.kolakowski.SwifterSampletvOS;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SDKROOT = appletvos;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
 				TARGETED_DEVICE_FAMILY = 3;
 				TVOS_DEPLOYMENT_TARGET = 9.1;
 			};
@@ -1270,6 +1284,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				CLANG_ENABLE_MODULES = YES;
+				COMBINE_HIDPI_IMAGES = YES;
 				CURRENT_PROJECT_VERSION = 1.1.3;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				DEFINES_MODULE = YES;
@@ -1295,6 +1310,7 @@
 			isa = XCBuildConfiguration;
 			buildSettings = {
 				CLANG_ENABLE_MODULES = YES;
+				COMBINE_HIDPI_IMAGES = YES;
 				COPY_PHASE_STRIP = NO;
 				CURRENT_PROJECT_VERSION = 1.1.3;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
@@ -1311,6 +1327,7 @@
 				PRODUCT_BUNDLE_IDENTIFIER = pl.kolakowski.SwiftertvOS;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SKIP_INSTALL = YES;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
 				VERSIONING_SYSTEM = "apple-generic";
 				VERSION_INFO_PREFIX = "";
 			};
@@ -1319,6 +1336,7 @@
 		7CCD87651C66099B0068099B /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				COMBINE_HIDPI_IMAGES = YES;
 				DEBUG_INFORMATION_FORMAT = dwarf;
 				GCC_NO_COMMON_BLOCKS = YES;
 				INFOPLIST_FILE = SwifteriOSTests/Info.plist;
@@ -1333,6 +1351,7 @@
 		7CCD87661C66099B0068099B /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				COMBINE_HIDPI_IMAGES = YES;
 				COPY_PHASE_STRIP = NO;
 				DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
 				GCC_NO_COMMON_BLOCKS = YES;
@@ -1342,6 +1361,7 @@
 				MTL_ENABLE_DEBUG_INFO = NO;
 				PRODUCT_BUNDLE_IDENTIFIER = pl.kolakowski.SwifteriOSTests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
 			};
 			name = Release;
 		};
@@ -1377,6 +1397,7 @@
 				PRODUCT_BUNDLE_IDENTIFIER = pl.kolakowski.SwifterOSXTests;
 				PRODUCT_NAME = "$(TARGET_NAME)";
 				SDKROOT = macosx;
+				SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
 			};
 			name = Release;
 		};

+ 1 - 1
XCode/Swifter.xcodeproj/xcshareddata/xcschemes/SwifterMac.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "0710"
+   LastUpgradeVersion = "0800"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 1 - 1
XCode/Swifter.xcodeproj/xcshareddata/xcschemes/SwifteriOS.xcscheme

@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Scheme
-   LastUpgradeVersion = "0710"
+   LastUpgradeVersion = "0800"
    version = "1.3">
    <BuildAction
       parallelizeBuildables = "YES"

+ 7 - 3
XCode/SwifterSampleOSX/main.swift

@@ -12,9 +12,13 @@ do {
     server["/testAfterBaseRoute"] = { request in
         return .OK(.Html("ok !"))
     }
-    try server.start(9080)
+    if #available(OSX 10.10, *) {
+        try server.start(9080)
+    } else {
+        // Fallback on earlier versions
+    }
     print("Server has started ( port = 9080 ). Try to connect now...")
-    NSRunLoop.main().run()
+    RunLoop.main().run()
 } catch {
     print("Server start error: \(error)")
-}
+}