UITextView ios16 beta textView.attributedText = attributedText not working

Is there any special optimization for UITextView? UITableViewCell is using UITextView, when the cell is reused, the same textView and the same attributedText, textView.attributedText=attributedText not working, must first perform the textView.attributedText=nil operation, will this problem be fixed in the subsequent ios16 system?

  • Could you show the code ?

Add a Comment

Replies

textView.attributedText=attributedText is intended to always work, there should be no need to clear out the text with nil as in intermediate. Please file a feedback report about this if you can reproduce it!

Having said that, clearing it out with nil and later re-setting it should have the same effect, so it is safe to do as a workaround.

  • Is fix in next iOS16 beta version?

Add a Comment

1.In the ios16beta version, UITextView is used in UITableViewCell. When the cell is reused, and the textView.attributedText assignment is updated, it is not rendered.

2. Our guess is that UITextView has been modified, and the corresponding rendering process is not triggered when assigning. And finally we find that views can be rendered normally when setting 'textView.attributedText=nil' before setting real attribute text, and then setting 'textView.attributedText=realAttributedText' after cleaning. (View UI Hierarch in the view structure, there is a corresponding _UiTextLayoutLayoutFragmentView)

3.Looking at the API, we find that ios16 UITextView has been modified, which means TextKit2 is used for rendering processing by default, and it can 'fall back' to TextKit1 for rendering processing by accessing the layoutManager property.

// From iOS 16 onwards, UITextViews are, by default, created with a TextKit 2 NSTextLayoutManager managing text layout (see the .textLayoutManager property). They will dynamically 'fall back' to a TextKit 1 NSLayoutManager if TextKit 1 features are used (notably, if the .layoutManager property is accessed).
// This convenience initializer can be used to specify TextKit 1 by default if you know code in your app relies on that. This avoids inefficiencies associated with the needless creation of a NSTextLayoutManager and the subsequent fallback.
+ (instancetype)textViewUsingTextLayoutManager:(BOOL)usingTextLayoutManager API_AVAILABLE(ios(16.0), tvos(16.0));
// This property accesses the TextKit 2 NSTextLayoutManager. You should generally prefer to use it over the TextKit 1 .layoutManager property if it exists. This property will return nil if TextKit 1 is in use.
@property(nonatomic, nullable, readonly) NSTextLayoutManager *textLayoutManager API_AVAILABLE(ios(16.0), tvos(16.0));
// To ensure compatibilty with older code, accessing the .layoutManager of a UITextView - or its .textContainer's .layoutManager - will cause a UITextView that's using TextKit 2 to 'fall back' to TextKit 1, and return a newly created NSLayoutManager. After this happens, .textLayoutManager will return nil - and _any TextKit 2 objects you may have cached will cease functioning_. Be careful about this if you are intending to be using TextKit 2!
@property(nonatomic, readonly) NSLayoutManager *layoutManager API_AVAILABLE(ios(7.0));

After setting access to layoutManager, it can be rendered normally.

You can reproduce the scene through the following demo file:

The rendering error* occurs when we lay out through 'frame' using UITextView in UITableViewCell, adjust the size of UITextView view and update the corresponding content according to the text content. The reason is that UITextView has been upgraded in ios16beta system, and TextKit 2 is used for rendering processing by default. *(the corresponding _UiTextLayoutLayoutFragmentView is not generated in the view hierarchy). Conclusion:

  1. NORMAL when using constraint layout
  2. Using the 'frame' layout, it can be reproduced. At present, it is found that there are two ways to restore it

(1) Before assignment, clean up self.textView.attributedText = nil (2) When UITextView is created, access the layoutManager property once to trigger the downgrade of rendering processing from TextKit 2 to TextKit 1

This problem has a great impact on the online version, when it will be fixed?

it has some error add demo file 'TestViewController.m' when convert to ‘TestViewController.m.log’ the code:

//
// TestViewController.m
// TestUITextView
//
// Created by *** on 2022/6/8.
//

#import "TestViewController.h"
#import "TestTableViewCell.h"
#import "TestModel.h"

@interface TestViewController ()<UITableViewDataSource,UITableViewDelegate>

@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic , strong) NSMutableArray *datas;
@end

@implementation TestViewController

- (void)viewDidLoad {
  [super viewDidLoad];
  // Do any additional setup after loading the view.
  [self.tableView registerClass:[TestTableViewCell class] forCellReuseIdentifier:@"TestTableViewCell"];
  [self loadData];
}

- (void)loadData
{
  self.datas = [[NSMutableArray alloc] init];
  NSString *test = @"testabcdefg";
  for (NSInteger i = 0; i < 100; i++) {
    NSMutableString *text = [[NSMutableString alloc] init];
    [text appendFormat:@"%@ ",@(i)];
    NSInteger k = i;
    if (k > 10) k = k%10;
    for (NSInteger j = 0;j<k;j++) {
      [text appendString:test];
    }
    TestModel *model = [[TestModel alloc] initWithText:text];
    [self.datas addObject:model];
  }
  [self.tableView reloadData];
}

- (nonnull UITableViewCell *)tableView:(nonnull UITableView *)tableView cellForRowAtIndexPath:(nonnull NSIndexPath *)indexPath {
  TestTableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"TestTableViewCell"];
  TestModel *model = self.datas[indexPath.row];
  [cell bindModel:model];
  return cell;
}

- (NSInteger)tableView:(nonnull UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
  return self.datas.count;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
  TestModel *model = self.datas[indexPath.row];
  return model.size.height;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
  [tableView deselectRowAtIndexPath:indexPath animated:NO];
}

@end

Wow, that's quite a report - thank you for all the details and investigation!

For submitting large bug reports like this, you can use Feedback Assistant, and then you will be notified on its status as we investigate it: https://developer.apple.com/bug-reporting.

I looked into this a bit more - I'd advise you to check again with Beta 2 when it becomes available, and file a feedback report if it's still happening there. I believe it will not.

  • Thanks, when is the beta2 expected to be released?

  • thanks,I have checked it ! this problem has been solved with Beta 2

Add a Comment