How to pass UIControl as a function parameter? - ios

For example, I have one function. In this function as a parameter I have to pass some UIControl like UILabel, UITextFile, UIButton, etc. How can I do this:
func passDicData(controll : UIControll){
//code
}
Used like:
passDicData(UILabel)

//Use UIView
func passDicData(control:UIView){
//code
}
passDicData(UILabel(frame: .zero))

It is UIControl, not UIControll.
Moreover, the common ancestor of the UILabel, UITextField, and UIButton is UIView, see for example this scheme.
func passDicData(view: UIView){
//code
}

You can use this way,
func passDicData(control: AnyClass){
print(control.class())
}
and call it like this way,
passDicData(control: UILabel.self)

Yes, you can use UIControl as a parameter:
func passDicData(controll : UIControl){
//code
}
However, you will NOT be able to call this function like this:
passDicData(UILabel)
That's because
In your example, you are not creating an instance of an UILabel, you are just using its type. In order to pass the instance you should initialize an UILabel first, e.g., passDicData(UILabel())
UILabel is not a subclass of UIControl
Instead you could use UIView or UIResponder, both of them are super classes of UILabel
func passDicData(responder : UIResponder){
//code
}
passDicData(UILabel())

Related

Add custom functionality to UITextField, UILabel, UIView custom classes

In my app I have some interface elements such as :CustomLabel, CustomView, CustomTextField (all are custom classes inherit from their base class: UIView, UILabel, UITextField.
At this moment I'm calling from each element DrawRect callback to a function that draws underline on itself and basically I have chunks of duplicated code on each subclass.
How can I make this three subclasses have the same DrawRect content without creating an extension of UIView because I don't want each View or subclass of UIView to have this behaviour.
For this you could use a protocol and a protocol extension to add your common methods to your subclasses. Then you'd only have to make your classes conform to that protocol and override drawRect to call the methods from your protocol. Adding the new behaviour by just conforming to the protocol and not doing any other changes is not possible, unfortunately. You can't override methods in protocol extensions, and you can't add methods that use the Objective-C runtime there either which would allow method swizzling.
In code this would look something like this:
protocol CustomDrawing {}
extension CustomDrawing where Self: UIView {
func myDrawingCode() {
// Whatever
}
}
You use it like this then:
class CustomLabel: UILabel, CustomDrawing {
override func draw(_ rect: CGRect) {
super.draw(rect)
myDrawingCode()
}
}
If you need to access some common property or method in myDrawingCode() you will have to declare them inside the CustomDrawing protocol. UIView methods are available since the protocol extension is constrained to UIView and subtypes.

Override UI element .enabled property in Swift

I want to override property of UIView class to do extra lines of code each time property value of .enabled is changed. How do I do that?
For example:
There is MyUIView class myClass
There is myClass.enabled property
I want to override this to add next things
Edit subview of type UIView and set background to red colour if enabled/green if disabled.
Edit subview of type UIButton and make it disabled if disabled/enabled if enabled.
The code will look something like this -
class SubClass: UIView {
override var userInteractionEnabled: Bool {
didSet {
// Do the color change and other stuff.
// Use oldValue to access old value
}
}
}
There is much more to explore about this setter and getter.

Subclassing UIView

I see this topic is discussed elsewhere but I don't see an answer to my questions.
I subclassed UIView to create a custom view. Currently I'm using interface builder to create a UIView and then setting the custom class option to my subclass.
First question. When I do that, how to I reference that instance from my code? I have a public function I would like to call that updates my view but I don't know how to call it from my view controller
Second question. I created an instance of the class from within my view controller just playing around and I noticed the public function I created isn't available with that instance. Can I create public functions when I inherit from UIView?
It is easy to do:
1)subclass UIView to create CustomView, add your public function,in your project:
import UIKit
class CunstomView: UIView {
/*
// Only override draw() if you perform custom drawing.
// An empty implementation adversely affects performance during animation.
override func draw(_ rect: CGRect) {
// Drawing code
}
*/
public func printHello() {
print("hello")
}
}
2)In your storyboard, drag a UIView into your vc, and set the class to CunstomView, you can see that in my red frame:
3)click the Show the Assistant Editor, and ctrl-drag the view to the vc, set the name custom:
4)then in your vc's viewDidload function, you call the public function:
import UIKit
class ViewController: UIViewController {
#IBOutlet weak var custom: CunstomView!
override func viewDidLoad() {
super.viewDidLoad()
custom.printHello()
}
}
5)the result:
First question. When I do that, how to I reference that instance from
my code? I have a public function I would like to call that updates my
view but I don't know how to call it from my view controller
A: A view cannot exist by itself in app. You need viewcontroller to handle the custom view. Then in that VC, you can refer the view as IBOutlet.
Second question. I created an instance of the class from within my
view controller just playing around and I noticed the public function
I created isn't available with that instance. Can I create public
functions when I inherit from UIView?
A: You can create public function of custom view, just declare them in the header file. Then import the header in your VC. Then u can access it.
You can try to update your view from IB with the mothod below.
Objective-C:
-(void)awakeFromNib {
[super awakeFromNib];
//do something
}
Swift
override func awakeFromNib() {
super.awakeFromNib()
}
Second question
Do you mean the custom view don't answer the function you create within the view controller?

Accessing uibutton action from a different class Swift

I have an UITableView that is loaded from two custom cell xib files.
The second one contains an UIButton.
But since i've added the custom class for xib - it has its own actions and functions, which i cannot access from ViewController.
My goal is to apply some action on UIButton when the custom cell is loaded in the tableview.
My function is defined in ViewController (because all variables are there) and my UIButton action is defined in Custom class for xib.
How do i connect one to another?
Thank you
Here is the solution in swift
If you want to perform action in another class when an event takes place in another class, then you have to use Protocols in your code, so that you can perform the action in another class.
For example
Declare your protocol like this before the class interface
protocol MyDelegateClass {
func btnAction()
}
Define your protocol in the interface of your class like this
var MyDelegateClass! = nil
Now on your button action trigger the protocol like this
#IBAction func btnProtocolAction(sender: AnyObject) {
[delegate btnAction];
}
Now include the protocol in the class like this
class myActionClass: UIViewController, PopUpViewDelegate {
Now assign the protocol to the MyDelegateClass object like this
myProtocolObject.delegate=self
Also define the class which you have declared in MyDelegateClass like
func btnAction() {
print(#"This method will triggered");
}
Hope this helps you.
You can achieve this by simply posting a notification.
NSNotificationCenter.defaultCenter().postNotificationName("buttonClickedNotification", object: nil)
Post this notification from your button method in custom class. You can also pass any data by using object parameter (Here it is nil).
And observe the notification in your viewController.
NSNotificationCenter.defaultCenter().addObserver(self, selector: "buttonClicked:", name: "buttonClickedNotification", object: nil)
And implement buttonClicked() method in your viewController.
func buttonClicked(data: NSNotification)
{
//If any data is passed get it using
let receivedData:NSDictionary = data.object as! NSDictionary //If data is of NSDictionary type.
}
Write a delegate method. This will connect your ViewController and Custom Class. What have you tried already?

Swift - Access IBOutlet in other class

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
}

Resources