Anonymous Class in Swift

Anonymous class in swift

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

Can you create anonymous inner classes in Swift?

As @ChrisWagner states in his comment, you shouldn't need to do any of this in iOS8, at least for UIAlertView since there is a new UIAlertViewController that uses closures without any delegates. But from an academic point of view, this pattern is still interesting.

I wouldn't use anonymous class at all. I would just create a class that can be assigned as the delegate and accept closures to execute when something happens.

You could even upgrade this to accept a closure for each kind of action: onDismiss, onCancel, etc. Or you could even make this class spawn the alert view, setting itself as the delegate.

import UIKit

class AlertViewHandler: NSObject, UIAlertViewDelegate {
typealias ButtonCallback = (buttonIndex: Int)->()
var onClick: ButtonCallback?

init(onClick: ButtonCallback?) {
super.init()
self.onClick = onClick
}

func alertView(alertView: UIAlertView!, clickedButtonAtIndex buttonIndex: Int) {
onClick?(buttonIndex: buttonIndex)
}
}


class ViewController: UIViewController {

// apparently, UIAlertView does NOT retain it's delegate.
// So we have to keep it around with this instance var
// It'll be nice when all of UIKit is properly Swift-ified :(
var alertHandler: AlertViewHandler?

func doSoemthing() {
alertHandler = AlertViewHandler({ (clickedIndex: Int) in
println("clicked button \(clickedIndex)")
})

let alertView = UIAlertView(
title: "Test",
message: "OK",
delegate: alertHandler!,
cancelButtonTitle: "Cancel"
)
}
}

Passing around closures should alleviate the need for anonymous classes. At least for the most common cases.

How translate to Swift an anonymous class of Java?

Mostly this syntax (inline definition of anonymous classes) exists because Java doesn't allow the concept of closures or lambda functions, so if you want to pass a function to be invoked you have to pass an instance of a class with the function then declared inline.

In contrast, Swift, like most modern languages has a specific closure syntax which allows you to directly pass executable blocks to another routine, essentially it allows you to treat functions as first class language entities.

So, the bottom line is that no, Swift doesn't allow the construct you've asked about, but it does provide equivalent functionality for the dominant use case. The code most analogous to your example would be:

dispatch_async(...) {
Code to be executed asynchronously here
}

Which is really just syntactic sugar for:

dispatch_async(..., {
Your code here
})

Since the anonymous object is being created only as a holder for a single object, there's really no need for the object, or indeed, the class, and hence the syntax. The only time the Java syntax has a slight advantage is if the callee needs to maintain multiple related callbacks.

Hiding inner class in swift

Why do both calls work in the test caller?

Both currently work because:

  • The first case, A.getSettings()... is a classic getter that returns an object. I'm just puzzled with the fact that a new Settings is constructed each time, but this is perfectly legit.
  • The second case, A.Settings().... invokes the constructor of Settings to create an anonymous object, and invokes some methods on it. It's ok, because the inner class is public, but it's weird.

Can you make the inner class private?

You could make an inner class private to avoid it being accessed from the outside world:

  • This would work perfectly well for an private helper class totally invisible to the outside world.
  • For Settings this is not possible, because getSettings() returns objects of this class to the outside world, and this makes only sense if the outside world knows the class to deal with it.

Exemple:

class A {
static func getSettings() -> Settings { // ERROR if Settings would be private
let helper = Helper() // purely internal use: Helper can be private :-)
helper.demo()
return Settings()
}
class Settings { // making private is not possible (see above)
func turnOnSomeThing() {
print ("On")
}
}
private class Helper { // Cannot be used outside
func demo() {
print ("Demo")
}
}
}

But how to do with Settings?

If you want to return Settings objects to the wild outside world you need to keep that class public. However, if you want to avoid that the outside world misues the inner class and avoid objects to be created from the outside wolrd, you can use access control on the constructor:

class A {
static func getSettings() -> Settings {
...
}
class Settings {
fileprivate init() { /// <=== ACCESS CONTROL internal or fileprivate
}
func turnOnSomeThing() {
...
}
}
}

This prevents the calls of the form A.Settings()..., but only according to swift access control: with internal you can still call the constructor from another file of the same module; with fileprivate the constructor can only be called from within the source file in which you've defined your external class.

This technique of making the constructor inaccessible while keeping the class usable is frequently used for classes which instances shall only be created via a factory.

Do Swift inner classes have access to self of outer class?

AFAIK, you can't access the outer class out-of-the-box.

But what you can do is:

class Outer {

let value = ""
var inner = Inner()

class Inner {

weak var parent: Outer! = nil

func foo() {
let bar = parent.value
}

}

init() {
inner.parent = self
}

}

Or:

