I’m using the following to log some function calls.
func functionWasCalled(file: String = #file, function: String = #function) {
print("Function \(function) of file \(file) was called.")
}
When its caller is a method, I’d like functionWasCalled to also print the name of the class to which the caller belongs. Even when that method is static. And I don’t want to pass any explicit argument to functionWasCalled. What can I do?
I don't believe what you're specifically asking for is possible. There's no way I know of to evaluate something in your caller's context implicitly, except the provided #-literals.
That said, if you will change your syntax slightly, you can get the effect you want.
public class Logger {
public let caller: String
public init(for caller: Any) {
self.caller = "\(type(of: caller))"
}
public func info(_ message: String, file: String = #file, line: Int = #line, function: String = #function) {
print("Function \(function) of \(caller) in file \(file) was called.")
}
}
Now, in objects that use the logger, they just need to create their own with a consistent name like log. Make sure your Logger is stateless, so it's ok that they get created on demand.
class MyLoggingThing {
var log: Logger { Logger(for: self) }
func doSomething() {
log.info("Let's do this")
}
}
// Function doSomething() of MyLoggingThing in file MyPlayground.playground was called.
You can make this a little nicer with an extension, and handle static methods:
protocol Logging {}
extension Logging {
static var log: Logger { Logger(for: self) }
var log: Logger { Logger(for: self) }
}
class MyLoggingThing: Logging {
static func doSomethingStatic() {
log.info("Even static")
}
func doSomething() {
log.info("Let's do this")
}
}
Note that static methods will show the type as MyLoggingThing.Type. That's good or bad, depending on what you want. If you don't like the extra .Type, you can add an extra Logger.init like this:
public init(for staticCaller: Any.Type) {
self.caller = "\(staticCaller)"
}
That will cause types to be evaluated as themselves rather than as their metatypes.
If your logger is stateful or has a central configuration, or other situation where lots of loggers might be a problem, you should split apart the stateful "engine" part from this front-end. You can also make log a lazy var or otherwise initialize it in init when self is available.
In my personal Logging module, I also have a global "root" Logger called Log (with a leading capital). That makes it easier for functions that might not want to name themselves (such as top level functions or closures).
Try the following:
String(describing: self)
Like here:
class Foo {
func test () {
print(String(describing: self))
}
}
let f = Foo()
f.test()
Output:
Foo
For a class name, you can use self.classForCoder and for the filename, you can also use #fileID
func functionWasCalled(file: String = #file, function: String = #function, fileID: String = #fileID, callClass: AnyObject?) {
print("Function \(function) of file \(file) was called.")
print("File id", fileID)
print("Class is - ", callClass?.classForCoder ?? self.classForCoder)
}
Related
I would like to iterate in my code over the Swift AST like this, finding the struct keyword.
private func recursion(node: Syntax) -> String {
for child in node.children {
if let tokenKind = (child as? TokenSyntax)?.tokenKind, tokenKind == .structKeyword {
// if type(of: child) == StructDeclSyntax.self {
print ("yeah")
}
recursion(node: child)
}
}
let input = """
public struct cmd_deleteEdge<E: VEdge> : EdgeCommand {
public var keyEquivalent = KeyEquivalent.none
public let title = "Delete Edge"
public let id = "deleteEdge"
public let toolTip = "Delete selected Edge"
public let icon = Icon.delete
//receivers
public let edge: E
public init(edge: E) {
self.edge = edge
}
public func execute() throws -> ActionResult {
edge.deleteYourself()
return .success("deleted edge")
}
}
"""
public func convert(structText: String) throws -> String {
let sourceFile = try SyntaxParser.parse(source: structText)
let result = recursion(node: Syntax(sourceFile))
return result
}
try convert(structText: input)
It just simply doesn't work, I never reach the "Yeah" (which means I cannot do anything useful during the recursion).
I find this library very confusing. Would anyone have a good UML diagram explaining how it really works?
Before you tell me, yes I know I could use a Visitor, but I want to understand how it works by myself.
You can use SyntaxProtocol for iterating all items in AST and then use its _syntaxNode public property to make a target syntax, e.g.:
import SwiftSyntax
import SwiftSyntaxParser
func recursion(node: SyntaxProtocol) {
if let decl = StructDeclSyntax(node._syntaxNode) {
print(decl.identifier)
}
node.children.forEach { recursion(node: $0) }
}
let code = """
struct A {}
class Some {
struct B {}
}
func foo() {
struct C {}
}
"""
let sourceFile = try SyntaxParser.parse(source: code)
recursion(node: sourceFile)
Outputs:
A
B
C
NOTE: It is not recommended to retrieve _syntaxNode property directly and you can use Syntax(fromProtocol: node) instead.
SyntaxVisitor
But the best approach is using Visitor pattern with SyntaxVisitor class to avoid recursion issues for large and complex files:
class Visitor: SyntaxVisitor {
var structs = [StructDeclSyntax]()
init(source: String) throws {
super.init()
let sourceFile = try SyntaxParser.parse(source: source)
walk(sourceFile)
}
// MARK: - SyntaxVisitor
override func visit(_ node: StructDeclSyntax) -> SyntaxVisitorContinueKind {
structs.append(node)
return .skipChildren
}
}
let visitor = try Visitor(source: code)
visitor.structs.forEach {
print($0.identifier)
}
I found it after trial & error and reviewing of the API.
private func recursion(node: Syntax) -> String {
for child in node.children {
if let token = TokenSyntax(child), token.tokenKind == .structKeyword {
print ("yeah")
}
recursion(node: child)
}
return node.description
}
This approach to identify the kind of the token works, and the print statement will be reached. Again, I do wonder how the class diagram for SwiftSyntax would look like.
I need a single function to resolve different dependencies in a class.
But there is a compilation error appears.
Is it possible to create that generic function or there are some compiler constraints in Swift?
import Foundation
protocol Client: class {
var description: String { get }
}
final class ImportantPerson : Client {
var description: String {
return "Important person"
}
}
protocol Order: class {
var description: String { get }
}
final class LastOrder : Order {
var description: String {
return "Last order"
}
}
final class A {
fileprivate func resolveDependency<T>() -> T {
return resolve() as T
}
private func resolve() -> Client {
return ImportantPerson()
}
private func resolve() -> Order {
return LastOrder()
}
}
let a = A()
let client: Client = a.resolveDependency()
let order: Order = a.resolveDependency()
print("Client: \(client.description)")
print("Order: \(order.description)")
EDIT: This question is not about if Swift allows to create two functions that differs only by return type. I know it's possible. I think there are some artificial constraints in the compiler but not in the fundamental logic that should allow to infer needed type from a context.
Let's put yourself into the compiler's shoes. Imagine that this was not causing an error and you had one signature with different outputs.
Whenever you call resolveDependency<T>() -> T, the compiler will return you a type T which is an instance conforming to a protocol in your case.
In your code you call this method with different instances conforming to the same protocol. At that stage the compiler has no idea about this. All it knows is that you have passed an instance of T and it needs to give you a result in shape of T
There is no problem until this point. As soon as you execute
return resolve() as! T
The compiler will be confused. I have a T but I don't know which resolve() I will call... All I know is that I have a T. How would I know if this is an Order or a Client ?
In order to prevent such confusions we have compiler-time errors. At least this is the case for Swift. (I don't know how this works in other languages)
You need to define different methods with different signatures and cast your type accordingly to get a similar result
fileprivate func resolveDependency<T>() -> T {
// check if this is an Order
resolveForOrder()
// check if this is a Client
resolveForClient()
}
private func resolveForOrder() -> Order {
return LastOrder()
}
private func resolveForClient() -> Client {
return ImportantPerson()
}
This is like trying to fix a space shuttle engine with a car mechanic. Yes, they both have an engine, they both run on fuel but the mechanic only knows how to fix your car's engine he is not a rocket scientist(!)
This code works fine:
import Foundation
protocol Client: class {
var description: String { get }
}
final class ImportantPerson : Client {
var description: String {
return "Important person"
}
}
protocol Order: class {
var description: String { get }
}
final class LastOrder : Order {
var description: String {
return "Last order"
}
}
final class A {
fileprivate func resolveDependency<T>() -> T {
if T.self == Client.self {
return resolve() as Client as! T
} else {
return resolve() as Order as! T
}
}
private func resolve() -> Client {
return ImportantPerson()
}
private func resolve() -> Order {
return LastOrder()
}
}
let a = A()
let client: Client = a.resolveDependency()
let order: Order = a.resolveDependency()
print("Client: \(client.description)")
print("Order: \(order.description)")
But I believe that compiler should resolve the if else clause himself, it's not so hard as I suppose.
Also there is some bug in the compiler when it tries to match types like that:
switch T.self {
case is Client:
return resolve() as Client as! T
default:
return resolve() as Order as! T
}
We have function like this in swift 2.2 for printing a log message with the current running thread:
func MyLog(_ message: String) {
if Thread.isMainThread {
print("[MyLog]", message)
} else {
let queuename = String(UTF8String: dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))! // Error: Cannot convert value of type '()' to expected argument type 'DispatchQueue?'
print("[MyLog] [\(queuename)]", message)
}
}
These code no longer compile in swift 3.0. How do we obtain the queue name now?
As Brent Royal-Gordon mentioned in his message on lists.swift.org it's a hole in the current design, but you can use this horrible workaround.
func currentQueueName() -> String? {
let name = __dispatch_queue_get_label(nil)
return String(cString: name, encoding: .utf8)
}
If you don't like unsafe pointers and c-strings, there is another, safe solution:
if let currentQueueLabel = OperationQueue.current?.underlyingQueue?.label {
print(currentQueueLabel)
// Do something...
}
I don't know any cases when the currentQueueLabel will be nil.
Now DispatchQueue has label property.
The label you assigned to the dispatch queue at creation time.
var label: String { get }
It seems been existed from first, maybe not been exposed via public API.
macOS 10.10+
And please use this only to obtain human-readable labels. Not to identify each GCDQ.
If you want to check whether your code is running on certain GCDQ, you can use dispatchPrecondition(...) function.
This method will work for both OperationQueue and DispatchQueue.
func printCurrnetQueueName()
{
print(Thread.current.name!)
}
Here's a wrapper class that offers some safety (revised from here):
import Foundation
/// DispatchQueue wrapper that acts as a reentrant to a synchronous queue;
/// so callers to the `sync` function will check if they are on the current
/// queue and avoid deadlocking the queue (e.g. by executing another queue
/// dispatch call). Instead, it will just execute the given code in place.
public final class SafeSyncQueue {
public init(label: String, attributes: DispatchQueue.Attributes) {
self.queue = DispatchQueue(label: label, attributes: attributes)
self.queueKey = DispatchSpecificKey<QueueIdentity>()
self.queue.setSpecific(key: self.queueKey, value: QueueIdentity(label: self.queue.label))
}
// MARK: - API
/// Note: this will execute without the specified flags if it's on the current queue already
public func sync<T>(flags: DispatchWorkItemFlags? = nil, execute work: () throws -> T) rethrows -> T {
if self.currentQueueIdentity?.label == self.queue.label {
return try work()
} else if let flags = flags {
return try self.queue.sync(flags: flags, execute: work)
} else {
return try self.queue.sync(execute: work)
}
}
// MARK: - Private Structs
private struct QueueIdentity {
let label: String
}
// MARK: - Private Properties
private let queue: DispatchQueue
private let queueKey: DispatchSpecificKey<QueueIdentity>
private var currentQueueIdentity: QueueIdentity? {
return DispatchQueue.getSpecific(key: self.queueKey)
}
}
This works best for me:
/// The name/description of the current queue (Operation or Dispatch), if that can be found. Else, the name/description of the thread.
public func queueName() -> String {
if let currentOperationQueue = OperationQueue.current {
if let currentDispatchQueue = currentOperationQueue.underlyingQueue {
return "dispatch queue: \(currentDispatchQueue.label.nonEmpty ?? currentDispatchQueue.description)"
}
else {
return "operation queue: \(currentOperationQueue.name?.nonEmpty ?? currentOperationQueue.description)"
}
}
else {
let currentThread = Thread.current
return "UNKNOWN QUEUE on thread: \(currentThread.name?.nonEmpty ?? currentThread.description)"
}
}
public extension String {
/// Returns this string if it is not empty, else `nil`.
public var nonEmpty: String? {
if self.isEmpty {
return nil
}
else {
return self
}
}
}
What is the new syntax for dispatch_once in Swift after the changes made in language version 3? The old version was as follows.
var token: dispatch_once_t = 0
func test() {
dispatch_once(&token) {
}
}
These are the changes to libdispatch that were made.
While using lazy initialized globals can make sense for some one time initialization, it doesn't make sense for other types. It makes a lot of sense to use lazy initialized globals for things like singletons, it doesn't make a lot of sense for things like guarding a swizzle setup.
Here is a Swift 3 style implementation of dispatch_once:
public extension DispatchQueue {
private static var _onceTracker = [String]()
/**
Executes a block of code, associated with a unique token, only once. The code is thread safe and will
only execute the code once even in the presence of multithreaded calls.
- parameter token: A unique reverse DNS style name such as com.vectorform.<name> or a GUID
- parameter block: Block to execute once
*/
public class func once(token: String, block:#noescape(Void)->Void) {
objc_sync_enter(self); defer { objc_sync_exit(self) }
if _onceTracker.contains(token) {
return
}
_onceTracker.append(token)
block()
}
}
Here is an example usage:
DispatchQueue.once(token: "com.vectorform.test") {
print( "Do This Once!" )
}
or using a UUID
private let _onceToken = NSUUID().uuidString
DispatchQueue.once(token: _onceToken) {
print( "Do This Once!" )
}
As we are currently in a time of transition from swift 2 to 3, here is an example swift 2 implementation:
public class Dispatch
{
private static var _onceTokenTracker = [String]()
/**
Executes a block of code, associated with a unique token, only once. The code is thread safe and will
only execute the code once even in the presence of multithreaded calls.
- parameter token: A unique reverse DNS style name such as com.vectorform.<name> or a GUID
- parameter block: Block to execute once
*/
public class func once(token token: String, #noescape block:dispatch_block_t) {
objc_sync_enter(self); defer { objc_sync_exit(self) }
if _onceTokenTracker.contains(token) {
return
}
_onceTokenTracker.append(token)
block()
}
}
From the doc:
Dispatch
The free function dispatch_once is no longer available in
Swift. In Swift, you can use lazily initialized globals or static
properties and get the same thread-safety and called-once guarantees
as dispatch_once provided. Example:
let myGlobal: () = { … global contains initialization in a call to a closure … }()
_ = myGlobal // using myGlobal will invoke the initialization code only the first time it is used.
Expanding on Tod Cunningham's answer above, I've added another method which makes the token automatically from file, function, and line.
public extension DispatchQueue {
private static var _onceTracker = [String]()
public class func once(
file: String = #file,
function: String = #function,
line: Int = #line,
block: () -> Void
) {
let token = "\(file):\(function):\(line)"
once(token: token, block: block)
}
/**
Executes a block of code, associated with a unique token, only once. The code is thread safe and will
only execute the code once even in the presence of multithreaded calls.
- parameter token: A unique reverse DNS style name such as com.vectorform.<name> or a GUID
- parameter block: Block to execute once
*/
public class func once(
token: String,
block: () -> Void
) {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
guard !_onceTracker.contains(token) else { return }
_onceTracker.append(token)
block()
}
}
So it can be simpler to call:
DispatchQueue.once {
setupUI()
}
and you can still specify a token if you wish:
DispatchQueue.once(token: "com.hostname.project") {
setupUI()
}
I suppose you could get a collision if you have the same file in two modules. Too bad there isn't #module
Edit
#Frizlab's answer - this solution is not guaranteed to be thread-safe. An alternative should be used if this is crucial
Simple solution is
lazy var dispatchOnce : Void = { // or anyName I choose
self.title = "Hello Lazy Guy"
return
}()
used like
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
_ = dispatchOnce
}
You can declare a top-level variable function like this:
private var doOnce: ()->() = {
/* do some work only once per instance */
return {}
}()
then call this anywhere:
doOnce()
You can still use it if you add a bridging header:
typedef dispatch_once_t mxcl_dispatch_once_t;
void mxcl_dispatch_once(mxcl_dispatch_once_t *predicate, dispatch_block_t block);
Then in a .m somewhere:
void mxcl_dispatch_once(mxcl_dispatch_once_t *predicate, dispatch_block_t block) {
dispatch_once(predicate, block);
}
You should now be able to use mxcl_dispatch_once from Swift.
Mostly you should use what Apple suggest instead, but I had some legitimate uses where I needed to dispatch_once with a single token in two functions and there is not covered by what Apple provide instead.
Swift 3: For those who likes reusable classes (or structures):
public final class /* struct */ DispatchOnce {
private var lock: OSSpinLock = OS_SPINLOCK_INIT
private var isInitialized = false
public /* mutating */ func perform(block: (Void) -> Void) {
OSSpinLockLock(&lock)
if !isInitialized {
block()
isInitialized = true
}
OSSpinLockUnlock(&lock)
}
}
Usage:
class MyViewController: UIViewController {
private let /* var */ setUpOnce = DispatchOnce()
override func viewWillAppear() {
super.viewWillAppear()
setUpOnce.perform {
// Do some work here
// ...
}
}
}
Update (28 April 2017): OSSpinLock replaced with os_unfair_lock due deprecation warnings in macOS SDK 10.12.
public final class /* struct */ DispatchOnce {
private var lock = os_unfair_lock()
private var isInitialized = false
public /* mutating */ func perform(block: (Void) -> Void) {
os_unfair_lock_lock(&lock)
if !isInitialized {
block()
isInitialized = true
}
os_unfair_lock_unlock(&lock)
}
}
I improve above answers get result:
import Foundation
extension DispatchQueue {
private static var _onceTracker = [AnyHashable]()
///only excute once in same file&&func&&line
public class func onceInLocation(file: String = #file,
function: String = #function,
line: Int = #line,
block: () -> Void) {
let token = "\(file):\(function):\(line)"
once(token: token, block: block)
}
///only excute once in same Variable
public class func onceInVariable(variable:NSObject, block: () -> Void){
once(token: variable.rawPointer, block: block)
}
/**
Executes a block of code, associated with a unique token, only once. The code is thread safe and will
only execute the code once even in the presence of multithreaded calls.
- parameter token: A unique reverse DNS style name such as com.vectorform.<name> or a GUID
- parameter block: Block to execute once
*/
public class func once(token: AnyHashable,block: () -> Void) {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
guard !_onceTracker.contains(token) else { return }
_onceTracker.append(token)
block()
}
}
extension NSObject {
public var rawPointer:UnsafeMutableRawPointer? {
get {
Unmanaged.passUnretained(self).toOpaque()
}
}
}
import UIKit
// dispatch once
class StaticOnceTest {
static let test2 = {
print("Test " + $0 + " \($1)")
}("mediaHSL", 5)
lazy var closure: () = {
test(entryPoint: $0, videos: $1)
}("see all" , 4)
private func test(entryPoint: String, videos: Int) {
print("Test " + entryPoint + " \(videos)")
}
}
print("Test-1")
let a = StaticOnceTest()
a.closure
a.closure
a.closure
a.closure
StaticOnceTest.test2
StaticOnceTest.test2
StaticOnceTest.test2
StaticOnceTest.test2
OUTPUT:
Test-1
Test see all 4
Test mediaHSL 5
You can use a lazy var closure and execute it immediately with (#arguments_if_needed) so that it will call only one time. You can call any instance function inside of the closure [advantage].
You can pass multiple arguments based on need. You can capture those arguments when the class has been initialised and use them.
Another option: You can use a static let closure and it will execute only one time but you cannot call any instance func inside that static let clsoure. [disadvantage]
thanks!
Swift 5
dispatch_once is still available in libswiftFoundation.dylib standard library which is embedded to any swift app so you can access to exported symbols dynamically, get the function's symbol pointer, cast and call:
import Darwin
typealias DispatchOnce = #convention(c) (
_ predicate: UnsafePointer<UInt>?,
_ block: () -> Void
) -> Void
func dispatchOnce(_ predicate: UnsafePointer<UInt>?, _ block: () -> Void) {
let RTLD_DEFAULT = UnsafeMutableRawPointer(bitPattern: -2)
if let sym = dlsym(RTLD_DEFAULT, "dispatch_once") {
let f = unsafeBitCast(sym, to: DispatchOnce.self)
f(predicate, block)
}
else {
fatalError("Symbol not found")
}
}
Example:
var token: UInt = 0
for i in 0...10 {
print("iteration: \(i)")
dispatchOnce(&token) {
print("This is printed only on the first call")
}
}
Outputs:
iteration: 0
This is printed only on the first call
iteration: 1
iteration: 2
iteration: 3
iteration: 4
iteration: 5
iteration: 6
iteration: 7
iteration: 8
iteration: 9
iteration: 10
Use the class constant approach if you are using Swift 1.2 or above and the nested struct approach if you need to support earlier versions.
An exploration of the Singleton pattern in Swift. All approaches below support lazy initialization and thread safety.
dispatch_once approach is not worked in Swift 3.0
Approach A: Class constant
class SingletonA {
static let sharedInstance = SingletonA()
init() {
println("AAA");
}
}
Approach B: Nested struct
class SingletonB {
class var sharedInstance: SingletonB {
struct Static {
static let instance: SingletonB = SingletonB()
}
return Static.instance
}
}
Approach C: dispatch_once
class SingletonC {
class var sharedInstance: SingletonC {
struct Static {
static var onceToken: dispatch_once_t = 0
static var instance: SingletonC? = nil
}
dispatch_once(&Static.onceToken) {
Static.instance = SingletonC()
}
return Static.instance!
}
}
Is there an equivalent syntax or technique for Anonymous class in Swift?
Just for clarification Anonymous class in Java example here - http://docs.oracle.com/javase/tutorial/java/javaOO/anonymousclasses.html
Thanks!
There is no equivalent syntax, as far as I know.
Regarding equivalent techniques, theoretically you could use closures and define structs and classes inside them. Sadly, I can't get this to work in a playground or project without making it crash. Most likely this isn't ready to be used in the current beta.
Something like...
protocol SomeProtocol {
func hello()
}
let closure : () -> () = {
class NotSoAnonymousClass : SomeProtocol {
func hello() {
println("Hello")
}
}
let object = NotSoAnonymousClass()
object.hello()
}
...currently outputs this error:
invalid linkage type for global declaration
%swift.full_heapmetadata* #_TMdCFIv4Test7closureFT_T_iU_FT_T_L_19NotSoAnonymousClass
LLVM ERROR: Broken module found, compilation aborted!
Command /Applications/Xcode6-Beta.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/swift failed with exit code 1
You can also create a basic empty class that acts like a bare protocol, and pass a closure to the init function that overrides anything you want, like this:
class EmptyClass {
var someFunc: () -> () = { }
init(overrides: EmptyClass -> EmptyClass) {
overrides(self)
}
}
// Now you initialize 'EmptyClass' with a closure that sets
// whatever variable properties you want to override:
let workingClass = EmptyClass { ec in
ec.someFunc = { println("It worked!") }
return ec
}
workingClass.someFunc() // Outputs: "It worked!"
It is not technically 'anonymous' but it works the same way. You are given an empty shell of a class, and then you fill it in or override whatever parameters you want when you initialize it with a closure.
It's basically the same, except instead of fulfilling the expectations of a protocol, it is overriding the properties of a class.
For example, Java listener/adapter pattern would be translated to Swift like this:
protocol EventListener {
func handleEvent(event: Int) -> ()
}
class Adapter : EventListener {
func handleEvent(event: Int) -> () {
}
}
var instance: EventListener = {
class NotSoAnonymous : Adapter {
override func handleEvent(event: Int) {
println("Event: \(event)")
}
}
return NotSoAnonymous()
}()
instance.handleEvent(10)
(Crashing the compiler on Beta 2)
The problem is, you always have to specify a name. I don't think Apple will ever introduce anonymous classes (and structs etc.) because it would be pretty difficult to come with a syntax that doesn't collide with the trailing closures.
Also in programming anonymous things are bad. Naming things help readers to understand the code.
No anonymous class syntax in Swift. But, you can create a class inside a class and class methods:
class ViewController: UIViewController {
class anonymousSwiftClass {
func add(number1:Int, number2:Int) -> Int {
return number1+number2;
}
}
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
class innerSwiftClass {
func sub(number1:Int, number2:Int) -> Int {
return number1-number2;
}
}
var inner = innerSwiftClass();
println(inner.sub(2, number2: 3));
var anonymous = anonymousSwiftClass();
println(anonymous.add(2, number2: 3));
}
}
This is what I ended up doing (Observer pattern). You can use closures in a similar way you would use anonymous classes in Java. With obvious limitations of course.
class Subject {
// array of closures
var observers: [() -> Void] = []
// #escaping says the closure will be called after the method returns
func register(observer: #escaping () -> Void) {
observers.append(observer)
}
func triggerEvent() {
observers.forEach { observer in
observer()
}
}
}
var subj = Subject()
// you can use a trailing closure
subj.register() {
print("observerd")
}
// or you can assign a closure to a variable so you can maybe use the reference to removeObserver() if you choose to implement that method
var namedObserver: () -> Void = {
print("named observer")
}
subj.register(observer: namedObserver)
subj.triggerEvent()
// output:
// observerd
// named observer
If you want to inline a click handler in Java style fashion, first define your closure as a variable in your button class:
var onButtonClick: () -> Void = {}
Then add a method to accept the closure as parameter and store it in the variable for later use:
func onClick(label: String, buttonClickHandler: #escaping () -> Void) {
button.label = label
onButtonClick = buttonClickHandler
}
Whenever the closure should be executed, call it in your button class:
onButtonClick()
And this is how to set the action that should occur on click:
newButton.onClick(label: "My button") { () in
print("button clicked")
}
You can also accept multiple parameters. For example, a toggle button may be handled like this:
var buttonClicked: (_ isOn: Bool) -> Void { set get }
Simply use a struct for defining the interface via function values and then anonymously implement it from a function, as is a very common way to write objects in JavaScript.
The function is only required for creating a private scope for the object returned.
import Foundation
struct Logger {
let info: (String) -> ()
let error: (String) -> ()
}
func createSimpleLogger() -> Logger {
var count = 0
func number() -> Int {
count += 1
return count
}
return Logger(
info: { message in
print("INFO - #\(number()) - \(message)")
},
error: { message in
print("ERROR - #\(number()) - \(message)")
}
)
}
let logger = createSimpleLogger()
logger.info("Example info log message")
logger.error("Example error log message")
Output:
INFO - #1 - Example info log message
ERROR - #2 - Example error log message