Swift, Self from AnyObject - ios

Is it possible to get Self from AnyObject?
Take this example:
// Superclass
class ManagedObject {
class func findByID(id: String) -> AnyObject? {
let objects = objectsWithPredicate(NSPredicate(format: "id == %#", id))
return objects.firstObject() // Returns AnyObject
}
}
// Subclass
class User : ManagedObject {
class func returnFirstSelf() -> Self? {
return findById("1") // This doesn't work because it returns AnyObject, but I need Self.
}
}
If not, what is the best alternative way to ensure that when calling User.returnFirstSelf(), the compiler gives back a User, and when calling UserSubclass.returnFirstSelf(), it gives back a UserSubclass.

You can simply return User? from your class function, if this is an option:
public class func returnFirstSelf() -> User? {
if let found = findByID("1") as? User {
return found
}
return nil
}
There's currently no way (I'm aware of) to return Self? with Swift as it stands. The problem is that Self has a somewhat... "dynamic" meaning, separate from concrete types, protocols, and even generics. A particular example that demonstrates this is: What if you have a class StudentUser that extends User? If you tried to implement it like this:
class func returnFirstSelf() -> Self? {
if let found = findById("1") as? Self { // Note the check that 'found' is a 'Self'
return found
}
return nil
}
Then you encounter a compiler error because you cannot use Self outside the result of a protocol or class method. And if you try to implement it like this:
class func returnFirstSelf() -> Self? {
if let found = findById("1") as? User { // Note 'User' instead of 'Self'
return found
}
return nil
}
Then you run the risk of Self actually meaning StudentUser, and even if you pass the check that requires found to be a User, it doesn't guarantee that found will be a StudentUser. This will occur in the case that StudentUser does not override the method to ensure that the as? checks against StudentUser.
The critical flaw here in my opinion is that you cannot use the required keyword on class methods, requiring subclasses to override them. This would allow the compiler to ensure that any subclasses have overridden the method and provided an implementation that can guarantee type safety.

Craig Otis' answer is spot on. However, one option is to create a copy constructor. This may not work for the asker's scenario where they're inheriting from a NSManagedObject, but it should work for non-managed objects.
required init(user: User) {
super.init(user: User) // or super.init() if top of inheritance.
self.name = user.name
self.email = user.email
// etc.
}
class func returnFirstSelf() -> Self? {
if let found = findById("1") { // Note the check that 'found' is a 'Self'
return self.init(copy: found as! User)
}
return nil
}

Related

What exactly happens when you assign self to delegate?

I'm new to Swift and I'm having a hard time understanding the purpose of assigning self to a delegate. Part of the difficulty stems from the fact that delegate seems to be used in two different ways.
First is as means to send messages from one class to another when a specific event happens, almost like state management. Second is to enable "a class or structure to hand off (or delegate) some of its responsibilities to an instance of another type," as stated in documentation. I have a feeling that these two are fundamentally the same and I'm just not getting it.
protocol PersonProtocol {
func getName() -> String
func getAge() -> Int
}
class Person {
var delegate: PersonProtocol?
func printName() {
if let del = delegate {
print(del.getName())
} else {
print("The delegate property is not set")
}
}
func printAge() {
if let del = delegate {
print(del.getAge())
} else {
print("The delegate property is not set")
}
}
}
class ViewController: UIViewController, PersonProtocol {
var person: Person!
override func viewDidLoad() {
person.delegate = self
person.printAge()
person.printName()
}
func getAge() -> Int {
print("view controller")
return 99
}
func getName() -> String {
return "Some name"
}
}
What is the purpose of person.delegate = self in this case? Isn't ViewController already required to conform to PersonProtocol without it?
I have a feeling that these two are fundamentally the same
The first is a special case of the second. "send messages from one class to another" is just a specific way of "handing off some of its responsibilities". The "messages" are the "responsibilities"
What is the purpose of person.delegate = self in this case?
Here, person delegates (i.e. hands off) some of its responsibilities to another object. It does this by sending messages to another object. First, it needs to identify which objects it can delegate these responsibilities to. This is achieved by requiring that its delegate conform to PersonProtocol, as PersonProtocol defines the messages that Person is going to send.
Next, person needs to know exactly which object it should send these messages to. This is what person.delegate = self does. Remember that person doesn't know anything about your ViewController until this point. Instead of = self, you could say:
person.delegate = SomeOtherClassThatConformsToPersonProtocol()
and person will send its messages to that object instead, and the methods in your ViewController won't be called.
Isn't ViewController already required to conform to PersonProtocol without it?
Correct, but without it, person doesn't know which object it should send its messages to, and as a result, the methods in your ViewController won't be called.
Note that the delegate property should be declared as weak to avoid retain cycles. When you do person.delegate = self, you get a retain cycle: self has a strong reference to person, person also has a strong reference to self via the delegate property.
If you notice inside your Person class, delegate is nil. If you don't execute person.delegate = self, delegate will remain nil.
In other words, assigning ViewController to person.delegate allows Person to identify who the delegate is (i.e., have a reference to ViewController), and that way you can successfully execute statements like delegate?.getName() or delegate?.getAge() from the Person class.
that means Person is not able to getName() and getAge() so Person class delegate that to other DataSource.
Lets say the your view controller has a data source class PersonDataSource which deal with API to get this information So
class PersonDataSource: PersonProtocol {
func getAge() -> Int {
print("view controller")
return 99
}
func getName() -> String {
return "Some name"
}
}
so the view controller will looks like this
class ViewController: UIViewController {
var person: Person!
var personDataSource = PersonDataSource()
override func viewDidLoad() {
person.delegate = personDataSource
person.printAge()
person.printName()
}
}

