Forcing all UIKit stuff to be done in the main thread

Viewed 462

I am doing a complex application that has to do stuff on a lot of threads and frequently update the interface.

So I have to add a lot of

  dispatch_async(dispatch_get_main_queue(), ^{

  });

in the middle of the code to dispatch UI updates to the main thread and I find it ugly and disruptive as hell.

So, I have this idea of creating subclasses of elements like UILabel, UITextField, etc., overriding their main thread methods like this:

- (void)setAttributedText:(NSAttributedString *)attributedText {
  dispatch_async(dispatch_get_main_queue(), ^{
    [super setAttributedText:attributedText];
  });
}

- (void)setText:(NSString *)text {
  dispatch_async(dispatch_get_main_queue(), ^{
    [super setText:text];
  });
}

- (void)scrollRangeToVisible:(NSRange)range {
  dispatch_async(dispatch_get_main_queue(), ^{
    [super scrollRangeToVisible:range];
  });
}

but again, I have to have this same code scatter all over these classes.

Is there a better way?

1 Answers

I think your problem is arising because you are tightly coupling your computation to your UI. You can look at alternate architectures, such as MVVM, although formally adopting this architecture works best when you have a binding framework.

Even without a binding framework you can improve your situation by introduction some model properties with some setter/getter code to work with the actual UI element.

For example, declare a pair of properties, one for the text field and one for the text

@property (weak, nonatomic)  UITextField *someTextField;
@property (strong, nonatomic) NSString *someText;

Now, implement setter and getter methods to couple them:

-(NSString *)someText {
   return self.someTextField.text;
} 

-(Void *)setSomeText: (NSString *)newValue {
    dispatch_async(dispatch_get_main_queue(), ^{
        self.someTextField.text = newValue
  });
}

Now, this is a pretty simple example, and has a slight issue in that immediately retrieving the value of someText after setting it won't return the value that was just set due to the asynchronous nature of the set operation, but that shouldn't be an issue in most cases. It does demonstrate how you could start to decouple the data model from the UI elements and so separate concerns with data from concerns with the mechanics of updating UI elements.

Related