class Outer {

class Inner {

unowned let parent: Outer

init(parent: Outer) {
self.parent = parent
}

}

let value = ""
var inner: Inner! = nil

init() {
inner = Inner(parent: self)
}

}

Lazy/inline implement a protocol in Swift

What you're looking for is an inner class (not necessarily an anonymous one), declared in a scope that lets it access the count variable of a MyClass instance, and that adopts a protocol defined at a different scope. Right now Swift has a few of those pieces, but it doesn't look like you can put them all together in any way that's as concise as what you might be looking for.

You might think about declaring an inner class:

class MyView: UIView {
let someComponent = SomeInnerComponent() // type SomeInnerComponent is inferred
var count = 0 // type Int is inferred
class Helper: SomeProtocol {
func a0() { count-- } // ERROR
// ...
}
init() {
someComponent.delegate = Helper()
}
}

But that won't work, because count is implicitly self.count, where self is a Helper instance, not the MyView instance that "owns" the Helper instance. And there isn't a way to reference that MyView instance (or its properties) from within a Helper's methods, because you could just as well construct a MyView.Helper() without having an existing MyView instance. Inner classes (or nested types in general) in Swift nest only in lexical scope, not in existential ownership. (Or to put it another way, since you referenced Java: all inner classes in Swift are like static inner classes in Java. There's no non-static inner class.) If that's a feature you'd like, though, it's probably worth telling Apple you want it.

You could also try declaring Helper inside MyView.init() -- in Swift you can nest type definitions anywhere, including inside functions or methods of other types. Defined there, it can refer to MyView's properties. However, now the type information for Helper is only visible inside of MyView.init(), so when you assign it to someComponent.delegate (whose type is just SomeProtocol), you can't make use of it... this crashes the compiler, even. (That's another bug to report, but it's hard to say whether the bug is really "compiler crashes on valid usage" or "code is bad, but compiler crashes instead of producing error".)

The closest solution I can come up with looks something like this:

class SomeInnerComponent {
var delegate: SomeProtocol?
}
protocol SomeProtocol {
func a0()
func a1()
}
class MyClass {
var someComponent = SomeInnerComponent()
var count = 0
struct Helper: SomeProtocol {
var dec: () -> ()
var inc: () -> ()
func a0() { dec() }
func a1() { inc() }
}
init() {
someComponent.delegate = Helper(
dec: { self.count -= 1 }, // see note below
inc: { self.count += 1 }
)
}
}

How it works:

  • Helper is an inner struct (could be a class, but a struct is simpler)
  • It implements the a0 and a1 methods, satisfying the requirements of SomeProtocol
  • The implementations of a0 and a1 call through to the closures dec and inc, which are stored properties (aka instance variables) of the Helper struct
  • You write (or otherwise specify) these closures when you construct a Helper instance (using the default member-wise initializer, Helper(dec: (Void -> Void), inc: (Void -> Void)))
  • Because you can write the closures when initializing a Helper, those closures can capture variables where you're calling the initializer, including the implicit self that refers to the MyClass instance creating the Helper.

You need both a0/a1 and dec/inc because you need closures (the latter), not methods, for capturing the enclosing state. And even though closures and funcs/methods are in many ways interchangeable, you can't create a method/func implementation by assigning a closure to a method/func name. (It'd be a different story if SomeProtocol required closure properties instead of methods, but I'm assuming SomeProtocol isn't something under your control.)

Anyway, this is kind of a lot of boilerplate and a layer of abstraction that you might not really need, so it's probably worth looking into other ways to architect your code.


Note: my example uses the closure { self.count -= 1 } where you might expect { self.count-- }. The latter doesn't work because that's an expression with a value, so Swift will interpret it as shorthand for the closure's return value. Then it'll complain that you assigned a () -> Int closure to a property that expects a () -> () (aka Void -> Void) closure. Using -= 1 instead works around this issue.

How Does RXSwift combineLatest Use, What Looks Like, An Anonymous Class In A Closure And Handle Additional Parameters

The (arg1: $1, arg2: $0.0, arg3: $0.1, arg4: $2) part inside the closure creates a Tuple. A tuple is a group of multiple values of any type. Each element of a tuple can have a name, but they always can be accessed by number. In your example the tuple has 4 elements with the names arg1, arg2, arg3 and arg4. The elements of a tuple can have any type.

The syntax to create tuples is a list of comma-separated values with optional names inside parenthesis:

 let a = (1, "hello", true)
let b = (first: 1, second: "hello", true)

To access the values of a tuple you use a . followed by the name or index:

 print(a.0, a.1, a.2)
print(b.first, b.second, b.2)
let x = b.0

Note that you can also use the index, even if the element is named.



Related Topics



Leave a reply



Submit