Thursday, June 25, 2015

QuantLib 1.6 framework (libc++) for iOS and Mac OS X

QuantLib 1.6 framework (compile with -std=c++11 -stdlib=libc++) and prefix pre-built binary.
Architectures in the fat file: framework/ql.framework/ql are: armv7 i386 x86_64 arm64

Pre-built framework and libraries prefix for QuantLib 1.6 can be downloaded from here.

Below is the bash script (modified from http://github.com/philipbarnes/quantlib-on-iOS) to build the framework (compile with -std=c++11 -stdlib=libc++).
Requires Boost 1.58.0 pre-built binary which can be downloaded from here.

build-ql.sh    Select all
#!/bin/bash #=============================================================================== # Filename: build-ql.sh #=============================================================================== # Changes: # # Builds a quantlib framework for iOS & MacOSX # # Requires a pre-built version of boost built using the boost.sh script by # Pete Goodliffe. The structure of this script is based on Pete's boost.sh # # This takes a brute-force approach to the build and builds the arm6, arm7, arm64 and # i386 and x86_64 versions of quantlib one after the other. It makes clean between builds. # # To configure the script, change the variables below to point to the build of # boost lib, include and SYSROOT #=============================================================================== : ${CURRENTDIR:=`pwd`/} : ${BOOST_HOME:=$CURRENTDIR/../ofxiOSBoost-master/usr/local/lib} : ${BOOST_SRC:=$CURRENTDIR/../ofxiOSBoost-master/usr/local/include} : ${ARMV6_SYSROOT:=/Applications/Xcode431.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.1.sdk} : ${ARMV7_SYSROOT:=/Applications/Xcode501.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.sdk} : ${ARMV7S_SYSROOT:=/Applications/Xcode501.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS7.0.sdk} : ${ARM64_SYSROOT:=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk} : ${iPhoneSimulator_SYSROOT:=/Applications/Xcode501.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator7.0.sdk} : ${MacOSX_SYSROOT:=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk} #=============================================================================== # The number of jobs for make to run. On a 2.8 Mac Pro 8 core it takes around # 31 minutes with 9 jobs to build all the libraries and framework. #=============================================================================== : ${JOBS:=3} #=============================================================================== # No need to change these variables. # Xcode 4.x and 5.x are used to build the libraries. This now resides in # /Applications/Xcode???.app/Contents #=============================================================================== : ${ARM_DEV_DIR:=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer} : ${SIM_DEV_DIR:=/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer} : ${SRCDIR:=`pwd`/src} : ${BUILDDIR:=`pwd`/build} : ${PREFIXDIR:=`pwd`/prefix} : ${FRAMEWORKDIR:=`pwd`/framework} #=============================================================================== # Utility functions for reporting #=============================================================================== displayConfiguration() { echo echo " =================================================================" echo echo " Configuration" echo " SRCDIR :" $SRCDIR echo " BUILDDIR :" $BUILDDIR echo " PREFIXDIR :" $PREFIXDIR echo " FRAMEWORKDIR :" $FRAMEWORKDIR echo echo " BOOST_HOME :" $BOOST_HOME echo " BOOST_SRC :" $BOOST_SRC echo echo " JOBS :" $JOBS echo echo " ARM_DEV_DIR :" $ARM_DEV_DIR echo " SIM_DEV_DIR :" $SIM_DEV_DIR } displayMessage() { echo echo " =================================================================" echo " $@" echo } doneSection() { echo echo " =================================================================" echo " Done: $@" echo } abort() { echo echo "Aborted: $@" exit 1 } #=============================================================================== # Prepare the directory structures #=============================================================================== cleanEverythingReadyToStart() { displayMessage "Cleaning everything ready to start" rm -rf $BUILDDIR #rm -rf $PREFIXDIR #rm -rf $FRAMEWORKDIR doneSection } #=============================================================================== # Prepare the directory structures #=============================================================================== createDirectoryStructure() { displayMessage "Creating directory structure" [ -d $BUILDDIR ] || mkdir -p $BUILDDIR [ -d $PREFIXDIR ] || mkdir -p $PREFIXDIR [ -d $FRAMEWORKDIR ] || mkdir -p $FRAMEWORKDIR doneSection } #=============================================================================== # Build the armv6 quantlib libraries #=============================================================================== buildArmv6() { displayMessage "Configuring armv6 libraries" rm -rf $PREFIXDIR/armv6 make distclean > /dev/null # requires clang 3.1 lib in Xcode 4.3.1 for building armv6 binary CC="/Applications/Xcode431.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" \ CXX="/Applications/Xcode431.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang++" \ CPP="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cpp" \ CXXCPP="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cpp" \ CXXFLAGS="-arch armv6 -std=c++11 -stdlib=libc++ -isysroot $ARMV6_SYSROOT" \ CFLAGS="-arch armv6 -std=c99 -isysroot $ARMV6_SYSROOT" \ LDFLAGS="-stdlib=libc++" \ ./configure --with-boost-include=$BOOST_SRC \ --with-boost-lib=$BOOST_HOME \ --host=arm-apple-darwin10 \ --target=arm-apple-darwin10 \ --with-sysroot=$ARMV6_SYSROOT \ --prefix=/usr/local \ --disable-shared --enable-static displayMessage "Making Armv6 libraries" make -j $JOBS && make DESTDIR=$PREFIXDIR/armv6 install || abort "make armv6 failed" doneSection "armv6 done" } #=============================================================================== # Build the armv7 quantlib libraries #=============================================================================== buildArmv7() { displayMessage "Configuring armv7 libraries" rm -rf $PREFIXDIR/armv7 make distclean > /dev/null CC="xcrun --sdk iphoneos clang" \ CXX="xcrun --sdk iphoneos clang++" \ CPP="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cpp" \ CXXCPP="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cpp" \ CXXFLAGS="-arch armv7 -std=c++11 -stdlib=libc++ -isysroot $ARMV7_SYSROOT" \ CFLAGS="-arch armv7 -std=c99 -isysroot $ARMV7_SYSROOT" \ LDFLAGS="-stdlib=libc++" \ ./configure --with-boost-include=$BOOST_SRC \ --with-boost-lib=$BOOST_HOME \ --host=arm-apple-darwin10 \ --target=arm-apple-darwin10 \ --with-sysroot=$ARMV7_SYSROOT \ --prefix=/usr/local \ --disable-shared --enable-static displayMessage "making armv7 libraries" make -j $JOBS && make DESTDIR=$PREFIXDIR/armv7 install || abort "make armv7 failed" doneSection "armv7 done" } #=============================================================================== # Build the armv7s quantlib libraries #=============================================================================== buildArmv7s() { displayMessage "Configuring armv7s libraries" rm -rf $PREFIXDIR/armv7s make distclean > /dev/null CC="xcrun --sdk iphoneos clang" \ CXX="xcrun --sdk iphoneos clang++" \ CPP="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cpp" \ CXXCPP="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cpp" \ CXXFLAGS="-arch armv7s -std=c++11 -stdlib=libc++ -isysroot $ARMV7S_SYSROOT" \ CFLAGS="-arch armv7s -std=c99 -isysroot $ARMV7S_SYSROOT" \ LDFLAGS="-stdlib=libc++" \ ./configure --with-boost-include=$BOOST_SRC \ --with-boost-lib=$BOOST_HOME \ --host=arm-apple-darwin10 \ --target=arm-apple-darwin10 \ --with-sysroot=$ARMV7S_SYSROOT \ --prefix=/usr/local \ --disable-shared --enable-static displayMessage "making armv7s libraries" make -j $JOBS && make DESTDIR=$PREFIXDIR/armv7s install || abort "make armv7s failed" doneSection "armv7s done" } #=============================================================================== # Build the arm64 quantlib libraries #=============================================================================== buildArm64() { displayMessage "Configuring arm64 libraries" rm -rf $PREFIXDIR/arm64 make distclean > /dev/null CC="xcrun --sdk iphoneos clang" \ CXX="xcrun --sdk iphoneos clang++" \ CPP="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cpp" \ CXXCPP="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cpp" \ CXXFLAGS="-arch arm64 -std=c++11 -stdlib=libc++ -isysroot $ARM64_SYSROOT" \ CFLAGS="-arch arm64 -std=c99 -isysroot $ARM64_SYSROOT" \ LDFLAGS="-stdlib=libc++" \ ./configure --with-boost-include=$BOOST_SRC \ --with-boost-lib=$BOOST_HOME \ --host=arm-apple-darwin10 \ --target=arm-apple-darwin10 \ --with-sysroot=$ARM64_SYSROOT \ --prefix=/usr/local \ --disable-shared --enable-static displayMessage "making arm64 libraries" make -j $JOBS && make DESTDIR=$PREFIXDIR/arm64 install || abort "make arm64 failed" doneSection "arm64 done" } #=============================================================================== # Build the i386 quantlib libraries #=============================================================================== buildi386() { displayMessage "Configuring i386 libraries" rm -rf $PREFIXDIR/i386 make distclean > /dev/null CC="xcrun --sdk iphonesimulator clang" \ CXX="xcrun --sdk iphonesimulator clang++" \ CPP="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cpp" \ CXXCPP="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cpp" \ CXXFLAGS="-arch i386 -std=c++11 -stdlib=libc++ -isysroot $iPhoneSimulator_SYSROOT" \ CFLAGS="-arch i386 -isysroot $iPhoneSimulator_SYSROOT" \ LDFLAGS="-stdlib=libc++" \ ./configure --with-boost-include=$BOOST_SRC \ --with-boost-lib=$BOOST_HOME \ --with-sysroot=$iPhoneSimulator_SYSROOT \ --prefix=/usr/local \ --disable-shared --enable-static displayMessage "Building i386 libraries" make -j $JOBS && make DESTDIR=$PREFIXDIR/i386 install || abort "make i386 failed" doneSection "i386 done" } #=============================================================================== # Build the x86_64 quantlib libraries #=============================================================================== buildx86_64() { displayMessage "Configuring x86_64 libraries" rm -rf $PREFIXDIR/x86_64 make distclean > /dev/null CC="xcrun --sdk macosx clang" \ CXX="xcrun --sdk macosx clang++" \ CPP="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cpp" \ CXXCPP="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/cpp" \ CXXFLAGS="-arch x86_64 -std=c++11 -stdlib=libc++ -mmacosx-version-min=10.7 -isysroot $MacOSX_SYSROOT" \ CFLAGS="-arch x86_64 -mmacosx-version-min=10.7 -isysroot $MacOSX_SYSROOT" \ LDFLAGS="-stdlib=libc++" \ ./configure --with-boost-include=$BOOST_SRC \ --with-boost-lib=$BOOST_HOME \ --with-sysroot=$MacOSX_SYSROOT \ --prefix=/usr/local \ --disable-shared --enable-static displayMessage "Building x86_64 libraries" make -j $JOBS && make DESTDIR=$PREFIXDIR/x86_64 install || abort "make x86_64 failed" doneSection "x86_64 done" } #=============================================================================== # Build the framework # # Unlike the boost build by Pete Goodliffe, all the libraries are created # individually and so do not need to be unpacked and scrunched together. # # Create the framework libraries in-site #=============================================================================== buildFramework() { VERSION_TYPE=Alpha FRAMEWORK_NAME=ql FRAMEWORK_VERSION=A FRAMEWORK_CURRENT_VERSION=1.6 FRAMEWORK_COMPATIBILITY_VERSION=1.6 FRAMEWORK_BUNDLE=$FRAMEWORKDIR/$FRAMEWORK_NAME.framework rm -rf $FRAMEWORKDIR displayMessage "Framework: Setting up directories..." mkdir -p $FRAMEWORK_BUNDLE mkdir -p $FRAMEWORK_BUNDLE/Versions mkdir -p $FRAMEWORK_BUNDLE/Versions/$FRAMEWORK_VERSION mkdir -p $FRAMEWORK_BUNDLE/Versions/$FRAMEWORK_VERSION/Resources mkdir -p $FRAMEWORK_BUNDLE/Versions/$FRAMEWORK_VERSION/Headers mkdir -p $FRAMEWORK_BUNDLE/Versions/$FRAMEWORK_VERSION/Documentation displayMessage "Framework: Creating symlinks..." ln -s $FRAMEWORK_VERSION $FRAMEWORK_BUNDLE/Versions/Current ln -s Versions/Current/Headers $FRAMEWORK_BUNDLE/Headers ln -s Versions/Current/Resources $FRAMEWORK_BUNDLE/Resources ln -s Versions/Current/Documentation $FRAMEWORK_BUNDLE/Documentation ln -s Versions/Current/$FRAMEWORK_NAME $FRAMEWORK_BUNDLE/$FRAMEWORK_NAME FRAMEWORK_INSTALL_NAME=$FRAMEWORK_BUNDLE/Versions/$FRAMEWORK_VERSION/$FRAMEWORK_NAME displayMessage "Framework: Lipoing library into $FRAMEWORK_INSTALL_NAME" /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo \ -arch armv7 "$PREFIXDIR/armv7/usr/local/lib/libQuantLib.a" \ -arch armv7s "$PREFIXDIR/armv7s/usr/local/lib/libQuantLib.a" \ -arch arm64 "$PREFIXDIR/arm64/usr/local/lib/libQuantLib.a" \ -arch i386 "$PREFIXDIR/i386/usr/local/lib/libQuantLib.a" \ -arch x86_64 "$PREFIXDIR/x86_64/usr/local/lib/libQuantLib.a" \ -output "$FRAMEWORK_INSTALL_NAME" \ -create || abort "Lipo $1 failed" displayMessage "Framework: Copying includes..." cp -r $PREFIXDIR/x86_64/usr/local/include/ql/* $FRAMEWORK_BUNDLE/Headers/ displayMessage "Framework: Creating plist..." cat > $FRAMEWORK_BUNDLE/Resources/Info.plist <<EOF <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <plist version="1.0"> <dict> <key>CFBundleDevelopmentRegion</key> <string>English</string> <key>CFBundleExecutable</key> <string>${FRAMEWORK_NAME}</string> <key>CFBundleIdentifier</key> <string>org.quantlib</string> <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string> <key>CFBundlePackageType</key> <string>FMWK</string> <key>CFBundleSignature</key> <string>????</string> <key>CFBundleVersion</key> <string>${FRAMEWORK_CURRENT_VERSION}</string> </dict> </plist> EOF doneSection "$FRAMEWORK_BUNDLE" } #=============================================================================== # Execution starts here #=============================================================================== displayConfiguration cleanEverythingReadyToStart createDirectoryStructure buildArmv7 buildArm64 buildi386 buildx86_64 buildFramework displayMessage "Completed successfully"


Note: QuantLib 1.5 is incompatible with Boost 1.58. Use Boost 1.57 instead.

Here is the framework and prefix for Quantlib 1.6+1.5

Here is the framework and prefix for Boost 1.58+1.57

Saturday, June 20, 2015

iOS Drawing in swift playground

swift Playground can be used for prototype iOS Drawing



swift Plyaground    Select all
//: Playground - a place where programmer can prototype import UIKit class IconView: UIView { override func drawRect(rect: CGRect) { drawRawBackgroundWithBaseColor(UIColor.orangeColor(), backgroundRectangle: self.bounds) let textAttributes = [ NSForegroundColorAttributeName : UIColor.blackColor(), NSFontAttributeName : UIFont.systemFontOfSize(32.0) ] let FString: String = "Hello World" let distanceX: CGFloat = -12.0 let distanceY: CGFloat = 0.0 let centerX = CGRectGetMidX(self.bounds) let centerY = CGRectGetMidY(self.bounds) FString.drawAtPoint(CGPointMake(centerX + distanceX, centerY + distanceY), withAttributes:textAttributes) } } func drawRawBackgroundWithBaseColor(strokeColor: UIColor, backgroundRectangle:CGRect) { let lineWidth = backgroundRectangle.width/36.0 let cornerRadius = backgroundRectangle.width/16.0 // let tileRectangle = backgroundRectangle.rectByInsetting(dx: lineWidth/2.0, dy: lineWidth/2.0) let tileRectangle = backgroundRectangle.insetBy(dx: lineWidth/2.0, dy: lineWidth/2.0) // Stroke Drawing let strokePath = UIBezierPath(roundedRect:tileRectangle, cornerRadius:cornerRadius) strokeColor.setStroke() strokePath.lineWidth = lineWidth strokePath.stroke() // Draw an ellipse // let ovalPath = UIBezierPath(ovalInRect: backgroundRectangle.rectByInsetting(dx: lineWidth*1.5, dy: lineWidth*1.5)) let ovalPath = UIBezierPath(ovalInRect: backgroundRectangle.insetBy(dx: lineWidth*1.5, dy: lineWidth*1.5)) UIColor.blueColor().setStroke() ovalPath.lineWidth = lineWidth ovalPath.stroke() // let context:CGContextRef = UIGraphicsGetCurrentContext() let context:CGContextRef = UIGraphicsGetCurrentContext()! CGContextSetFillColorWithColor(context, UIColor.greenColor().CGColor) CGContextAddRect(context, CGRectMake(100.0, 100.0, 60.0, 60.0)) CGContextFillPath(context) } // Instantiate the UIView let rect = CGRect(x: 0.0, y: 0.0, width: 420.0, height: 320.0) let icon = IconView(frame: rect) icon.backgroundColor = UIColor.clearColor() icon




Updated for Swift 3.0 (Xcode 8 beta 6) syntax below

swift Plyaground 3.0     Select all
//: Playground - noun: a place where people can play #if os(iOS) import UIKit class IconView: UIView { override func draw(_ rect: CGRect) { drawRawBackgroundWithBaseColor(strokeColor: UIColor.orange, backgroundRectangle: self.bounds) let textAttributes = [ NSForegroundColorAttributeName : UIColor.black, NSFontAttributeName : UIFont.systemFont(ofSize: 32.0) ] let FString: String = "Hello World" let distanceX: CGFloat = -12.0 let distanceY: CGFloat = 0.0 let centerX = self.bounds.midX let centerY = self.bounds.midY FString.draw(at: CGPoint(x:centerX+distanceX, y:centerY+distanceY), withAttributes: textAttributes) } } func drawRawBackgroundWithBaseColor(strokeColor: UIColor, backgroundRectangle:CGRect) { let lineWidth = backgroundRectangle.width/36.0 let cornerRadius = backgroundRectangle.width/16.0 let tileRectangle = backgroundRectangle.insetBy(dx: lineWidth/2.0, dy: lineWidth/2.0) // Stroke Drawing let strokePath = UIBezierPath(roundedRect:tileRectangle, cornerRadius:cornerRadius) strokeColor.setStroke() strokePath.lineWidth = lineWidth strokePath.stroke() // Draw an ellipse let ovalPath = UIBezierPath(ovalIn: backgroundRectangle.insetBy(dx: lineWidth*1.5, dy: lineWidth*1.5)) UIColor.blue.setStroke() ovalPath.lineWidth = lineWidth ovalPath.stroke() let context:CGContext = UIGraphicsGetCurrentContext()! context.setFillColor(UIColor.green.cgColor) context.addRect(CGRect(x: 100.0, y: 100.0, width: 60.0, height: 60.0)) context.fillPath() } // Instantiate the UIView let rect = CGRect(x: 0.0, y: 0.0, width: 420.0, height: 320.0) let icon = IconView(frame: rect) icon.backgroundColor = UIColor.clear icon #endif #if os(OSX) import Cocoa class IconView: NSView { override func draw(_ rect: CGRect) { drawRawBackgroundWithBaseColor(strokeColor: NSColor.orange, backgroundRectangle: self.bounds) let textAttributes = [ NSForegroundColorAttributeName : NSColor.black, NSFontAttributeName : NSFont.systemFont(ofSize: 32.0) ] let FString: String = "Hello OSX" let distanceX: CGFloat = -12.0 let distanceY: CGFloat = 0.0 let centerX = self.bounds.midX let centerY = self.bounds.midY FString.draw(at: CGPoint(x:centerX+distanceX, y:centerY+distanceY), withAttributes: textAttributes) } } func drawRawBackgroundWithBaseColor(strokeColor: NSColor, backgroundRectangle:CGRect) { let lineWidth = backgroundRectangle.width/36.0 let cornerRadius = backgroundRectangle.width/16.0 let tileRectangle = backgroundRectangle.insetBy(dx: lineWidth/2.0, dy: lineWidth/2.0) // Stroke Drawing let strokePath = NSBezierPath(roundedRect: tileRectangle, xRadius: cornerRadius, yRadius: cornerRadius) strokeColor.setStroke() strokePath.lineWidth = lineWidth strokePath.stroke() // Draw an ellipse let ovalPath = NSBezierPath(ovalIn: backgroundRectangle.insetBy(dx: lineWidth*1.5, dy: lineWidth*1.5)) NSColor.blue.setStroke() ovalPath.lineWidth = lineWidth ovalPath.stroke() let context:CGContext = NSGraphicsContext.current()!.cgContext context.setFillColor(NSColor.green.cgColor) context.addRect(CGRect(x: 100.0, y: 100.0, width: 60.0, height: 60.0)) context.fillPath() } // Instantiate the UIView let rect = CGRect(x: 0.0, y: 0.0, width: 420.0, height: 320.0) let icon = IconView(frame: rect) extension NSView { var backgroundColor: NSColor? { get { guard let layer = self.layer, let backgroundColor = layer.backgroundColor else { return nil } return NSColor(cgColor: backgroundColor) } set { self.wantsLayer = true self.layer?.backgroundColor = newValue?.cgColor } } } icon.backgroundColor = NSColor.clear icon #endif




Friday, June 19, 2015

Static and Dynamic link for Swift Compiler

Swift compiler can be used to compile command line tool under Mac OSX. This is an example and how-to use swift compile and use the compiled module as immediate mode under Mac
http://github.com/practicalswift/Pythonic.swift
The above link has instruction to create the dynamic library libPythonic.dylib

After that, here is how to create the additional static library in swift compiler under Mac
Makefile    Select all
cd Pythonic.swift/src/
xcrun -sdk macosx swiftc -parse-as-library -module-name Pythonic -c Pythonic.swift Pythonic.*.swift
ar rvs libPythonic_static.a Pythonic*.o


And this is how to compile as command line tool and link against the static library as below
compile    Select all
mkdir -p my-pythonic-app cd my-pythonic-app/ cp ../Pythonic.swiftdoc ../Pythonic.swiftmodule ../libPythonic_static.a ../libPythonic.dylib . cat << EOF > my_pythonic_app.swift #!/usr/bin/env xcrun swift -I . import Pythonic assert(" hello ".strip() == "hello") println("This feels really.. Pythonic!") EOF xcrun swiftc -I. -L. -lPythonic_static -sdk $(xcrun --show-sdk-path --sdk macosx) my_pythonic_app.swift -o myapp1 ./myapp1
Note: If there is error __swift_FORCE_LOAD_$_swiftFoundation in linking static library try adding -Xlinker -all_load

To compile as command line tool by linking the dynamic library, use this Terminal command (please make sure that the dynamic library file libPythonic.dylib is copied to the current folder).
xcrun swiftc -I. -L. -module-link-name Pythonic -Xlinker -rpath -Xlinker "." -sdk $(xcrun --show-sdk-path --sdk macosx) my_pythonic_app.swift -o myapp2

Then compare the file size of myapp1 and myapp2 in order to verify the difference in linking methods.



Tuesday, June 16, 2015

Map, Filter, Reduce in Swift

With Swift, iOS and Mac developers have map, filter, and reduce methods on arrays. These methods can replace almost all uses of for-in-loops, and are more clear and concise.



map_filter_reduce.swift    Select all
let words = ["angry", "hungry", "aardvark", "aardwolf"] func concatenate(xs: [String]) -> String { var result: String = "" for x in xs { result += x + " " } return result.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceCharacterSet()) } concatenate(words) // "angry hungry aardvark aardwolf" println("GRR!! " + words .filter {$0.hasSuffix("gry")} .map {$0.uppercaseString} .reduce("HULK") {"\($0) \($1)"} + "!!!" ) // "GRR!! HULK ANGRY HUNGRY!!!" let numbers = [ 10000, 10303, 30913, 50000, 100000, 101039, 1000000 ] println( numbers .filter { $0 % 2 == 0 } .map { NSNumberFormatter.localizedStringFromNumber($0, numberStyle: .DecimalStyle) } .reduce("") { countElements($0) == 0 ? $1 : $0 + " " + $1 } ) // "10,000 50,000 100,000 1,000


