Swift Nested Class Properties

Swift nested class properties

Swift's nested classes are not like Java's nested classes. Well, they're like one kind of Java's nested classes, but not the kind you're thinking of.

In Java, an instance of an inner class automatically has a reference to an instance of the outer class (unless the inner class is declared static). You can only create an instance of the inner class if you have an instance of the outer class. That's why in Java you say something like this.new nested().

In Swift, an instance of an inner class is independent of any instance of the outer class. It is as if all inner classes in Swift are declared using Java's static. If you want the instance of the inner class to have a reference to an instance of the outer class, you must make it explicit:

class Master {
var test = 2;

class Nested{
init(master: Master) {
let example = master.test;
}
}

func f() {
// Nested is in scope in the body of Master, so this works:
let n = Nested(master: self)
}
}

var m = Master()
// Outside Master, you must qualify the name of the inner class:
var n = Master.Nested(master:m)

// This doesn't work because Nested isn't an instance property or function:
var n2 = m.Nested()

// This doesn't work because Nested isn't in scope here:
var n3 = Nested(master: m)

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)
}

}

How can I directly access inner class in Swift

You can use a typealias

typealias FranchiseLogic = Logic.FranchiseLogic

This will allow you to use it as FranchiseLogic in the scope where the typealias is defined.

I have two inner class in class and i can't init class in swift

The compiler is correct, you are attempting to pass self to the constructor of Customer before all stored properties are initialised, as SESSION won't be initialised until after the Session object is initialised, but that needs self - your two requirements are mutually exclusive.

You may need to rethink your architecture; If nothing else, the reference from Customer to Session combined with the reference from Session to Customer will give you a retain cycle and a memory leak.

If you want to use the current architecture, it is probably best to make the Customer property of Session a weak optional to avoid both your initialisation problem and the retain cycle;

class Customer {
let session: Session
let auth: Auth

init() {
self.auth = Auth()
self.session = Session()
session.customer = self
}

class Session {
weak var customer: Customer?
}
}

You could make customer an implicitly unwrapped optional to avoid the need to unwrap it explicitly each time you refer to it, but you risk a crash if customer is released or not set:

class Session {
weak var customer: Customer!
}

On a point of style, Swift properties and variables should start with a lower case letter and use camel case, so auth, session and userID, not AUTH, SESSION and USER_ID.

It is a good practice to use inner classes in swift for models?

This is a good practice to make your namespace organized and the question is related to the below one:
Swift nested class properties

How to specify nested custom view class?

At this time, I think that Interface Builder only recognizes the names of Objective-C classes. You can still make Interface Builder find a nested class with the @objc keyword:

class SuperView: UIView {
@objc(SVNestedView) class NestedView: UIImageView {
}
}

Then, in Interface Builder, specify that th view is of class SVNestedView. Since Objective-C isn't namespaced, you still need to pick unique names for each nested class, but at least the Swift side is properly namespaced.

Why would one use nested classes?

You would do that for Namespacing. This way you can have the classes with the same name (like DataGenerator). But for different purposes. This one would be DataImporter.DataGenerator class, but you could have another OtherClass.DataGenerator class which would be a totally different one.

Like in Objective-C when you had 2 or 3 letters before the name of the class (ex: UIView). But when you created your own, it would be like SSView

You can also declare the inner class private and use it just in that file.

KeyPath to Nested Class

A nested class is referred to by name using standard dot notation, so in your case the nested class is Config.Client.

As you know a key-path is of the form \<type name>.<path> so the path you are seeking is \Config.Client.name.

HTH

How to get the string representation of a nested class

String(reflecting: type(of: theValue))

update by Edwin Vermeer:
For the required conversion to the internal string representation i now have the following function (still in draft)

public class func convertToInternalSwiftRepresentation(type: String) -> String {
if type.components(separatedBy: "<").count > 1 {
// Remove the Array or Set prefix
let prefix = type.components(separatedBy: "<") [0] + "<"
var subtype = type.substring(from: prefix.endIndex)
subtype = subtype.substring(to: subtype.characters.index(before: subtype.endIndex))
return prefix + convertToInternalSwiftRepresentation(type: subtype) + ">"
}

if type.contains(".") {
var parts = type.components(separatedBy: ".")
if parts.count == 2 {
return parts[1]
}
let c = String(repeating:"C", count: parts.count - 1)
var rv = "_Tt\(c)\(parts[0].characters.count)\(parts[0])"
parts.remove(at: 0)
for part in parts {
rv = "\(rv)\(part.characters.count)\(part)"
}
return rv
}
return type
}


Related Topics



Leave a reply



Submit