Storing UIViewController generic with a protocol as a property

Okay, so I'm pretty sure I'm overthinking this.
I am passing through a viewController that conforms to a protocol as a generic like so:
static func sortPage<T: UIViewController>(controller: T, err: NSError) where T: SortAlertDelegate { }
What I want to be able to do is store that controlleras a property so I can access all the functions UIViewController gives me and the functions thats the SortAlerDelegate gives me.
Any ideas?
You can't specify a type and protocol conformance for a property. You'll need to cast your property to the correct type whenever you want to use specific features. However, you can make this less painful with a bit of boilerplate:
let myProperty: UIViewController? = nil {
willSet(newValue) {
if (newValue as? SortAlertDelegate != nil) {
myProperty = newValue
} else {
myProperty = nil
}
}
}
This way, if you try to set the property to an object which doesn't conform to the protocol, the set will be aborted and the property will be set to nil.
You can also write read-only properties in order to get your property as the type you need at the moment:
let myPropertyAsViewController: UIViewController? {
get { return myProperty }
}
let myPropertyAsDelegate: SortAlertDelegate? {
get {
if let myProperty = myProperty {
return myProperty as! SortAlertDelegate
} else {
return nil
}
}
}
In general it is not possible unless you move the generic constraint on top of your class definition like:
class ViewController<T: UIViewController> : UIViewController where T: SortAlertDelegate {
let delegateController: T
}
But you can also make two references in your class like
class ViewController: UIViewController {
let controller: UIViewController
let delegate: SearchAlertDelegate
}
And then store the same object as two different references.

How can I return self in a class method?

Tried this and it gives me an error:
class BaseClass {
class var testProperty: String {
return "Original"
}
class func testingFunc()->Self {
return self // error - Can not convert return expression of type "Self.Type" to return the type "Self"
}
}
Any thought?
Thanks
In a class/static function, self refers to the Class Type. There is no instance to refer to, so what you get is the type, which is the current scope. It's not the same in an instance method, where self refers to <instance>.self
class Foo {
class func classMethod() -> Foo.Type {
return self // means Foo.self
}
func instanceMethod() -> Foo {
return self // means <instance of Foo>.self
}
}
Your return type should be the class type you are in. In this case it isBaseClass.
Also, you are defining a class function which is basically a static function. It will not return an instance. I don't really understand what you are trying to accomplish.
If you want to get info about an instance, use an instance function. Omit the keyword class when defining the function.
class BaseClass {
func instanceInfo() {
// self here refers to the instance
}
}

Return an array of type Self