Updated for Swift 3.0 syntax below

map_filter_reduce.swift    Select all
let words = ["angry", "hungry", "aardvark", "aardwolf"] func concatenate(_ xs: [String]) -> String { var result: String = "" for x in xs { result += x + " " } return result.trimmingCharacters(in: .whitespaces) // Xcode 8 beta 6 // return result.trimmingCharacters(in: NSCharacterSet.whitespaces()) // Xcode 8 beta 1 } concatenate(words) // "angry hungry aardvark aardwolf" print("GRR!! " + words .filter {$0.hasSuffix("gry")} .map {$0.uppercased()} .reduce("HULK") {"\($0) \($1)"} + "!!!" ) // "GRR!! HULK ANGRY HUNGRY!!!" let numbers = [ 10000, 10303, 30913, 50000, 100000, 101039, 1000000 ] print( numbers .filter { $0 % 2 == 0 } .map { NumberFormatter.localizedString(from: ($0 as NSNumber) , number: .decimal) } // Xcode 8 beta 6 // .map { NumberFormatter.localizedString(from: $0, number: .decimal) } //Xcode 8 beta 1 .reduce("") { $0.characters.count == 0 ? $1 : $0 + " " + $1 } ) // "10,000 50,000 100,000 1,000




strong, weak and unowned references in Swift

Both weak and unowned references do not create a strong hold on the referred object (a.k.a. they don't increase the retain count in order to prevent ARC from deallocating the referred object). But why two keywords? This distinction has to do with the fact that Optional types are built-in the Swift language.

A weak reference allows the possibility of it to become nil (this happens automatically when the referenced object is deallocated), therefore the type of your property must be optional - so you, as a programmer, are obligated to check it before you use it (basically the compiler forces you, as much as it can, to write safe code).

An unowned reference presumes that it will never become nil during it's lifetime. A unowned reference must be set during initialization - this means that the reference will be defined as a non-optional type that can be used safely without checks. If somehow the object being referred is deallocated, then the app will crash when the unowned reference will be used.





weak_unowned_ref.swift    Select all
// Optional Binding & chained class Person { var residence: Residence? init(residence:Residence?) { self.residence = residence } } class Residence { var address: Address? init(address:Address?) { self.address = address } } class Address { var buildingNumber: String? var streetName: String? var apartmentNumber: String? init(buildingNumber:String?, streetName: String?, apartmentNumber: String?) { self.buildingNumber = buildingNumber self.streetName = streetName self.apartmentNumber = apartmentNumber } convenience init() { self.init(buildingNumber:"", streetName:"", apartmentNumber:"") } } // Weak Reference with among objects independent lifetime class CreditCard { weak var holder: Person? } // Unowned references from owned objects with same lifetime class DebitCard { unowned let holder: Person init(holder: Person) { self.holder = holder } } let paul = Person(residence: Residence(address: Address(buildingNumber: "234", streetName: "Brooke Street", apartmentNumber: "9"))) //let paul = Person(residence: Residence(address: Address())) if let buildNumber = paul.residence?.address?.buildingNumber?.toInt() { println("paul's building number is \(buildNumber)") } if let buildNumber = DebitCard(holder: paul).holder.residence?.address?.buildingNumber?.toInt() { println("debitcard holder's building number is \(buildNumber)") } if let buildNumber = CreditCard().holder?.residence?.address?.buildingNumber?.toInt() { println("creditcard holder's building number is \(buildNumber)") } // Swift 3 syntax as below let paul = Person(residence: Residence(address: Address(buildingNumber: "234", streetName: "Brooke Street", apartmentNumber: "9"))) if let buildNumber = paul.residence?.address?.buildingNumber! { print("paul's building number is \(buildNumber)") } if let buildNumber = DebitCard(holder: paul).holder.residence?.address?.buildingNumber! { print("debitcard holder's building number is \(buildNumber)") } if let buildNumber = CreditCard().holder?.residence?.address?.buildingNumber! { print("creditcard holder's building number is \(buildNumber)") }




Optionals in Swift

Swift is designed for safety. As Apple mentioned, optionals are an example of the fact that Swift is a type safe language. Swift’s optionals provide compile-time check that would prevent some common programming errors happened at run-time. Optionals are safer and more expressive than nil pointers in Objective-C and are at the heart of many of Swift's most powerful features.





optional_binding.swift    Select all
// Optional Binding class Person { var residence: Residence? init(residence:Residence?) { self.residence = residence } } class Residence { var address: Address? init(address:Address?) { self.address = address } } class Address { var buildingNumber: String? var streetName: String? var apartmentNumber: String? init(buildingNumber:String?, streetName: String?, apartmentNumber: String?) { self.buildingNumber = buildingNumber self.streetName = streetName self.apartmentNumber = apartmentNumber } convenience init() { self.init(buildingNumber:"", streetName:"", apartmentNumber:"") } } //let paul = Person(residence: Residence(address: Address())) let paul = Person(residence: Residence(address: Address(buildingNumber: "234", streetName: "Brooke Street", apartmentNumber: "9"))) if let buildNumber = paul.residence?.address?.buildingNumber?.toInt() { println("paul's building number is \(buildNumber)") } // swift 3 syntax as below if let buildNumber = paul.residence?.address?.buildingNumber! { print("paul's building number is \(Int(buildNumber)!)") }