简体   繁体   中英

Extensions with stored properties

I'm still learning Swift, and I'm trying to create an extension to add a placeholder to UITextView.

My idea for it is to create 2 UITextViews, one with a text as a placeholder, and when the user starts editing the text, it's actually hidden and the user is modifying the other UITextView.

However, my question here is not for having a placeholder in UITextView, but it's in regards of how-to use extensions to solve this problem.
My question is , what do I have to change in my implementation to create an extension that would look from the caller side as:
myTextView.placeholder("a placeholder text..")

So far, I have created it in my UIViewController, and need to move it to an extension, but I have a lot of stored properties, so it wouldn't work.

Here's my code:

import UIKit

class ViewController: UIViewController, UITextViewDelegate {


    let myTextView: UITextView = {
        let textView = UITextView()
        textView.tag = 0
        textView.backgroundColor = UIColor.yellow
        textView.layer.cornerRadius = 8
        textView.translatesAutoresizingMaskIntoConstraints = false
        return textView
    }()

    let textViewPlaceHolder: UITextView = {
        let textViewPlaceHolder = UITextView()
        textViewPlaceHolder.tag = 1
        textViewPlaceHolder.text = "Placeholder text.."
        textViewPlaceHolder.textColor = UIColor.lightGray
        textViewPlaceHolder.backgroundColor = UIColor.clear
        textViewPlaceHolder.translatesAutoresizingMaskIntoConstraints = false
        return textViewPlaceHolder
    }()


    func textViewDidChange(_ textView: UITextView) {
        myTextView.becomeFirstResponder()
        if textView.tag == 1 && (myTextView.text != nil || myTextView.text != "") {
            textView.isHidden = true
            textViewPlaceHolder.resignFirstResponder()
        } else if textView.tag == 0 {
            if myTextView.text == nil || myTextView.text == "" {
                textViewPlaceHolder.becomeFirstResponder()
                myTextView.resignFirstResponder()
                textViewPlaceHolder.isHidden = false
                textViewPlaceHolder.text = "Placeholder text.."

            }
        }
    }

    func textViewDidBeginEditing(_ textView: UITextView) {
        DispatchQueue.main.async {
            self.textViewPlaceHolder.selectedRange = NSMakeRange(0, 0)
        }
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        view.backgroundColor = UIColor.lightGray
        view.addSubview(myTextView)
        textViewConstraints()
        view.addSubview(textViewPlaceHolder)
        myTextViewPHConstraints()

        myTextView.delegate = self
        textViewPlaceHolder.delegate = self

    }

    func textViewConstraints() {
        myTextView.widthAnchor.constraint(equalTo: self.view.widthAnchor, constant: -16).isActive = true
        myTextView.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
        myTextView.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
        myTextView.heightAnchor.constraint(equalToConstant: 200).isActive = true
    }

    func myTextViewPHConstraints() {
        textViewPlaceHolder.widthAnchor.constraint(equalTo: self.view.widthAnchor, constant: -16).isActive = true
        textViewPlaceHolder.centerXAnchor.constraint(equalTo: self.view.centerXAnchor).isActive = true
        textViewPlaceHolder.centerYAnchor.constraint(equalTo: self.view.centerYAnchor).isActive = true
        textViewPlaceHolder.heightAnchor.constraint(equalToConstant: 200).isActive = true
    }

}

As I mentioned above, I'm still learning Swift and this question is not for solving a very specific problem, it's more than that, it's meant to learn how to solve problems in Swift extensions.

Note: Don't use the code above to solve placeholder problem as it's no perfectly working.

You can do something like this:

extension UITextView {

    private struct AssociatedKeys {
        static var placeholder = "placeholder"
    }

    var placeholder: String! {
        get {
            guard let placeholder = objc_getAssociatedObject(self, &AssociatedKeys.placeholder) as? String else {
                return String()
            }

            return placeholder
        }

        set(value) {
            objc_setAssociatedObject(self, &AssociatedKeys.placeholder, value, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
}

It's impossible to access stored properties directly in extension. Create a global class aside, call your global class in you view controllers and in your extension. There you can see all stored variables inside in your extension.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM