How to crash #Xcode 11: New -> Playground -> UIKit -> Single View. Run.
— @KenHatesSoftwar Aug. 19, 2020
I just remembered why I never use Xcode playgrounds.
Do Playgrounds no longer work at all in #XCode 11.0 for anyone else? They just get stuck on "Running..." & never execute any code. Even a default playground with only the default code & a "print(str)" command just hangs there doing nothing. #coding @Apple @AppleSupport #Xcode11
— @BioAlex Sep. 27, 2019
Now I get why Apple requires students to submit a playground that can be experienced in at most 3 minutes to apply for a WWDC scholarship… The reviewers have to spend the remaining 57 minutes trying to get Xcode to run it successfully 🤦
— @BalestraPatrick Mar. 24, 2019
Never ever praise an Xcode playground. It’s bound to crash 10 seconds later. #Swift #xcode #ios
— @YOADAPPS Dec. 20, 2018
Because of Xcode Swift Playground instability while running even the simplest of Swift code, this Swift code runner was implemented with Pharo. It brings the benefits of greatly increased stability for trying short pieces of Swift code and working with that output in Pharo's stable, modern, live development environment.
Interact with Swift on Pharo.
Run Swift with the Pharo Swift Playground, interoperate with Pharo, inspect output and Swift ASTs.
- Pharo 8 reference platform.
- Requires:
- macOS (tested with 11.0.1) or GNU/Linux (tested with Ubuntu 14.04, 64 bit).
- Swift tools (see Installation below).
- Swift Playground:
Print it
. - Swift Playground: Syntax highlighting and code completion.
- Swift Playground: Open/save files.
- Swift response string to Pharo object deserialization.
- Move documentation to the wiki.
- Support the latest Pharo release.
- Support Spec2.
-
Install and setup the Swift tools for your environment:
- macOS: Install the Command Line Tools for Xcode.
- GNU/Linux: Install Swift from swift.org.
-
In a Playground, Do it:
Metacello new repository: 'github://brackendev/SwiftPlayground-Pharo:v1.0.2/src'; baseline: 'SwiftPlayground'; onConflict: [ :ex | ex useIncoming ]; onUpgrade: [ :ex | ex useIncoming ]; onDowngrade: [ :ex | ex useLoaded ]; load.
Swift code can be run in the Swift Playground and inline within Pharo code.
Write, compile, run, and inspect output of Swift code via the Swift Playground (accessible via the Tools menu).
-
Do it
– Run the selected Swift code -
Inspect it
– Run the selected Swift code and inspect it -
Print it
– Run the selected Swift code and print it (TODO) -
Inspect AST
– Returns the Swift AST for the selected Swift code. For example,print("Hello, World!")
returns:(import_decl range=[Swift:1:1 - line:1:8] 'Foundation') (top_level_code_decl range=[Swift:2:1 - line:2:22] (brace_stmt range=[Swift:2:1 - line:2:22] (call_expr type='<null>' arg_labels=_: (unresolved_decl_ref_expr type='<null>' name=print function_ref=unapplied) (paren_expr type='<null>' (string_literal_expr type='<null>' encoding=utf8 value="Hello, World!" builtin_initializer=**NULL** initializer=**NULL**)))))
Outside of the Swift Playground, Swift code can be executed within Pharo code by using the runSwift
string class extension. For example:
Pharo class extensions can be used to run and view the ASTs of Swift code with the runSwift
and swiftAST
class extensions:
Returns Swift output as a string. Use the print function within the Swift code to create output. For example:
swiftString := 'The five boxing wizards jump quickly' asLowercase asSwiftString.
('let (lowercased, alphabet) = (Set(', swiftString, '), "abcdefghijklmnopqrstuvwxyz")
print("\(!alphabet.contains { !lowercased.contains($0) })")') runSwift.
returns 'true'
.
Tip: Simple Swift code does not need the print function. For example:
'Array("ABCDE")' runSwift.
returns '["A", "B", "C", "D", "E"]'
, and:
swiftArray := #(1 2 3 4 5) asSwiftArray.
(swiftArray, '.map{$0 * $0}.reduce(0, +)') runSwift.
returns '55'
.
Returns the Swift AST of Swift code.
Pharo class extensions can be used as quick helpers to serialize Pharo objects to Swift code (as Pharo strings). For example, 'Hello, World!' asSwiftString
returns '"Hello, World!"'
.
These are useful in concatenating Pharo strings of Swift code. For example, in the code below, notice the usage of sentence
and asSwiftString
and how they're used in the swiftCode
string concatenation:
sentence := 'The five boxing wizards jump quickly' asLowercase asSwiftString.
swiftCode := ('
// Determine a pangram
let (sentenceSet, alphabet) = (Set(', sentence, '), "abcdefghijklmnopqrstuvwxyz")
print(!alphabet.contains {
!sentenceSet.contains($0)
})
').
swiftCode runSwift.
returns 'true'
.
Currently, the following class extensions have been implemented. The examples are also availabe via the SPExamples
object.
Currently only handles one depth of booleans, numbers, and strings. Example:
#(1 'A' 2 true 3 false) asSwiftArray.
returns '[1,"A",2,true,3,false]'
.
Example:
true asSwiftBoolean.
returns 'true'
.
Currently only handles one depth of booleans, numbers, and strings. Example:
(Dictionary newFrom: {(1 -> 2). ('A' -> 3). (4 -> 'B'). (5 -> true).
(false -> 'C'). ('D' -> 'E')}) asSwiftDictionary.
returns '[1:2,"A":3,4:"B",5:true,"D":"E",false:"C"]'
.
Example:
'Hello, World!' asSwiftString.
returns '"Hello, World!"'
.
Pharo class extensions can be used as quick helpers to deserialize Swift code (as Pharo strings) to better Pharo objects. These are useful to more easily handling Swift code ouput. For example, 'true' asPharoBoolean
returns true
.
Currently, the following extension methods have been implemented. The examples are also availabe via the SPExamples
object.
Example:
'1 == 1' runSwift asPharoBoolean.
returns true
.
An example using asSwiftString
, runSwift
, and asPharoBoolean
:
sentence := 'The five boxing wizards jump quickly' asLowercase asSwiftString.
swiftCode := ('
// Determine a pangram
let (sentenceSet, alphabet) = (Set(', sentence, '), "abcdefghijklmnopqrstuvwxyz")
print(!alphabet.contains {
!sentenceSet.contains($0)
})
').
swiftCode runSwift asPharoBoolean.
returns true
.
The Apple Foundation framework is imported into Swift code automatically. To use other Apple frameworks with Swift code, use the Swift import
directive.
To prevent asynchronous Swift code from exiting too early, use the Swift dispatchMain() function to never return and use the Swift exit() function to exit where appropriate.
For example, in the Swift code below, a Swift URLRequest network request session is started and dispatchMain()
is called so the program does not prematurely exit. In the session response closure, exit(0)
is then called to exit the program.
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
var url = URL(string: "https://www.gravatar.com/4f64c9f81bb0d4ee969aaf7b4a5a6f40.json")
var request = URLRequest(url: url!)
request.httpMethod = "GET"
let task = session.dataTask(with: request, completionHandler: { data, response, error in
if let uError = error {
print(uError.localizedDescription) // Returns error string
} else if let uData = data, let string = String(data: uData, encoding: String.Encoding.utf8) {
print(string) // Returns response string
}
exit(0) // Exit after asynchronous work is complete
})
task.resume()
session.finishTasksAndInvalidate()
dispatchMain() // Prevent premature exit
This project makes use of the following third-party libraries and utilities:
Bracken Spencer
SwiftPlayground-Pharo is released under the MIT license. See the LICENSE file for more info.
- @pharoproject [Twitter]
- @swiftlang [Twitter]
- pharo.org
- swift.org