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 newSettings
is constructed each time, but this is perfectly legit. - The second case,
A.Settings()....
invokes the constructor ofSettings
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, becausegetSettings()
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
anda1
methods, satisfying the requirements ofSomeProtocol
- The implementations of
a0
anda1
call through to the closuresdec
andinc
, which are stored properties (aka instance variables) of theHelper
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 implicitself
that refers to theMyClass
instance creating theHelper
.
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
How to Create a Window with Transparent Background with Swift on Osx
How to Import a Swift Function Declared in a Compiled .Swiftmodule into Another Swift File
What's the Equivalent to String.Localizedstringwithformat(_:_:) for Swiftui's Localizedstringkey
How Does Dictionary Use the Equatable Protocol in Swift
Getting Optional("") When Trying to Get Value from Keychain
Uicollectionview Compositionallayout Not Calling Uiscrolldelegate
Cast a Swift Struct to Unsafemutablepointer<Void>
Keyboard Overlaying Action Sheet in iOS 13.1 on Cncontactviewcontroller
Swiftier Swift for 'Add to Array, or Create If Not There...'
Get Current Time as String Swift 3.0
Accessing Mkmapview Elements as Uiviewrepresentable in the Main (Contentview) Swiftui View
Swiftui Exporting or Sharing Files
Confusion Due to Swift Lacking Implicit Conversion of Cgfloat