I'm having trouble figuring out a way to return an array of instances of a specific dynamic class type, at runtime, in Swift.
I successfully compiled and tested this version which returns a single instance of a class:
class Generic {
class func all() -> Self {
return self.init()
}
required init() {
}
}
class A: Generic {
}
let a = A.all() // is of type A
The challenge here is to get compilation to allow the all function to be prototyped as follows: class func all() -> [Self] (i.e return an array of instances, working with subclasses, without any cast).
class Generic {
class func all() -> [Self] {
return [self.init()]
}
required init() {
}
}
class A: Generic {
}
let a = A.all() // won't compile
I could return an array of Generic instances with class func all() -> [Generic] but this requires an additional cast with as! to get the correct type A. I'd like to take advantage of begin in the context of class A and using the Self keyword, to let the compiler infer the 'real' type. Do you guys think it's possible?
It seems to be only possible to return single instances, not arrays.
EDIT: Got this to work using AnyObject. Better, but not optimal as it requires a cast to the correct type.
class Generic {
class func all() -> [AnyObject] {
return [self.init()]
}
required init() {
}
}
class A: Generic {
}
let a = A.all() as! [A]
Thanks!
PS: Any other way to do this using generics or protocols/protocol extensions is also an option. If you have a more "Swifty" version in mind, please be my guest. Can't help myself thinking there's maybe a better way to do this, but can't figure out how.
The only option I can see of doing something like that is using protocols instead of a base class, like this:
protocol Generic {
func all() -> [Self]
init()
}
extension Generic {
func all() -> [Self] {
return [self.dynamicType.init()]
}
}
final class A : Generic {
}
A().all()
You have two limitations doing it like this. First, all classes that conform to your protocol have to be final. Second, all classes must obviously implement the init defined in the protocol, otherwise we wouldn't be able to have the all method defined.
Edit: you don't actually need to define the init as long as you don't define any other initializers
Edit 2: I didn't notice you used class functions, you can modify my example to use class functions instead of instance methods by replacing func all() -> [Self] with static func all() -> [Self] and
func all() -> [Self] {
return [self.dynamicType.init()]
}
with
static func all() -> [Self] {
return [self.init()]
}
Unfortunately, there doesn't seem to be a way to do this using Self. Self cannot be used in expressions, so [Self] or Array<Self> are not allowed.
However, I think that your use case is completely valid and you should repot it as a bug.

Swift - Dynamic cast class unconditional?

It doesn't seem like I can cast a generic type to another? Swift is throwing DynamicCastClassException.
Basically here is the problem:
// T is defined as T: NSObject
let oebj1 = NetworkResponse<User>()
let oebj2 = oebj1 as NetworkResponse<NSObject>
Here is why I need to do this casting
class BaseViewController: UIViewController {
// Not allowed to make a generic viewController and therefore have to cast the generic down to NSObject
func fetchData(completion: (NetworkResponse<NSObject>)->()) {
fatalError("You have to implement fetchData method")
}
}
class UsersViewController: BaseViewController {
override func fetchData(completion: (NetworkResponse<NSObject>)->()) {
userNetworkManager.fetchUsers { networkUSerResponse in
completion(networkUSerResponse as NetworkResponse<NSObject>)
}
}
}
class UserNetworkManager {
func fetchUsers(completion: (NetworkResponse<User>)->()) {
// Do stuff
}
}
In general, there doesn't seem to be a way to do this. The basic problem is that NetworkResponse<NSObject> and NetworkResponse<User> are essentially completely unrelated types that happen to have identical functionality and similar naming.
In this specific case, it really isn't necessary since you're throwing away the known Userness of the result anyway, meaning that if you really want to treat it as a User later you'll have to do a conditional cast back. Just remove the generic from NetworkResponse and it will all work as expected. The major drawback is that within UserVC.fetchData you won't have access to the returned User result without a (conditional) cast.
The alternative solution would be to separate out whatever additional information is in NetworkResponse from the payload type (User/NSObject) using a wrapper of some sort (assuming there's significant sideband data there). That way you could pass the NetworkResponse to super without mutilation and down-cast the payload object as needed.
Something like this:
class User : NSObject {
}
class Transaction {
let request:NSURLRequest?
let response:NSURLResponse?
let data:NSData?
}
class Response<T:NSObject> {
let transaction:Transaction
let payload:T
init(transaction:Transaction, payload:T) {
self.transaction = transaction
self.payload = payload
}
}
class UserNetworkManager {
func fetchUsers(completion: (Response<User>) -> ()) {
completion(Response(transaction:Transaction(), payload:User()))
}
}
let userNetworkManager = UserNetworkManager();
class BaseVC {
func fetchData(completion: (Response<NSObject>) -> ()) {
fatalError("Gotta implement fetchData")
}
}
class UserVC : BaseVC {
override func fetchData(completion: (Response<NSObject>) -> ()) {
userNetworkManager.fetchUsers { response -> () in
completion(Response(transaction: response.transaction, payload: response.payload))
}
}
}
Although at that point, you're probably better off just separating the transaction information and payload information into separate arguments to the callback.

Resources