I have thousands of lines of chained animations code. I have moved it all to a GraphicsHelper class with references back to the data in my ViewController. Once I am through with the code I would like to jettison the class instance on the theory that I can keep memory (and my view controller code) small. The view controller stays in scope during the whole app which runs through several "phases". Is there a way to programmatically disconnect the class instance of the helper class? I have tried to assign nil but I get an error that the class does not conform to NilLiteralConverter protocol. Any way to disconnect the instance or an alternative to my perceived voluminous code problem? Thank you all in advance. Am I the only one in the world that wants to do something like this?
You need to declare the instance variable of your class as an optional,
class ViewController: UIViewController {
var helper: GraphicsHelper!
override func viewDidLoad() {
super.viewDidLoad()
helper = GraphicsHelper()
// some time later
helper = nil // no errors on this line, GraphicsHelper deinit called
}
}
Related
I have a UIViewController that is part of a UINavigationController and I want a custom view in my navigation bar. The code is then something like this:
class MyViewController: UIViewController
override func viewDidLoad() {
super.viewDidLoad()
self.customNavigationView = MyNavigationView()
self.navigationItem.titleView = self.customNavigationView
}
}
MyViewController and MyNavigationView are tightly coupled in a sense - they form a single piece of UI and only make sense when used together. I wonder what the preferred way to handle such cases is pattern-wise. In particular, what's the preferred way to send messages from MyNavigationView to MyViewController (such as buttons tapped).
I saw the following options:
Use a delegate pattern, create a MyNavigationViewDelegate protocol and add a delegate property to MyNavigationView. While the most object-oriented approach, it seems a bit "over-engineered" to me and has a lot of overhead for something that is basically a single unit of UI
Make MyNavigationView an inner class of MyNavigationController to indicate their strong relationship. Seems fine, but I like to have a file per class for easy navigation
Use a weak var myViewController: MyViewController? in MyNavigationView. I don't think the variable should be an optional, though, because semantically it is not
Use a let myViewController: MyViewController and a custom initializer in MyNavigationView that sets it. Seems the best option to me right now, but I'm not sure if it can create a memory leak since its a strong reference cycle
Thanks to #Mohsen Hossein pour: Sending notifications from MyNavigationView to MyViewController.
I wonder what other people's thoughts on this are. Is there are clear pattern that should be used here or is it a matter of taste?
While any answer to this question is ultimately opinionated in the MVP design pattern a view should not contain any business logic, just display logic. which means it should not know anything about its host.
The way I would approach it is to write the connection code and the interaction code in its host instead.
class MyNavigationView : UIView
{
var button : UIButton!
}
class ViewController : UIViewController
{
override func viewDidLoad() {
super.viewDidLoad()
self.customNavigationView = MyNavigationView()
self.navigationItem.titleView = self.customNavigationView
// here you can assign gesture recognizers or add event listeners
}
}
I would use a notification if you only need to know if something happened in the other view, it is easier and faster to implement, if you need more explanation on how to use notifications please ask and I can edit my answer and explain some more.
Everyone tells me "Use super.viewDidLoad() because it's just like that" or "I've been doing it always like that, so keep it", "It's wrong if you don't call super", etc.
override func viewDidLoad() {
super.viewDidLoad()
// other stuff goes here
}
I've only found a few topics about Objective-C cases and they were not so enlightening, but I'm developing in Swift 3, so can any expert give me a good detailed explanation on this?
Is it a case of just good practice or are there any hidden effects?
Usually it's a good idea to call super for all functions you override that don't have a return value.
You don't know the implementation of viewDidLoad. UIViewController could be doing some important setup stuff there and not calling it would not give it the chance to run it's own viewDidLoad code.
Same thing goes when inheriting from a UIViewController subclass.
Even if calling super.viewDidLoad doesn't do anything, always calling it is a good habit to get into. If you get into the habit of not calling it, you might forget to call it when it's needed. For example when subclassing a ViewController that depends on it from a 3rd party framework or from your own code base.
Take this contrived example:
class PrintingViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
print("view has loaded")
}
}
class UserViewController: PrintingViewController {
override func viewDidLoad() {
super.viewDidLoad()
// do view setup here
}
}
Not calling viewDidLoad here would never give PrintingViewController a chance to run its own viewDidLoad code
If you don't want to do anything in viewDidLoad just don't implement it. The super method will be called anyway.
I have a secret, when I worked at Apple I read the source code for UIKit, partly to answer questions I had like this, viewDidLoad is empty in all the UI*ViewController classes.
Naturally I am not there anymore, they may have changed this.
I think calling super.viewDidLoad() is, first of all, a good practice.
The usual thing in iOS is to do all of your subclass setups after the superclass has completed the setup that it needs to do (initializing properties, laying things out, etc.). If you don't give the superclass a chance to handle all of its setups before you start changing things around, it's possible you'll encounter some strange bugs and behavior.
We can draw a parallel with Class Initialization: "A designated initializer must delegate up to a superclass initializer before assigning a value to an inherited property." We're doing this to be sure that all superclass properties have a value and based on that fact we could safely use them through inheritance in our subclass.
Rule of thumb:
When initializing/setting up, run the superclass' implementations first.
When tearing down/cleaning up, run the superclass' implementation last.
Assuming that viewDidLoad() is some sort of initialization we should call super.viewDidLoad() first to correctly set things up in the superclass.
If we check the implementation of viewDidLoad() in UIViewController base class, we can see that it's empty. So maybe the only one reason to calling super.viewDidLoad() from you child class is a good coding style :-) Lets follow it!
That depends on the implementation of viewDidLoad in the class UIViewController (from which all view controllers inherit). If it's empty than calling super.viewDidLoad() won't do much. However if it has some functionality regarding the view controller then you certainly would want to use it.
Since it's not in your hands regarding the implementation of a UIViewController you should always call this method
When inheriting directly from UIViewController, call super when its documentation tells you to.
For example, viewWillAppear(Bool) says, "If you override this method, you must call super at some point in your implementation," whereas viewDidLoad() does not.
If you are not inheriting directly from UIViewController and the class you are inheriting from does not have reliable documentation, or may silently introduce a breaking change requiring that super be called, then always call super.
if your class is been inherited from UIViewController directly then there is no need to invoke super.viewDidLoad. This definately make your code look bit consice but usually iOS community suggest to call it anyway.
if your class is been inherited from custom UIViewController which indeed has some functionality which your class can leverage then invoke super.viewDidLoad.
I understand how to use delegation with iOS objects that already exist. For example, if I create an instance of a UITableView, and my view controller conforms to the UITableView delegate, I can implement the various methods of the UITableView delegate. My newly create table can receive notifications, for example, when didSelectRowAtIndexPath is called.
My question is why did my table get this particular delegate callback? My understanding is that the delegate is just a list of methods with no implementation. It seems to me there must be a lot more going on. What is really going on "behind the scenes"?
Image if I were to rename all the delegate methods to the following:
- mysteryMethod1
- mysteryMethod2
- mysteryMethod3... Etc
One of these methods is responsible for setting the height of a row at a particular index. Another one these methods will be responsible for editing a particular row.
Everything I read about delegation says the delegator makes a contract with the delegate. The delegate promises to implement the methods. When it does, somehow everything is wired up correctly and everything magically works. What is the magic that I'm not seeing?
I think that in order to know how delegates actually work you should create your own custom delegate first, that way you will see that there is no magic under the hood, you probably can't see the implementation of the actual apple build in delegate methods but I assure you that there is a lot of logic implemented in those but it's just not available for privacy reasons I assume.
When you create your custom delegate let's say for example...
You have Class A and in this class, you start by creating a protocol
protocol ClassADelegate: class {
func changeBackgroundColor(_ color: UIColor?)
}
In this class you have a delegate property like this.
weak var delegate: ClassADelegate?
Let's say that this class is a Viewcontroller and you have an IBACtion on it like a UIbutton, and your goal is that when you tap that button another ViewController in your app change its background color to blue. Inside this action in Class A you do this...
func someAction() {
delegate?.changeBackgroundColor(.blue)
}
,
Let's say that the "magic" happens here in class A, by the way if you are thinking in delegates using UITableview think that UItableView is class A.
ok so now you have Class B that is where you want to change the color right?
Well now class B needs to conform to the protocol like this, just like you also conform to the protocol UITableViewDelegate etc.
class ClassB: UIViewController, ClassADelegate {
}
Now think of the word delegate for a second and think what that means, you are just delegating responsibility to somebody else, right? and yes, in this case, ClassB is going to be the delegated, for that we need to have an instance of Class A in class B just to have access to it's delegate property.
let classa = ClassA()
classa.delegate = self
the final step is just to call the method of the protocol like this..
func changeBackgroundColor(_ color: UIColor?) {
view.backgroundColor = color
}
To conclude if yo see this method in your class but you don't have access to the implementation of the protocol, you will ask yourself "where does this magic color coming from??" but as you saw it just comes from another class where a protocol belongs to, hope this helps.
While trying to implement an extension for UIViewController I realise that there is no normal way, or is not allowed to override this functions (even when they are available for UICollectionViewController and UITableViewController):
extension UIViewController{
public override func viewWillAppear(){
super.viewWillAppear()
//do some stuff
}
}
I realise that there is no normal way, or is not allowed to override this functions (even when they are available for UICollectionViewController and UITableViewController):
viewDidLoad
viewWillLoad
viewWillAppear
viewDidAppear
There is some way to do this? I would like to have some implementation there and working for every UIViewController on my app... All in just one place.
Please, note that I don't want to make a new class subclassing
UIViewController, overriding those methods and making my controller to
extend it. This is the obvious and simplest solution, but this do not satisfy what I'm trying to do.
I'm using swift 1.2 in XCode 6.3
What you are trying to do is similar to what done by this code:
class MyClass {
func myFunc() {}
}
extension MyClass {
override func myFunc() {}
}
The 4 methods that you are trying to override are defined in UIViewController, and not to one of its superclasses. And you can't override a method which is defined in the same class.
Update
I can think of 2 different ways to solve the problem - the first is the one you don't want (subclassing UIViewController).
The other one is method swizzling - I never used it so I don't want to provide you inaccurate info. Maybe it's worth reading this article by Nate Cook, which incidentally is showing an example of replacing viewWillAppear.
I have about 8 view controllers in my app, and i have a function in each one that does the exact same thing. I was hoping to be able to condense it into one central function that can perform the task for all 8. The function would need to receive an instance of itself so that it could perform the task on the appropriate view controller, but since i have no idea which one is being passed i set the instance type as UIViewController *. That way, i'd be able to receive any of the view controllers. The problem is i have to execute a method from this method, and since each method is custom to those child classes to UIViewController and im PASSING UIViewController, i can't access the functions from the instance. Is there some way to do this? Access a child class method from an instance of the parent class? Here's some code:
- (void)changeIsFullscreen:(UIViewController *)viewController { // <-- Right here is the
// ^^^ instance of the class that's passed to the function. I
// can't pass the child because there are so many different
// children that will be using it.
if (isFullscreen == NO) {
[viewController setIsFullscreen:YES]; // Right here is the child
// class method that i need to call.
// They all have the method, and if they
// don't i could use try/catch blocks to
// catch the error if there was some way to do it.
} else {
[viewController setIsFullscreen:NO]; // Right here is the child
// class method that i need to call
}
}
I know one way to do this would be to extend UIViewController, create the method in THAT class, and extend all the other child view controllers from the new class i just extended. I don't know if that is the correct way to accomplish this task, though. Is it? Or should I do it another way?
I may be missing something obvious here, but if all of your view controller subclasses implement this method, it sounds like they should all derive from some intermediate class. So, you'd have a class that derives from UIViewController and implements -changeIsFiullscreen, and all of your view controllers are derived from that class.