Edit - Sorry guys, I don't think I gave enough detail:
In Parse's iOS framework, they is a class called PFObject (ClassA). The framework also allows you to subclass (ClassB) PFObject. AND, if a scenario such as the one I gave should occur, they would be no issue.
My question is how is this possible? I understand that a subclass could contain variables/methods that would not be present in the main class, thus making the process of casting a class to a subclass unreasonable/unsafe.
They have a protocol defined as PFSubclassing, but I don't see exactly how this allows this behaviour to occur.
I've got the following in Playground:
class ClassA: NSObject { }
class ClassB: ClassA { }
let objectA = ClassA()
let objectB = objectA as! ClassB // <- Crashes
Questions:
Why is a crash occurring?
Is there any way around this?
You do know how inheritance works right? Class B inherits from Class A. When you make an instance of ClassA and then try to cast it to class B, many different things might happen because this is undefined behavior. The problem here is what's called slicing. The compiler refuses to cast down from a parent class to a child class because it knows the child class may have different info (variables, func. etc) and it doesn't necessarily know how to translate those into an instance of a super classes child class. However, going the other way around is almost always fine, i.e
let objectB = ClassB()
let objectA = objectB as? ClassA
A subclass inherits all functionality from its super class and can add own functionality.
Logically you can cast types only from more to less functionality (sub -> super) but not vice versa.
Related
I understand that generally I cannot instantiate a protocol.
But if I include an initialiser in the protocol then surely the compiler knows that when the protocol is used by a struct or class later, it will have an init which it can use?
My code is as below and line:
protocol Solution {
var answer: String { get }
}
protocol Problem {
var pose: String { get }
}
protocol SolvableProblem: Problem {
func solve() -> Solution?
}
protocol ProblemGenerator {
func next() -> SolvableProblem
}
protocol Puzzle {
var problem: Problem { get }
var solution: Solution { get }
init(problem: Problem, solution: Solution)
}
protocol PuzzleGenerator {
func next() -> Puzzle
}
protocol FindBySolvePuzzleGenerator: PuzzleGenerator {
var problemGenerator: ProblemGenerator { get }
}
extension FindBySolvePuzzleGenerator {
func next() -> Puzzle {
while true {
let problem = problemGenerator.next()
if let solution = problem.solve() {
return Puzzle(problem: problem, solution: solution)
}
}
}
}
The line:
return Puzzle(problem: problem, solution: solution)
gives error: Protocol type 'Puzzle' cannot be instantiated
Imagine protocols are adjectives. Movable says you can move it, Red says it has color = "red"... but they don't say what it is. You need a noun. A Red, Movable Car. You can instantiate a Car, even when low on details. You cannot instantiate a Red.
But if I include an initialiser in the protocol then surely the compiler knows that when the protocol is used by a struct or class later, it will have an init which it can use?
Protocols must be adopted by classes, and there might be a dozen different classes that all adopt your Puzzle protocol. The compiler has no idea which of those classes to instantiate.
Protocols give us the power to compose interfaces without the complexity of multiple inheritance. In a multiple inheritance language like C++, you have to deal with the fact that a single class D might inherit from two other classes, B and C, and those two classes might happen to have methods or instance variables with the same name. If they both have a methodA(), and B::methodA() and C::methodA() are different, which one do you use when someone call's D's inherited methodA()? Worse, what if B and C are both derived from a common base class A? Protocols avoid a lot of that by not being directly instantiable, while still providing the interface polymorphism that makes multiple inheritance attractive.
I understand that I can't do it - I just want to understand why the
compiler can't do it?
Because protocols in Swift represent abstraction mechanism. When it comes to abstraction, you could think about it as a template, we don't have to care about the details of how it behaves or what's its properties; Thus it makes no sense to be able to create an object from it.
As a real world example, consider that I just said "Table" (as an abstracted level), I would be pretty sure that you would understand what I am talking about! nevertheless we are not mentioning details about it (such as its material or how many legs it has...); At some point if I said "create a table for me" (instantiate an object) you have the ask me about specs! and that's why the complier won't let you create object directly from a protocol. That's the point of making things to be abstracted.
Also, checking: Why can't an object of abstract class be created? might be helpful.
Unfortunately swift does not allow that even with such "hack"
You would need to use a class that confirms to that protocol as an object you refer to.
When you instantiate an object, the Operating System has to know how to allocate and deal with that kind of object in the memory: Is it a reference type (Classes)? Strong, weak or unowned reference? Or is it a value type (Structs, Strings, Int, etc)?
Reference types are stored in the Heap, while value types live in the Stack. Here is a thorough explanation of the difference between the two.
Only Reference and Value types (objects) can be instantiated. So, only the objects that conform to that protocol can then be instantiated, not the protocol itself. A protocol is not an object, it is a general description or schema of a certain behavior of objects.
As to Initialization, here what the Apple docs say:
Initialization is the process of preparing an instance of a class,
structure, or enumeration for use. This process involves setting an
initial value for each stored property on that instance and performing
any other setup or initialization that is required before the new
instance is ready for use.
Lets say there are two classes, class A and class B. Class B is a child view controller of A.
protocol ClassADelegate: class{
functions
}
class A {
code
add B as child view controller
}
protocol ClassBDelegate: class{
functions
}
class B {
code
}
Considering that class A is the parent view controller of B, My question is if class A is a delegate of class B and class B is a delegate of class A, does that create an ownership cycle? Is this bad practice?
The parent should be the child's delegate.
The parent, if it needs to tell the child something, should just invoke methods.
Delegates in Cocoa are stored as weak references. Weak references can't keep objects alive the way strong references do, thus you have no risk of strong reference cycles.
However, I can't think of a situation in which this would make sense. It's not really a delegate pattern anymore, it's just 2 objects arbitrarily messaging each other.
if class A is a delegate of class B and class B is a delegate of class A, does that create an ownership cycle? Is this bad practice?
It doesn't necessarily produce a reference cycle. Normally, an object doesn't retain its delegate. As to whether it's bad practice, that depends. It's unusual, in that you'd normally expect that a delegate would have a lifetime at least as long as the object that it's delegating for, while you'd expect a child view controller to have a shorter lifetime than its parent. Without knowing more about your intended design, it's impossible to say for sure.
Delegation is a new concept for me. To my understanding, it asks someone else to do some job for me. I then, delegate some tasks to him.
class Vehicle {
var numberOfWheels = 0
var description: String {
return "\(numberOfWheels) wheel(s)"
}
}
class Bicycle: Vehicle {
override init() {
super.init() //# Delegate up
numberOfWheels = 2
}
}
The code super.init() is a delegate up action in class initialization. The subclass initializer calls the initializer of the superclass first. The superclass' default initializer assigning the integer 0 to the variable numberOfWheels. This is Phase one initialization. After that, the overriding action of the subclass' initializer further customizes the variable by numberOfWheels = 2.
Question Is there any incorrectness of my understanding? and I hope the delegate up description I'm used here is correct.
Please correct any error and misunderstandings I have it here. Thanks
What you are depicting here has nothing to do with delegation-pattern at all, it's the concept of inheritance. Your bicycle class is inheriting from Vehicle. Vehicle has already implemented some code, so instead of writing it again you can use the code of the super-class (the class that is inherited from). Your super-class doesn't have a defined initializer, therefore the super.init() wont even do anything. You should read about inheritance and try to understand this concept better.
Here's what delegation does: You are right about the idea of delegation. It allows you to "outsource" some work to another class. This can be achieved with protocols. A delegate has to conform a delegation protocol to ensure that it has the methods you want to call on it. You are using protocols instead of inherited classes here, because you don't care about the implementation of the specific methods, you just want to tell your delegate to handle a situation, it's up to the delegate to know what to do.
Delegation is most commonly used in MVC applications for macOS and iOS. You can read more about delegation in the Apple Documentation. There are also dozens of tutorials like this one on the internet that show how delegation works in practice.
In order to be a bit more clear I am looking for a solution for the user to pass a class with a specific subclass and protocol, i.e. a class that inherits a viewController and delegate protocol. I know its possible to create a protocol list but cannot find a solution that works correctly. Currently I use a initializer and use the viewcontroller as a parameter and check for delegate inside the function but I would rather if I can have these types in the parameter instead.
EDIT:
Looking to do something similar to this
Protocol prot:Delegate{}
class cla:ViewController{}
class impl{
init(mainUI: cla, prot){
do things
}
}
That way back in the main view controller I can do something like this
class viewController: cla, prot{
var view:impl
override func loadView() {
//Attach to Screen
view = impl(mainUI: self);
}
}
Their is a bit more happening but that's the only part thats really relevant. Currently I use a initializer to just fail if the class doesn't inherit the correct protocols
You could create a dummy type that represents your requirements. A typealias doesn't work in this case, but this might:
class DummyClass: MyViewController, MyDelegateProtocol {}
func needsRequiredClass(input: DummyClass) {...}
With MyViewController and MyDelegateProtocol being the superclass and delegate you mentioned. The DummyClass would have an empty implementation.
Then, make your specific classes sub classes of DummyClass:
class TestClass: DummyClass {...}
And you can pass in that new class:
let test = TestClass()
self.needsRequiredClass(test)
You're asking the wrong question. In other words trying to shoe-horn in a serious design mistake.
A view should not know that its delegate is a UIViewController or a subclass.
A delegate should be any class that obeys (adopts) a specific delegate protocol.
A view should only delegate specific responsibilities. Each of those responsibilities must be described by a protocol method or property.
If you explain what your issue is in more detail (why you think you need direct access to the entire definition of a UIViewController within a UIView), we can help you avoid this mistake.
As long as a Swift class extends from NSObject we can pass it to the Objective-C runtime and ask it to introspect it for us.
We have three options:
class
classForCoder
classForKeyedArchiver
. . however class is struck out. (See image). Why is this?
That's because class is a keyword in Swift, therefore any valid method cannot be named class. In the same way you cannot create a method named for, while or other keyword.
I wasn't able to reproduce the strike-out with my methods, however, naming a method var (or other keyword) in obj-c makes it impossible to be called from Swift.
Edit
I was wrong. It's still possible to call class from Swift using
var clazz: AnyClass? = self.`class`()
However, then the compiler says:
'Class' is unavailable: use 'dynamicType' instead
So the answer by Edwin Vermeers is the correct one.
As you can see in the documentation, it's only available in Objective C and not in swift.
See: https://developer.apple.com/documentation/objectivec/nsobject/1571950-class
I think this is because the AnyObject gives you enough information (More than the NSObject)
for instance you can do NSStringFromClass(BaseObject) in swift instead of the NSStringFromClass([BaseObject class]) that you do in Objective C