I'm using tableview in all classes of my project. I just want to remove some default property like table bouncing to all tableview. Instead of remove it in each and every class, is there any option to write single line code that reflects for tableview in all class?
You can use Extension like this.
extension UITableView{
func setTableViewBasicProperties(){
self.backgroundColor = UIColor.gray
//tableview's other propeties
}
}
and simply call method into your ViewController:
yourtableView.setTableViewBasicProperties()
You can extend UITableView class and modify the properties as well as add some methods for added functionality.Extensions add new functionality to an existing class, structure, enumeration, or protocol type. This includes the ability to extend types for which you do not have access to the original source code.
You can extend UITableView as
extension UITableView{
func configureTableView(){
self.alwaysBounceVertical = NO;
//modify other propeties of UITable View
}
}
Now you can set these properties to each of tableview in any class as
self.yourtableView.configureTableView()
Related
I have two main screens in my app, currently both just subclasses of UIViewController. These two view controllers are very similar - they both implement my custom subclass of UIView called HeaderView that is responsible for displaying information and taking user input. As it stands, this code is repetitive because the HeaderView setup is the same for both view controllers - the only difference is what happens when the user confirms the text entry in HeaderView.
To cut down on repetitive code, I am creating a class called InputViewController (a subclass of UIViewController) that houses the aspects of the two view controllers that are identical. Eventually, I want the two view controllers to subclass InputViewController instead of UIViewController.
class InputViewController: UIViewController, InputProtocol {
private let headerView = HeaderView()
override func viewDidLoad() {
super.viewDidLoad()
// layout, etc.
setupCallbacks()
}
internal func setupCallbacks() {
headerView.onUpdate = { (text: String) in
// called when user confirms text entry in headerView
self.onHeaderUpdate()
}
}
internal func onHeaderUpdate() {} // Blank function
}
setupCallbacks() and onHeaderUpdate() are methods defined in the protocol that the InputViewController conforms to. The HeaderView implements a callback closure that is handled in setupCallbacks() by headerView.onUpdate...
The protocol that InputViewController conforms to:
protocol InputProtocol {
func setupCallbacks()
func onHeaderUpdate()
}
To illustrate this, I drew up a diagram;
Since I want the subclasses of InputViewController to override the onHeaderUpdate() method, is it conventional to leave the definition of onHeaderUpdate() in InputViewController blank or is there another solution to this?
is it conventional to leave the definition of onHeaderUpdate() in InputViewController blank
Yes, that is called an abstract method. It is common to give it code that crashes deliberately, as a way of saying, “I exist only to be overridden in a subclass.”
(I should go further and say that what you are creating, a base view controller that carries out initial configurations that all subclasses must implement, is also normal.)
Recently I wrote an app with one single scene and ViewController. I had to set a custom background picture for the View, which the ViewController manages (i.e. my top view contained the UIImageView). Later on I had to implement some logic in ViewController, so that it properly rotates/changes the picture when the screen is rotated. Also I had to overwrite some properties like preferredStatusBarStyle for the ViewController.
Now I have to implement a couple more scenes / screens in my app and it turns out that they all must have the same design as this currently present screen, so I think it makes sense if I create a CommonViewController which contains this common rotation-related logic for background picture, so that I can inherit all my other ViewControllers from this CommonViewController. The only problem I have is that CommonViewController "requires" that the view it manages has a backgroundPicture: UIView property, which I don't know how to ensure.
If I create a new file CommonViewController together with XIB-file, I can add the backgroundPicture image view in XIB and connect it with code (via regular "control-drag" approach), but apparently this won't work, as there is no guarantee that the views which inherit CommonViewController will have this property. What is the correct way to solve this issue without hacks on iOS in Swift?
Unfortunately I could not find a solution, maybe I've been searching for something wrong. It seems that I somehow need to inherit a CommonViewController for each scene (for each CustomViewController), but also I have to somehow set the top view of each of these controller's to be equal to some CommonView, so that CommonViewController does not crash when I try to access #IBOutlet weak var backgroundPicutre: UIImageView!.
The obvious way would be to define some method or property in the CommonViewController, so that the controllers which inherit it, can implement / override it, but it seems a bit hacky as it still requires copy-pasting in each ViewController which inherits CommonViewController.
How I imagined the solution: I create CustomViewController: CommonViewController, then I create a view controller in my Storyboard and change the "Class" property to "CustomViewController" (in property editor), then I select the view which corresponds to this newly added controller and change the "Class" property to "BackgroundImageView. But I'm not sure if it's the correct way to do (also I doubt thatCustomViewControllerwill properly "connect" itsIBOutletfieldbakcgroundImageViewwith the correspondingUIViewfromBackgroundImageView`, that's why I wanted to ask experts what they think about it.
I think you should define your base controller (CommonViewController) entirely in code, i.e. don't use no xibs / storyboards for the base controller. It doesn't mean you should rid off storyboards / xibs completely. Interface for alll other view controllers except CommonViewController may still be implemented with xibs / storyboards.
In this case CommonViewController implementation may look like this:
import UIKit
class CommonViewController: UIViewController {
// use this property every time you need to
// manipulate backgroundPicture
var backgroundPicture: UIImageView = {
// Replace with your image name
let image = UIImage(named: "BackgroundPicture")!
let imageView = UIImageView()
imageView.image = image
return imageView
}()
override func viewDidLoad() {
// If subclass overrides viewDidLoad()
// it should contain super.viewDidLoad()
super.viewDidLoad()
view.addSubview(backgroundPicture)
// Align backgroundPicture to bounds of superview
// You can remove this code and implement
// your own alignment with frames or Autolayout
backgroundPicture.frame = view.bounds
// Send backgroundPicture to back of the view
// Otherwise backgroundPicture may overlap views added in subclasses
view.sendSubviewToBack(backgroundPicture)
}
override func viewDidLayoutSubviews() {
// If subclass overrides viewDidLayoutSubviews()
// It should contain super.viewDidLayoutSubviews()
super.viewDidLayoutSubvews()
// Align backgroundPicture to bounds of superview
// You can remove this code and implement
// your own alignment with frames or Autolayout
backgroundPicture.frame = view.bounds
}
}
Anyone know why can't I access the variable 'sendTitle' in prepareForSegue from didSelectRowAtIndexPath? I saw some of the tutorials, they are doing the same thing with me, I've no idea why mine got error.
--What I'm doing now is passing value from tableView cell to another view controller.
I'm using Xcode 7 Swift 2.1
you have to declare sendTitle inside your class to make it visible to all methods. Something like follows.
import UIKit
class viewController: UITableViewController {
var sendTitle:String = ""
override func viewDidLoad() {
super.viewDidLoad()
}
//table view delegate methods
// just use sendTitle = cell.lblTitle.text!
}
Because it is declared privately in your didSelectRowAtIndexPath method. It won't be accessible outside of those function. if you want to access it from another function, declare it as global variable in your view controller.
I need your advice.
I have a screen with a table view and I'm using a separate file for UITableViewDataSource.
What I need is to be able to access the UITabBarItem inside my UITableViewDataSource (because based on the action on my tableview, I will update my tableview data, so I need to change something on my tabbar)
Any idea ?
Thanks.
To separate my datasource, in my controller I have:
var toPayDatasource: MyDataSource!
....
tableView.dataSource = mDatasource
tableView.delegate = myDatasource
And my datasource:
class MyDataSource: NSObject, UITableViewDataSource, UITableViewDelegate {
...
}
C.C.
One common mechanism for sending a message between two objects that are otherwise far apart is to use NSNotificationCenter. You can define a custom event and pass along whatever you need to update the tab bar item in the userInfo dictionary.
Since your datasource is separate you can create a Delegate for the view controller and pass it to the data source. Something like the following (right after setting data source for the tableView):
mDataSource.tabDelegate = self;
And declare / define the delegate the following way:
// protocol
protocol TabChangerProtocol {
// function signatures here
}
// data source
class MyDataSource : /* ... */ {
var tabDelegate : TabChangerProtocol!;
// rest here
}
// view controller
class ViewController : TabChangerProtocol, /* ... */ {
// ...
}
That way you can call the protocol functions from inside MyDataSource.
P.S Sorry for all the 3 dots. Typing code on mobile is annoying.
I have a UIView with a TableView and a Button (Big Button). The TableView has a custom Cell. In this cell there is an "Add" button. I want to animate the first button when the user makes click on the Add button.
This is my schema:
This is my code:
class ProductsViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
#IBOutlet var tableView: UITableView!
#IBOutlet var bigButton: UIButton! <- I WANT TO ANIMATE THAT BUTTON
}
ProductCell class
class ProductCell: UITableViewCell {
#IBAction func addProduct(sender: AnyObject) {
//I WANT TO ACCESS THE BIG BUTTON FROM HERE
}
}
Screen example of my app
I've tried to get the parent controller or the superview to get the IBOutlet but the app is crashing allways
Add block properties to your cells which lets them notify your view controller when they have been clicked. In your view controller block code, you can then access the big button.
See my answer to a similar question. Simply replace the switch example with your button. So replace UISwitch with UIButton.
How can I get index path of cell on switch change event in section based table view
So rather than have the cell try and talk to another cell/button, have the cell notify the controller which can then manage the big button changes.
Although I made a comment about using alternate methods you could also employ a strategy below based on updates to a property stored in the current view controller class. You could just as well use property observation on the ProductsViewController but I assume you'd like to keep OOP focused and reduce the size of your controller.
Subclass the ViewController
One could subclass an existing UIViewController and then create a property in the super class that deals with the value that was changed (row tapped). In that subclass you could then do some animation. Because you would be subclassing you continue to obtain all the benefits and methods defined in your existing controller. In your identity inspector point your Class to the new subclass and create any functional updates to your UI using animation.
class ProductsViewController:... {
var inheritedProperty:UIView = targetView {
willSet {newValue } // is the newValue
didSet {oldValue} //is the old value
}
}
class AnimatedProductsViewController:ProductsViewController {
override var inheritedProperty:UIView {
//do something interesting if the property of super class changed
willSet {newValue } // is the newValue
didSet {oldValue} //is the old value
//you might want to call this method like so
// didSet { animate(newValue) }
}
func animate (view: UIView){
//do animation routine using UIView animation, UIDynamics, etc.
}
}
Property Observation
Whenever the didSelectCell... method is called just set a value to the inheritedProperty. Then add the property observers (see sample code) and react when the property changes (maybe pass a reference to the view you want to animate).
For example: Within the property observer you can just take that view and pass it to your animator function (whatever is going to do the animation). There are many examples on SO of how to animate a view so just search for (UIView animation, UIDynamics, etc).
The normal benefits of separation are encapsulation of functionality and reuse but Swift also guarantees that each set of property observers will fire independently. You'd have to give some more thought to this as to its applicability in this use case.
Do all this things in your viewController
Add target Method to cell's add button in cellForRowAtIndexPath Method
Like This
cell.add.addTarget(self, action: "addProduct:", forControlEvents: UIControlEvents.TouchUpInside)
Define method
func addProduct(button:UIButton)
{
// do button animation here
}