I have a function that use very common on every UIViewController
func backPreviousScreen() {
self.navigationController?.popViewControllerAnimated(true)
}
Is anyway that I don't have to write detail that function above on each UIViewController ?, just need some method like I can inherit it, and use it in all UIViewController ?
You can create a protocol and add extension to it:
protocol Dismissable {
}
extension Dismissable where Self: UIViewController {
func backPreviousScreen() {
self.navigationController?.popViewControllerAnimated(true)
}
}
Now just mark the view controller class with this protocol and you are ready to go:
class MyViewController: UIViewController, Dismissable {
}
Create a BaseViewController with the method in it, then all of your viewcontrollers can inherit from it, thus all having the function
Instead of create base class method, Create a UINavigationController Extension. Which is you can use any where in your application.
import UIKit
import Foundation
extension UINavigationController
{
func backPreviousScreen (){
self.popViewControllerAnimated(true)
}
}
Use as follow self.navigationController.backPreviousScreen()
The idea of using a protocol is good, but i would recommend you to just create a class called BaseViewController that extends UIViewController like this
#interface BaseViewController : UIViewController
-(void) backPreviousScreen;
Then you can use it in any other controller like this
#import "BaseViewController.h"
#interface LoginViewController : BaseViewController
This was you can put functions, objects and everything you want and just call
[super backPreviousScreen];
from any of your subclasses
I recommend using this method and not the protocol because this way you can even create outlets easily since the storyboard and nibs recognise the base class and let you to create outlets that you can later access as well using
[super.someTextField setText:#"Some Text"];
Related
An object of UIView or subclass of UIView and comforms to UITableViewDelegate protocol.
I need a generic type rather than a spesific type. So that developer who use it can define a freely. The oc code we can do like this:
#property (strong) UIView<SomeDelegate> *contentView;
I am thinking you are just looking for something like this
class MyView : UIView, UITableViewDelegate {
}
You will most likely have to add UITableViewDatasource protocol as well
Best practice you can use extension method for Current Class along with delegate or datasource:
class MyView : UIView {
}
extension MyView: UITableViewDelegate,UITableViewDataSource
{
}
I'd like to do this:
UIView <UITextFieldDelegate>*
in swift.
Making an object that subclasses UIView also conform to the UITextFieldDelegate protocol.
You can express (id <UITextFieldDelegate, UIScrollViewDelegate>) using Protocol Composition
but not (UIView<UITextFieldDelegate> *). except for class definition.
// Obj-C
- (void)methodName:(id <UITextFieldDelegate, UIScrollViewDelegate>)arg { ... }
// Swift
func methodName(arg:protocol<UITextFieldDelegate, UIScrollViewDelegate>!) { ... }
Actually, an Obj-C method declared as - (void)methodName((UIView<UITextFieldDelegate> *))arg;, when it's bridged to Swift, you can call with any UIView instance.
EDIT:
After a little research, it seems you can declare your func like this
func myFunc<T:UIView where T:UITextFieldDelegate>(view:T) { ... }
Make a sub class of UIView and let the SubClassedView conforms to UITextFieldDelegate
In traditional way
#interface SubClassedView:UIView <UITextFieldDelegate>
#end
in swift
class SubClassedView:UIView, UITextFieldDelegate {
}
I've done some reading on here about passing data back from view controllers and I know that there are some definitely no-no's about this, but I wanted to inquire about a best practice for passing data in this manner and ask if what i'm doing below is ok?
I have 3 view controllers (classes ViewControllerA, B, and C) and when the user clicks a button (from either A, or B) it takes them to C using this:
let vc = new ViewControllerC()
self.presentViewController(vc, animated: true, completion: nil)
Passing data forward
So 'self' above is either A, or B. My thought was if I wanted to send C some info, I could just make a property of C (such as a string or int, etc, etc) and assign it above just before I do a presentViewController. Is that right?
i.e.
vc.propertyHere = "my value"
Passing Data Back
if something happened in C that I'd like to send back to A or B, what is the best practice?
To return back to A or B I know I can do this:
self.dismissModalViewControllerAnimated(true)
Should I first instantiate A or B (maybe by their base type) and access a similar property for the information I'd like to pass back? For example if A and B both inherit from some class, I could make a property on that class and just access / set it from C. Is that the right move? Or is there a better approach?
i.e.
callingViewController.myProperty = "my value i'm passing back"
Thanks!
Passing Data forward - Your implementation is good.
Passing Data Back -
Dont initiate A and B again, its a common mistake I see with new developers. A or B already exists, you came to this new controller from A/B and you just want to pass a value back to that class.
The best practice to use here is delegate design pattern.
Steps:
Create a protocol declaring the a method to call in A/B.
Implement a property in C named delegate.
Before presenting the view C, assign the delegate.
Whenever you want to pass any info to A or B call the delegate method.
Implementing delegate is explained in another SO answer here : How do I create delegates in Objective-C?
For downhill theres technically nothing wrong with your proposal of setting a property on the view controller
vc.propertyHere = "my value"
but theres a pattern called Dependancy Injection which provides a much cleaner conversation between the parent and the child.
So if your new view controller requires something to function you give it to the instance at init.
import Foundation
import UIKit
class ObjectTypeA {}
class ObjectTypeB {}
class FooVC : UIViewController {
var importantThing:ObjectTypeA!
var otherImportantThing:ObjectTypeB!
init(somethingINeed:ObjectTypeA, somethingElseINeed:ObjectTypeB) {
importantThing = somethingINeed
otherImportantThing = somethingElseINeed
super.init(nibName:nil,bundle:nil)
}
}
class BarVC : UIViewController {
func yo() {
let object1 = ObjectTypeA()
let object2 = ObjectTypeB()
let newVC = FooVC(somethingINeed: object1, somethingElseINeed: object2)
self.presentViewController(newVC, animated: true, completion: nil)
}
}
So keep doing what you are doing but look at other patterns in the future.
For passing data or events uphill a delegate pattern as described by others is best. That way there is no tight coupling between the parent and child. Any object which adopts the protocol can be the delegate.
e.g
class BlueSuedeShoes{}
protocol FunkyProtocol {
func danceLikeElvis(shoes:BlueSuedeShoes)
}
class LumpyVC:UIViewController {
var delegate:FunkyProtocol?
func somethingHappened() {
let myShoes = BlueSuedeShoes()
self.delegate?.danceLikeElvis(myShoes)
}
}
and a class which implements that protocol
class SmoothVC:UIViewController,FunkyProtocol {
func danceLikeElvis(shoes: BlueSuedeShoes) {
dontStepOn(shoes)
}
func dontStepOn(shoes:BlueSuedeShoes) {
}
}
You can use delegation pattern to achieve this. Here is an little example ,please see.
#protocol SecondViewControllerDelegate;
#interface SecondViewController;
SecondViewController : UIViewController
#property (nonatomic, assign) id<SecondViewControllerDelegate> delegate;
#property (nonatomic, retain) NSArray* someArray;
#end
#protocol SecondViewControllerDelegate
- (void)secondViewControllerDidFinish:(SecondViewController*)secondViewController;
#end
SecondViewController.m:
#implementation SecondViewController
#synthesize delegate;
#synthesize someArray;
- (void)dealloc
{
[someArray release];
[super dealloc];
}
- (void)someMethodCalledWhenUserIsDone
{
[delegate secondViewControllerDidFinish:self];
}
FirstViewController.h:
#import SecondViewController
#interface FirstViewController : UIViewController <SecondViewControllerDelegate>
{
...
}
#end
FirstViewController.m:
#implementation FirstViewController
- (void)secondViewControllerDidFinish:(SecondViewController*)secondViewController
{
NSArray* someArray = secondViewController.someArray
// Do something with the array
}
#end
Maybe it is not possible but here is my question:
I need to execute the same method on all the ViewControllers, precisely on the viewDidLoad or on the viewDidAppear methods.
Is there any way on the AppDelegate or somewhere of doing this apart from calling this function from every single controller?
Try this,
Create a BaseViewController
#interface BaseViewController : UIViewController
and create all other ViewControllers by subclassing BaseViewController
#interface AViewController : BaseViewController
and do ypu stuff in viewDidLoad or on the viewDidAppear of BaseViewController
Here is a simple approach to do this. Follow OOPS & make the use of inheritance like this.
Make a baseViewController & add two methods for example.
btBaseViewController.h
#interface btBaseViewController : UIViewController
#end
-(void)renderPadUI;
-(void)renderPhoneUI;
Provide a no-op definition for these two methods.
btBaseViewController.m
-(void)renderPhoneUI {
// to be overridden by derrived classes
}
-(void)renderPadUI {
// to me overridden by derrived classes.
}
And in viewDidLoad do something like this
if(IS_IPAD) {
[self renderPadUI];
}else{
[self renderPhoneUI];
}
Now Sub class your ViewControllers from this btBaseViewController class as
btHomeViewController.h
#interface btHomeViewController : btBaseViewController
#end
Now if you do not provide the definition of methods renderPhoneUI and renderPADUI btHomeViewController the base version will be executed.
Thats simple.
I'm guessing making a UIViewController subclass that does what you do and make every controller of your app of that new subclass type.
MyUIViewController.h
#interface MYUIViewController : UIViewController
#end
MYUIViewController.m
#implementation MYUIViewController
- (void)viewDidLoad
{
[super viewDidLoad];
[self myMethodCall];
}
And then, every UIViewController that needs to execute this method, should be of MYUIViewController type.
You can define the method in the app delegate or you can make a subclass of a UIViewController
I have two UIViewController sublcasses, both of them conform to the UITextFieldDelegate protocol. IOW, I have these classes.
# MyVC1.h
#interface MyVC1 : UIViewController <UITextFieldDelegate>
# MyVC1.m
#interface MyVC1 () {
// Private variable, so not a property
UITextField *_myTextField;
}
#end
#implementation MyVC1
- (void)viewDidLoad
{
_myTextField = [self textFieldwithPlaceHolderText:#"*Text"];
}
#end
SAME CODE for MyVC2 class, except of course the class name.
However, and this is the strange part, my code compiles for MyVC1, but NOT for MyVC2. For MyVC2, compiler says "No visible #interface for "MyVC2" declares the selector "textFieldwithPlaceHolderText". What am I missing for MyVC2? I've double- and triple-checked!
Like Jsdodgers said, textFieldwithPlaceHolderText is not a method of UITextFieldDelegate. Check your #imports section on both controllers - maybe VC1 imports a category for UIViewController class that adds that method to it. A category import would look like this: #import "UIViewController+_.h"
Ok, it's late, and I'm sleepy. MyVC1 defines the textFieldwithPlaceHolderText method, but NOT MyVC2. I cut/past the viewDidLoad section, but forgot to cut/paste the method. Sorry to waste your time.
copy the method "textFieldwithPlaceHolderText" in myVc2.h in interface a
and implement in myvc2.m if i post anything wrong sorry for that