Custom UIView not appearing on ViewController

Hi

I have a custom UIView contained xib which is in an xcframework. The view has a timeout property which removes itself from the super view if it expiries.

If the view does expiry, it fires a delegate which the function can observe using the KVC approach.

What I'm experiencing is my function adds the view to the view controller ok, but doesn't display it until the function completes or throws an error.

Here is a snippet of what I have described:

// MARK:  Contained in custom xcframework
class MyView: UIView {
   var delegate: VerificationHandler?
   
   required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        initialize()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        initialize()
    } 

   func initialize() {
     let bundle = Bundle(for: type(of: self))
     let uvNib = UINib(nibName: String(describing: type(of: self)), bundle: bundle)
     let uvView = uvNib.instantiate(withOwner: self, options: nil).first as! UIView
     
      addSubview(uvView)

      Timer.scheduledTimer(withTimeInterval: TimeInterval(10), repeats: false) { [self] timer in
            timer.invalidate()
            delegate?.verification(didContinue: false)
            removeFromSuperview()
      }
   }
}

protocol VerificationHandler {
   func verification(didContinue: Bool)
}

class VerificationResult: NSObject {
    @objc dynamic var value: Bool
    init(_ value: Bool) {
        self.value = value
    }
}

public enum MyEnum {
}

public extension MyEnum {
   private static var verificationResult: VerificationResult = VerificationResult(false)

   public static func myFunction(_ viewController: UIViewController) throws -> MyObject {
     if let viewController = viewController {
       let view = MyView(frame: viewController.view.frame)
       view.delegate = self as? VerificationHandler
       viewController.view.addSubview(view)

         let semaphore = DispatchSemaphore.init(value: 0)
        
       // observe the change occurring in the view which creates the verificationResult.
       var result: Bool
       let kvc = verificationResult.observe(\.value, options: .new)  { _, change in
        result = change.newValue!   // didContinue
        semaphore.signal()
       }

       semaphore.wait()
       
       if !result {
           throw MyError.timeout
       }

       return MyObject(...)
   }
}

extension MyEnum: VerificationHandler {
    func verification(didContinue: Bool) {
        MyEnum.verificationResult = VerificationResult(didContinue)
    }
}


// MARK: View controller app code
class ViewController: UIViewController {
   override func viewDidLoad() {
      super.viewDidLoad()
   }

   @IBAction func onClick(_ sender: UIButton) {
      do {
         // this call is where the custom view from the xcframework should appear
         let result = try MyEnum.myFunction(self)
      }
      catch let error {
         print(error.localizedDescription)
      }
   }
}

I'm using the semaphore to wait for the timer in MyView to fire which would cause the KVC to invoke. Not sure if this is the best way, but I'm blocked and can't figure out why the view only appears after an Error is thrown from myFunc.

Any guidance appreciated.

Answered by Frameworks Engineer in 679412022

I assume myFunction is called on the main thread as it is modifying UIKit. So the semaphore you add blocks the main thread from continuing until your timer fires. You are essentially stopping all UI changes until your timer fires as the main thread is blocked.

Accepted Answer

I assume myFunction is called on the main thread as it is modifying UIKit. So the semaphore you add blocks the main thread from continuing until your timer fires. You are essentially stopping all UI changes until your timer fires as the main thread is blocked.

Custom UIView not appearing on ViewController
 
 
Q