I don’t know where to start this. It started off as my post turkey festive season relaxation and just gets longer and longer.
I thought to myself “I’ll try and make a GUI in Swift using only emacs and the Swift REPL” - I Googled a bit (as one does these days) and found an amazing bit of code in Swift from the command line. “Jens” gave the following code example:
#!/usr/bin/swift import WebKit let application = NSApplication.sharedApplication() application.setActivationPolicy(NSApplicationActivationPolicy.Regular) let window = NSWindow(contentRect: NSMakeRect(0, 0, 960, 720), styleMask: NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask, backing: .Buffered, `defer`: false) window.center() window.title = "Minimal Swift WebKit Browser" window.makeKeyAndOrderFront(window) class WindowDelegate: NSObject, NSWindowDelegate { func windowWillClose(notification: NSNotification) { NSApplication.sharedApplication().terminate(0) } } let windowDelegate = WindowDelegate() window.delegate = windowDelegate class ApplicationDelegate: NSObject, NSApplicationDelegate { var _window: NSWindow init(window: NSWindow) { self._window = window } func applicationDidFinishLaunching(notification: NSNotification) { let webView = WebView(frame: self._window.contentView!.frame) self._window.contentView!.addSubview(webView) webView.mainFrame.loadRequest(NSURLRequest(URL: NSURL(string: "https://forums.developer.apple.com/thread/5137")!)) } } let applicationDelegate = ApplicationDelegate(window: window) application.delegate = applicationDelegate application.activateIgnoringOtherApps(true) application.run()
#!/usr/bin/swift
import WebKit
let application = NSApplication.sharedApplication()
application.setActivationPolicy(NSApplicationActivationPolicy.Regular)
let window = NSWindow(contentRect: NSMakeRect(0, 0, 960, 720),
styleMask: NSTitledWindowMask | NSClosableWindowMask |
NSMiniaturizableWindowMask,
backing: .Buffered, `defer`: false)
window.center()
window.title = "Minimal Swift WebKit Browser"
window.makeKeyAndOrderFront(window)
class WindowDelegate: NSObject, NSWindowDelegate {
func windowWillClose(notification: NSNotification) {
NSApplication.sharedApplication().terminate(0)
}
}
let windowDelegate = WindowDelegate()
window.delegate = windowDelegate
class ApplicationDelegate: NSObject, NSApplicationDelegate {
var _window: NSWindow
init(window: NSWindow) {
self._window = window
}
func applicationDidFinishLaunching(notification: NSNotification) {
let webView = WebView(frame: self._window.contentView!.frame)
self._window.contentView!.addSubview(webView)
webView.mainFrame.loadRequest(NSURLRequest(URL: NSURL(string: "https://forums.developer.apple.com/thread/5137")!))
}
}
let applicationDelegate = ApplicationDelegate(window: window)
application.delegate = applicationDelegate
application.activateIgnoringOtherApps(true)
application.run()
Which when I stuck in a file called browser.swift
and gave the shell command
`swift browser.swift' up popped the following window:
I later found very similar code with more explanation at http://practicalswift.com/.
My immediate reaction was “Golly – Swift might just be usable” and I was hooked. I’d also read that Swift was a functional language which again piqued my interest.
In the next week or so I found that Swift was certainly not a pure functional language but that it was whole lot better than Objective-C. Above all it had a REPL and I could program outside Xcode (which I hate). I can use my dear and very old friend emacs whose commands are located somewhere near the base of my spine.
How we programmed GUIs in the good ‘ol days
Once upon a time GUIs were windows containing a few buttons and some text. When you clicked the buttons the text changed. We were easily amused in the old days.
Writing a program to create a GUI was really easy. I’d write some code that looked something like this:
window = make_window(Width, Height, Title) b1 = make_button(window, X, Y, Width, Ht, Label) e1 = make_entry(window, X, Y, Width, Ht) l1 = make_label(window, X, Y, Width, Ht) b1.onclick = function X = read(e1) write(l1, X) end
I’d use my favorite text editor, stick this in a file my_gui.bas
and
say the magic words:
> basic my_gui.bas
Then the wife, kids, cats, dogs and the entire neighborhood would rejoice a GUI would appear as if by magic.
I’d hardly call this programming, all we had to do was figure out the positions and labels on the objects and type them into a computer.
As time went on tools were built to “assist” writing such programs as if it were too difficult to figure out the coordinates of where those pesky little buttons should go. Figuring out the coordinates could be done in a drag and drop interface and we could offer the user a vast library of widgets that could be used - not just buttons and text entries, but sliders and date selection widgets and goodness-knows-what-they-do selectors.
The languages to program GUIs became more complicated, and the number of functions available to manipulate the widgets became so large that nobody could ever remember them all.
So we made integrated IDEs that hid thousands of commands from the users and which offered hundred of widgets and could be used to build amazing shiny things.
But the tools became larger and larger to the point of unusability and the simple ways of making a GUI which a beginner programmer could knock up in a few minutes were lost.
I’m an old-style programmer. I like to understand every line of code I write. I like to write my code in files and study the results.
This is my attempt to make an old-style GUI in Swift.
All the code for the GUI must be in a single Swift file which I’ll launch from the terminal. I’ll use only the Apple Swift compiler, Emacs and Make.
I’m a beginner at Swift and Cocoa - I’ve asked a number of questions in the article and I hope that some of you who read this can provide answers to these questions. All the source is on-line and so you can send me pull requests or add comments at the end of the article.
Another goal is to shorten and/or clarify the programs. So if you can remove a line of code which you feel is irrelevant, or improve the explanation please tell me.
Brevity of expression is not a primary goal - since I’d favor slightly more verbose code if it is clearer than extremely terse code. The goal is clear obviously correct code and code patterns that are easy to scale and reproduce.
To help you navigate you can jump straight to the code or read the entire article from start to finish:
Part 1 - primitive functions
- experiment 0 - Not really a window
- experiment 1 - A minimal window
- experiment 2 - A window with specific size and a title
- experiment 3 - A window with a button
- experiment 4 - A window with a text field
- experiment 5 - Connecting the button to a text field
- experiment 6 - A window with an image
Part 2 - Abstractions
Part 3 - Philosophy
The programs have been tested on OS X Yosemite version 10.10.5 with Xcode version 7.2 and Swift version 2.1.
Each program is in a single file
called experiment1.swift
, experiment2.swift
and so on.
The source can be found here.
Running and compiling the examples
To run the an example in a terminal give the command
swift experiment<K>.swift
To compile example<K>
give the command:
switftc -o experiment<K> experiment<K>.swift
This will generate an executable called experiment<K>
Part 1 - Primitive Functions
Experiment 0 - How not to make a window
If we start Xcode, do File->New->Project
and select Coco Application
then set the language to Swift
then Xcode will create a file called
ApplicationDelegate.swift
with the following content:
// // AppDelegate.swift // Project // // Created by joseph armstrong on 28/12/15. // Copyright © 2015 joseph armstrong. All rights reserved. // import Cocoa @NSApplicationMain class AppDelegate: NSObject, NSApplicationDelegate { @IBOutlet weak var window: NSWindow! func applicationDidFinishLaunching(aNotification: NSNotification) { // Insert code here to initialize your application } func applicationWillTerminate(aNotification: NSNotification) { // Insert code here to tear down your application } }
This file cannot be run outside Xcode - here’s what happens if we try to run this directly in a terminal:
swift AppDelegate.swift
AppDelegate.swift:11:1: error: 'NSApplicationMain' attribute cannot be used in a module that contains top-level code
@NSApplicationMain
^
AppDelegate.swift:1:1: note: top-level code defined in this source file
//
^
So this doesn’t work - but after a little Googling and some small edits we can modify this so that we can create a window in the shell, this is show in the next section.
Experiment 1 - A simple window
This window is created with the following code - which is
derived from AppDelegate.swift
.
// experiment1.swift // run with: // $ swift experiment1.swift import Cocoa class AppDelegate: NSObject, NSApplicationDelegate { let window = NSWindow() func applicationDidFinishLaunching(aNotification: NSNotification) { window.makeKeyAndOrderFront(window) window.level = 1 } } let app = NSApplication.sharedApplication() let controller = AppDelegate() app.delegate = controller app.run()
To run the program store the above in a file experiment1.swift
and run
the program in a terminal with the following command:
$ swift experiment1.swift
Experiment 2 - A window with a title and specific size
Now I’ll make a larger window and add a title:
Here I’ve make the window a specific size a title and some controls to the title bar:
// experiment2.swift // run with: // $ swift experiment2.swift import Cocoa class AppDelegate: NSObject, NSApplicationDelegate { let window = NSWindow() func applicationDidFinishLaunching(aNotification: NSNotification) { window.setContentSize(NSSize(width:600, height:200)) window.styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask window.opaque = false window.center(); window.title = "Experiment 2" window.makeKeyAndOrderFront(window) window.level = 1 } } let app = NSApplication.sharedApplication() let controller = AppDelegate() app.delegate = controller app.run()
Adding controls
Now we can make a simple window. The next step is to add some controls. I’ve added one control in each experiment.
Experiment 3 - A window with a button
Here’s a window with a button in it - note that nothing happens when we click the button - in experiment 5 I’ll add a click action to the button.
The code is as follows:
// experiment3.swift // run with: // $ swift experiment3.swift import Cocoa class AppDelegate: NSObject, NSApplicationDelegate { let window = NSWindow() func applicationDidFinishLaunching(aNotification: NSNotification) { window.setContentSize(NSSize(width:600, height:200)) window.styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask window.opaque = false window.center(); window.title = "Experiment 3" let button = NSButton(frame: NSMakeRect(20, 100, 180, 30)) button.bezelStyle = .ThickSquareBezelStyle button.title = "Click Me" button.target = NSApp window.contentView!.addSubview(button) window.makeKeyAndOrderFront(window) window.level = 1 } } let app = NSApplication.sharedApplication() let controller = AppDelegate() app.delegate = controller app.run()
Exercise: Try Googling ThickSquareBezelStyle
you should be able to
find all the available button styles. Try making small edits to the
program to see what happens.
experiment 4 - A window with a text field
This is actually a TextView
where I’ve set the background color to the window
background color.
Exercise: Make a better or alternative version.
// experiment4.swift // run with: // $ swift experiment4.swift import Cocoa class AppDelegate: NSObject, NSApplicationDelegate { let window = NSWindow() func applicationDidFinishLaunching(aNotification: NSNotification) { window.setContentSize(NSSize(width:600, height:200)) window.styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask window.opaque = false window.center(); window.title = "Experiment 4" let text = NSTextView(frame: NSMakeRect(20, 150, 180, 30)) text.string = "Some Text" text.editable = false text.backgroundColor = window.backgroundColor text.selectable = false window.contentView!.addSubview(text) window.makeKeyAndOrderFront(window) window.level = 1 } } let app = NSApplication.sharedApplication() let controller = AppDelegate() app.delegate = controller app.run()
Experiment 5 - Connecting the button to the text field
// experiment5.swift // run with: // $ swift experiment5.swift import Cocoa class AppDelegate: NSObject, NSApplicationDelegate { var text = NSTextView(frame: NSMakeRect(20, 150, 180, 30)) let window = NSWindow() @IBAction func myAction(sender: AnyObject) { text.string = "Wow I've been clicked" } func applicationDidFinishLaunching(aNotification: NSNotification) { window.setContentSize(NSSize(width:600, height:200)) window.styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask window.opaque = false window.center(); window.title = "Experiment 5" let button = NSButton(frame: NSMakeRect(20, 100, 280, 30)) button.bezelStyle = .ThickSquareBezelStyle button.title = "Click me and the text will change" button.target = self; button.action = "myAction:" // Note the colon window.contentView!.addSubview(button) text.string = "Some Text" text.editable = false text.backgroundColor = window.backgroundColor text.selectable = false window.contentView!.addSubview(text) window.makeKeyAndOrderFront(window) window.level = 1 } } let app = NSApplication.sharedApplication() let controller = AppDelegate() app.delegate = controller app.run()
This code is a bit of a mess, it had to be carefully constructed so
that the variable text
was defined before the button callback
function myAction
(since text
is referred to in the body of the
myAction
function).
This is a tad tricky and would indeed be impossible if the relationships
between the controls could not be ordered (for example, it would be
impossible to create two buttons b1
and b2
which when clicked
change the labels of the “other” button) - I’ll solve this problem
later by allowing the click action on a button to be defined after
the all the controls have been created.
Experiment 6 - A window with an image
The image is from Sydney Padua’s most excellent book The Thrilling Adventures of Lovelace and Babbage
// experiment6.swift // run with: // $ swift experiment6.swift import Cocoa class AppDelegate: NSObject, NSApplicationDelegate { let window = NSWindow() func applicationDidFinishLaunching(aNotification: NSNotification) { window.setContentSize(NSSize(width:500, height:260)) window.styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask window.opaque = false window.center(); window.title = "Experiment 6" // load and display an image let path = "../images/ada.png" let img = NSImage(contentsOfFile: path)! let imgView = NSImageView(frame: NSMakeRect(10, 10, 480, 240)) imgView.image = img window.contentView!.addSubview(imgView) window.makeKeyAndOrderFront(window) window.level = 1 } } let app = NSApplication.sharedApplication() let controller = AppDelegate() app.delegate = controller app.run()
Part 2 - Abstractions
The goal of this part is to make a simple set of functions that hides most of the detail of making windows and adding controls to them.
The end result is going to be a program fragment that looks like this:
let entry1 = make_entry(window, (200, 80, 180, 30), "1") let text1 = make_text(window, (20, 80, 180, 30), "Hello from me") let text2 = make_text(window, (20, 120, 180, 30), "Another field") let button1 = make_button(window, (120, 40, 80, 30), "Click") // make a click function let f1 = {() -> Bool in text1.string = "Callback worked" print(entry1.textStorage!.string) text2.string = entry1.textStorage!.string return true} // button1.onclick = f1
All the details of making the controls will be hidden in functions
like make_text
, make_button
and so “wiring up” the controls will
be done by hooking callback functions on the buttons.
To do this needs some trickery, so in the sections that follow I’ll first explain the techniques and then refactor the code in the Part 1 into a form that fits my purpose.
Firt I’ll look at parameter passing in Swift.
Parameter naming gobbledygook
Swift parameter passing is totally unobvious.
I had expected that the “obvious” way to declare and call a function would be something like this:
// funcs1.swift func add(x:Int, y:Int, z:Int) -> Int { return x+y+z } print("add=", add(1,2,3))
But oh dear:
swift funcs1.swift funcs1.swift:5:18: error: missing argument labels 'y:z:' in call print("add=", add(1,2,3)) ^ y: z:
A little research revealed that the correct way to call
add
was to use the totally unobvious syntax:
// funcs2.swift func add(x:Int, y:Int, z:Int) -> Int { return x+y+z } print("add =", add(1,y:2,z:3))
Inconsistent moi? - the first parameter name is omitted. All the other parameters must be present in the same order as the definition. Great shades of objective C!
This horrible syntax works:
> swift funcs2.swift add = 6
Better though again unobvious is to prefix each argument in the function definition with
underscore _
like this:
// funcs3.swift func add(x:Int, _ y:Int, _ z:Int) -> Int { return x+y+z } print("add=", add(1,2,3))
Now at least we can call the function in the same way as we’d do in just about every other programming language under the sun.
A button callback function
To make a callback function for a button we have to step back and then understand how closures work, and then we can make a callback function.
I’ll start by defining a simple class with an instance variable:
class Demo { var firstname: String = "fred" } let x = Demo() print(x.firstname) x.firstname = "joe" print(x.firstname)
This should look familiar to you if you’ve programmed in an OO language.
Running this we see the following:
> swift classes1.swift fred joe
Now I’ll do the same things with a functional argument:
class Demo { var call: () -> Bool = {() -> Bool in true} } let x = Demo() print(x.call()) var i = 10 var f = {() -> Bool in print("hello I'm a callback and i =", i); return true} x.call = f print(x.call()) i = 20 print(x.call())
Running this:
true hello I'm a callback and i = 10 true hello I'm a callback and i = 20 true
Which to my mind is horrendous. The closure
f
does not capture the value ofi
at the time whenf
is defined, changingi
afterf
was defined make nonsense of the idea of a closure.
If we are extremely careful we can use this mechanism to add a callback facility to
buttons. We’ll do this and make a custom class, by inheriting the properties
of NSButton
and adding our own callback routine:
class MyButton: NSButton { var onclick: () -> Bool = {() -> Bool in true} func myclick(sender: AnyObject) { self.onclick() } }
and to make a button I call make_button
func make_button(window: NSWindow, _ size:(x:Int, y:Int, width:Int, ht:Int), _ title:String ) -> MyButton { let button = MyButton() button.frame = NSMakeRect(CGFloat(size.x), CGFloat(size.y), CGFloat(size.width), CGFloat(size.ht)) button.title = title button.bezelStyle = .ThickSquareBezelStyle button.target = button button.action = "myclick:" window.contentView!.addSubview(button) return button }
Now we can make some objects and add an onclick
callback to the buttons (just like
jquery) - the pseudo code to do this will look something like this:
... create a window ... text1 = make_text(window, Size, Text) entry1 = make_entry(window, Size, Default) button1 = make_button(window, Size, Text) F = ... a function involving text1, entry1, ... etc. button1.onclick = F
Putting it all together
Now let’s put it all together:
The code is rather long - but I was able to pull out most of the mess into simple reusable functionbs.
The code to create the window and add controls was easy and Xcode was not used.
// combined1.swift // run with: // $ swift combined1.swift import Cocoa class MyButton: NSButton { var onclick: () -> Bool = {() -> Bool in true} func myclick(sender: AnyObject) { self.onclick() } } func make_button(window: NSWindow, _ size:(x:Int, y:Int, width:Int, ht:Int), _ title:String ) -> MyButton { let button = MyButton() button.frame = NSMakeRect(CGFloat(size.x), CGFloat(size.y), CGFloat(size.width), CGFloat(size.ht)) button.title = title button.bezelStyle = .ThickSquareBezelStyle button.target = button button.action = "myclick:" window.contentView!.addSubview(button) return button } func make_entry(window:NSWindow, _ size:(x:Int, y:Int, width:Int, ht:Int), _ str: String ) -> NSTextView { let text = NSTextView(frame: NSMakeRect(10, 140, 40, 20)) text.frame = NSMakeRect(CGFloat(size.x), CGFloat(size.y), CGFloat(size.width), CGFloat(size.ht)) text.string = str text.editable = true text.selectable = true window.contentView!.addSubview(text) return text } func make_text(window:NSWindow, _ size:(x:Int, y:Int, width:Int, ht:Int), _ str: String ) -> NSTextView { let text = NSTextView(frame: NSMakeRect(10, 140, 40, 20)) text.frame = NSMakeRect(CGFloat(size.x), CGFloat(size.y), CGFloat(size.width), CGFloat(size.ht)) text.string = str text.editable = false text.backgroundColor = window.backgroundColor text.selectable = false window.contentView!.addSubview(text) return text } func set_window_args(window:NSWindow, _ w:Int, _ h:Int, _ title:String) -> Void { window.setContentSize(NSSize(width:w, height:h)) window.styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask window.opaque = false window.center(); window.title = title } class AppDelegate: NSObject, NSApplicationDelegate { let window = NSWindow() func applicationDidFinishLaunching(aNotification: NSNotification) { set_window_args(window, 400, 200, "My title") let entry1 = make_entry(window, (200, 80, 180, 30), "1") let text1 = make_text(window, (20, 80, 180, 30), "Hello from me") let text2 = make_text(window, (20, 120, 180, 30), "Another field") let button1 = make_button(window, (120, 40, 80, 30), "Click") // make a click function let f1 = {() -> Bool in text1.string = "Callback worked" print(entry1.textStorage!.string) text2.string = entry1.textStorage!.string return true} // button1.onclick = f1 window.makeKeyAndOrderFront(window) window.level = 1 } } let app = NSApplication.sharedApplication() app.setActivationPolicy(.Regular) let controller = AppDelegate() app.delegate = controller app.run()
Open Problems
I had hoped to write:
window = create_window(400, 200)
to create a 400
by 200
window:
To my mind this could be achieved with the following function:
func make_window(w:Int, _ h:Int) -> NSWindow { let window = NSWindow() window.setContentSize(NSSize(width:w, height:h)) window.styleMask = NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask window.opaque = false window.center(); window.title = "Experiment 5" return window }
But this for some weird reason does not work. So I’ve split the code into two parts:
window = NSWindow()
in the initialization section of the AppDelegate
class, and a function
set_window_args
in the the applicationDidFinishLaunching
method.
Swift as a functional language
The bad
- Verbose syntax - types are declared rather than inferred
- Mutable data types
- Weird mix of Classes, Structs and functions
- No concurrency model
The good
- It has a REPL
- I can write apps outside XCode
I like the syntax of exceptions if the function X can raise an exception then one must qualify call with ! ? or use an explicit try syntax
In Erlang term the use of ! and ? is easy to explain
Imagine an Erlang function f(X) that returns {ok, Val} when Val = f(X)
or
otherwise {eror, Why}
if the function could not compute a value for some argument X
The Swift compiler convention if implemented in Erlang would require f(X)
to be
evaluated within a catch
statement, like this:
case (catch f(X)) of
{ok, Val} ->
...;
{error, Why} ->
...
end
otherwise an error would be indicted.
If we were absolutely sure that {ok, Val}
would be returned we’d write:
Val = f!(X)
Which is equivalent to the Erlang
{ok, Val} = f(X)
The ? convention unwraps {ok, Val}
into Val
or {error, Why}
into nil
in Swift.
Comments on Swift
I’ve been programming Swift for a couple of weeks now. Do I like it?
Swift is widely marketed as a functional language - so it’s interesting to see how well it shapes up as a functional programming language - or at least to see how compares to other FPLs that I am familiar with.
Sequential FPLs gain a lot of power from the mechanisms they offer. The offer (in varying degrees) type systems that (claim to) prevent (some run-time) errors. Pattern matching syntaxes make the programs very short. Immutable data structures simplifies reasoning about the programming and debugging. Higher order functions add to power of the language be treating functions as first class data.
Where Swift shines it is in the integratiion with the underlying Objective C frameworks on the Mac. To this extent Swift programming is a much more attractive proposition than programming in C or Objective-C but but this is not because Swift is a good language rather that C and objective-C are bad languages for writing user-space application in.
The C family of languages (C, C++, Objective-C) are fine for writing operating system but not for writing the majority of user-space applications - here things like Python or visual-basic are far better.
Swift is a good replacement for contexts in which Objective-C would be used.
If you’re coming form Erlang/Haskell world you’ll think Swift is
verbose and a bit of a mess
but if you’re coming from Objective-C
you’ll think “Swift is concise and elegant”
In Swift I really miss pattern matching and I dislike having to excessivly declare types.
The lack of a decent concurrency model in Cocoa and Objective-C is reflected in the Swift code - which although it works is pretty horrible.
Textual vs Interactive interfaces
I’ve said that I don’t like Xcode so I’ve added some reasons why.
Two common ways to create programs are:
1) We create a text file using a text editor.
2) We create a program by clicking on buttons and dragging objects in an IDE (Integrated Development Environment) (for example, Xcode).
In the first method we don’t usually have to tell the user how to create a text file with given content. It suffices to give a listing of the file and assume that the user can create the file using an editor of their choice. It is totally irrelevant how the file is created the only thing that matters is that the content of the file is correct.
In order to understand the program only the content of the file must be understood. We can examine it line by line, asking if we understand what the lines of code mean.
Using an IDE is horribly different - describing how to interact with a an IDE is very difficulty to do in text. Usually we have to show how to do this typically with a YouTube video, or in a mixture of text and images.
An excellent example of the difficulty of describing how to do something is can be found in Notes from a Swift Developer – in this example the author uses a mixture of text and screenshots to describe how to build an application. Text alone does not work.
The application described in the link above has a simple layout which could be easily described in text (for example as an html table)
Unfortunately when we try to reproduce what we’ve seen in a video or follow a description that is a mixture of text and images, we find that the description almost invariably describes a different version of the IDE than the one we have available.
Textual descriptions of the form “and now click on the doggle control icon” are pretty useless if you haven’t got a clue what the doggle control icon looks like.
Worse - when the design process in an interface builder is finished - all the correct buttons have been clicked the resulting “state” of the system (ie the program) is not available in a textual format so we cannot ask, line-by-line what the individual statement in the description mean.
As you might gather - I hate IDEs like Xcode and Eclipse - I like to totally understand every line of code I wrote - my method of understanding code is always the same and independent of language. Find an example program that works then reduce lines until I can reduce no more making a minimal example that works - then understand every line.
This is a slow process - but in the long run faster than clicking at random in a IDE until your program works or Googling like crazy to see if somebody else has a canned solution to your problem.
I get the impression that developers think that developing in a IDE is
somehow “quicker” than developing with no such tools. As far as I can see this
is false. Once I have a working program in a given directory structure
I can make a clone of this in a single terminal command (cp -R ...
) and then
I’m off in my trusty editor.
Following instructions like
- enter this … into a file called …
- type the command … into the shell
are easy to obey and pass the “telephone test” (ie can we describe exactly what to do over a telephone) - no images or videos are needed to “show” the users what to do.
Once upon a time we could describe how to do something using text only. Then we used text and images. Now it needs videos.
Asking questions about text was easy - “what did you mean in paragraph 4” now we’d have to ask “what did you do 41.6-41.8 seconds into your video” watching somebody doing something in Xcode 200.7 in a video and preforming slow motion playbacks of selected sections is not my idea of programming.
References
I’ve found several documents which helped me - none of them solves the problem I’m try to solve but they have all provided clues to the solution:
- http://czak.pl/2015/09/23/single-file-cocoa-app-with-swift.html
- https://github.com/Eonil/CocoaProgrammaticHowtoCollection
- https://forums.developer.apple.com/thread/5137
- http://stackoverflow.com/questions/26609778/nsopenpanel-in-swift-how-to-open
- https://objectivec2swift.com/#/converter/code
- http://practicalswift.com/
- https://github.com/tylergaw/js-osx-app-examples
- http://www.raywenderlich.com/82046/introduction-to-os-x-tutorial-core-controls-and-swift-part-1
- http://commandlinefanatic.com/cgi-bin/showarticle.cgi?article=art024
- http://mediautopia.weebly.com/swift-1-intro.html
- http://dev.iachieved.it/iachievedit/using-swift-as-a-scripting-language/
- http://commandlinefanatic.com/cgi-bin/showarticle.cgi?article=art024
- http://www.knowstack.com/swift-programming-an-introduction/
Help and tips wanted
Does anynody know:
- How can I create two or more windows? - I seem to only be able to create a single window
- How can I make a socket client?
- How can I make a socket server?
Solutions should be single Swift files that can be run from the terminal.
The future
Articles like this are never finished only started …