NSTextStorage、YYText踩坑记录

1. 布景

需求是一组用户名,给定宽度

  • 能展现彻底:用户A, 用户B
  • 不能展现彻底,终究 +x人 :用户A, 用户B, 用户C +x人

我运用 TextKit 来核算是否发生了切公司让员工下班发手机电量截图断,拼接好方针字符串。运用 YYTextL枸杞ayout 来缓存布局信息,展现时直接运用 yyLabe字符串是什么意思l.textLayout = textLayout; 即可运用缓存好的布局信息,避免一些不必要的功能损耗。

2. 踩坑通过

原本一容器切都很正常,直到一个名叫“@ﻩㅤㅤㅤㅤㅤㅤㅤ阿风ㅤㅤㅤㅤ”的用户名ios应用商店,触发了展现反常和OOM崩溃。

下面咱们来看看引发工资超过5000怎么扣税这些问题的原因。

2.1 OOM问题

由于第一步现已核算好了切断,我认为后续运用 YYTextLayout 核算文本尺度是必定不会超过约束宽度的,所以在运用 YYTextContainer 时就运用了 CGSizeM容器设计ake(CGFLOAT_MAX, CGFLOAT_MAX) 来作为容器巨细,并在终究运用了 textBoundingSize 来缓存文本的巨细。

NSTextStorage *attrStr = // …
YYTextContainer *container = [YYTextContainer containerWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];
container.maximumNumberOfRows = 1;
container.truncationType = YYTextTruncationTypeEnd;
YYTextLayout *textLayout = [YYTextLayout layoutWithContainer:container text:attrStr];
CGSize textSize = textLayout.textBoundingSize;
// …

这儿我踩了第一个坑。

NSTextStorage、YYText踩坑记载

text工龄越长退休金越多吗BoundingSize 是整个制作区域的巨细,textBoundGoingRect描述了在哪个区域进行ios应用商店制作。

textBoundiios16ngSizetextBounGodingRect.size 并不等价。

所以,这儿运容器所能容纳什么叫做容器的容积textBoundingSize 获取到了一个非常大的尺度。

字符串逆序输出由于这儿缓存了这个尺度 (width = 1048576, height = 14) ,并且ios是苹果还是安卓终究给 YYLabel 进行 frame 设置之后呈现了崩溃问题。

这儿 YYLabe容器苗l 在列表中运用,所以呈现了多个 size 非常大的视图。

熟悉 YYLabel 的同学知道, YYLabel 会通过 Core Graphics 请求一块内存区字符间距怎么加宽域,并将文本制作出来,终究赋值给 layer.cont公司让员工下班发手机电量截图ents 达到iOS终究显示作用的。这儿由于运用了 多个过大的制作尺度 ,终究导致了 OOM 崩溃容器苗

2.2 展现反常

textBoun容器中有某种酒精含量的酒精溶液dingSize 不可,假如运用 textBoundingRect.size 是否能解决问题呢?

这儿要说到第二个坑。

由于 YYTapple tvextLayout容器设计缓存布局信息,yyLabel.textLayout = tex字符是什么tLayout; 则会直接用布局信息进行烘托。

虽然咱们 YYLabel 的尺度巨细正常了,可是制作仍发生在 (origin = (x = 1048410.29365625, y = -0.42999999999999972), size = (width = 165.70634375, height = 14.324999999999999)) 这个位置的。由于 x = 104工龄越长退休金越多吗8410.29365625 远超过正常尺度 (width = 1048576, height = 14) ,所以咱们看不到制作内容。

- (void)viewDidLoad {
  [super viewDidLoad];
  self.view.backgroundColor = UIColor.whiteColor;
  NSString *content = @"@ﻩㅤㅤㅤㅤㅤㅤㅤ阿风ㅤㅤㅤㅤ";
  UIFont *font = [UIFont systemFontOfSize:12.0];
  NSDictionary<NSAttributedStringKey, **id**> *attrs = @{
    NSFontAttributeName : font,
  };
  NSTextStorage *attrStr = [[NSTextStorage alloc] initWithString:content attributes:attrs];
  YYTextContainer *container = [YYTextContainer containerWithSize:CGSizeMake(CGFLOAT_MAX, CGFLOAT_MAX)];
  container.maximumNumberOfRows = 1;
  container.truncationType = YYTextTruncationTypeEnd;
  YYTextLayout *textLayout = [YYTextLayout layoutWithContainer:container text:attrStr];
  CGSize textSize = textLayout.textBoundingRect.size;
  YYLabel *yyLabel = [[YYLabel alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)];
  yyLabel.backgroundColor = UIColor.grayColor;
  yyLabel.textLayout = textLayout;
  [self.view addSubview:yyLabel];
  yyLabel.center = self.view.center;
}
NSTextStorage、YYText踩坑记载

终究,我运用 -[NSAttributedString boundingRectWithSize:options:context:] 提早核算容器苗了展现的宽度,终究让内容能够展现app store在屏幕上了。

- (void)viewDidLoad {
  [super viewDidLoad];
  self.view.backgroundColor = UIColor.whiteColor;
  NSString *content = @"@ﻩㅤㅤㅤㅤㅤㅤㅤ阿风ㅤㅤㅤㅤ";
  UIFont *font = [UIFont systemFontOfSize:12.0];
  NSDictionary<NSAttributedStringKey, id> *attrs = @{
    NSFontAttributeName : font,
  };
  NSTextStorage *attrStr = [[NSTextStorage alloc] initWithString:content attributes:attrs];
    // ===== 改变 =====
    CGSize size = [attrStr boundingRectWithSize:CGSizeMake(200, 0) options:NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin context:nil].size;
  YYTextContainer *container = [YYTextContainer containerWithSize:CGSizeMake(size.width, CGFLOAT_MAX)];
    // ===== 改变 =====
  container.maximumNumberOfRows = 1;
  container.truncationType = YYTextTruncationTypeEnd;
  YYTextLayout *textLayout = [YYTextLayout layoutWithContainer:container text:attrStr];
  CGSize textSize = textLayout.textBoundingRect.size;
  YYLabel *yyLabel = [[YYLabel alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)];
  yyLabel.backgroundColor = UIColor.grayColor;
  yyLabel.textLayout = textLayout;
  [self.view addSubview:yyLabel];
  yyLabel.center = self.view.center;
}
NSTextStorage、YYText踩坑记载

2.3 踩坑 NSTextStorage

下面来介绍一下,咱们的名称看ios下载着是正向的:

“@ﻩㅤㅤㅤㅤㅤㅤㅤ阿风ㅤㅤㅤㅤ”

但终究烘托出来时方向却不一样呢?

NSTextStorage、YYText踩坑记载

答案是 “ﻩ” 这个是一个阿拉伯符号,而 阿拉伯文是从右往左写的 所以烘托变成了上图这样。

还记得第一个坑, -[YYTextLayout textBoundingRect] 返回的 (origin = (x = 1048410.29365625, y = -0.42999999999999972), size = (width = 165.70634375, height = 14.324999999999999字符间距加宽2磅)) 吗?

这是由于 -[YYTextLayout textBoundingRect]字符是什么成的和体系不一样。即便是从右往左布局,体系 -[NSAttributedString boundingRectWithSize:options:context:] 返回的值为 (origin = (x = 0, y = 0), size = (width = 165.70634375, height = 14.365546875))。而 YYTextLayout 就非常实诚地从容器的最右侧开始布局,所以返回了一个非常大的值。

此外,这些看着像空格的容器对桌面的压强怎么算部分也不简单,通过 Unicode 转码后,咱们发现这些“空格”其实是 “u3164”

NSTextStorage、YYText踩坑记载

这也为咱们的烘托造成了一定的影响。

当咱们运用 NS容器对桌面的压强怎么算MutablgoogleeAt字符tributedString 时,枸杞咱们来调查一下富文本信息时怎样的。

NSString *content = @"@ﻩㅤㅤㅤㅤㅤㅤㅤ阿风ㅤㅤㅤㅤ";
UIFont *font = [UIFont systemFontOfSize:12.0];
NSDictionary<NSAttributedStringKey, id> *attrs = @{
    NSFontAttributeName : font,
};
NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:content attributes:attrs];
// 输出
(lldb) po attrStr
@ﻩㅤㅤㅤㅤㅤㅤㅤ阿风ㅤㅤㅤㅤ{
  NSFont = "<UICTFont: 0x7fb879f063c0> font-family: ".SFUI-Regular"; font-weight: normal; font-style: normal; font-size: 12.00pt";
}

能够看到字符间距怎么加宽咱们的富文本字体为 “.SFUI-Regular”

当咱们运用 NSTextStorage 时会是什么结果呢?

NSString *content = @"@ﻩㅤㅤㅤㅤㅤㅤㅤ阿风ㅤㅤㅤㅤ";
UIFont *font = [UIFont systemFontOfSize:12.0];
NSDictionary<NSAttributedStringKey, id> *attrs = @{
  NSFontAttributeName : font,
};
NSTextStorage *attrStr = [[NSTextStorage alloc] initWithString:content attributes:attrs];
// 输出
(lldb) po attrStr
@{
  NSFont = "<UICTFont: 0x7fb9b1b0fe20> font-family: ".SFUI-Regular"; font-weight: normal; font-style: normal; font-size: 12.00pt";
}ﻩ{
  NSFont = "<UICTFont: 0x7fb9b1b10c40> font-family: "Arial"; font-weight: normal; font-style: normal; font-size: 12.00pt";
}ㅤㅤㅤㅤㅤㅤㅤ阿{
  NSFont = "<UICTFont: 0x7fb9b4604350> font-family: ".AppleSDGothicNeoI-Regular"; font-weight: normal; font-style: normal; font-size: 12.00pt";
}风{
  NSFont = "<UICTFont: 0x7fb9b4604580> font-family: ".PingFangSC-Regular"; font-weight: normal; font-style: normal; font-size: 12.00pt";
}{
  NSFont = "<UICTFont: 0x7fb9b46047b0> font-family: ".AppleColorEmojiUI"; font-weight: normal; font-style: normal; font-size: 12.00pt";
}ㅤㅤㅤㅤ{
  NSFont = "<UICTFont: 0x7fb9b4604350> font-family: ".AppleSDGothicNeoI-Regular"; font-weight: normal; font-style: normal; font-size: 12.00pt";
}

咱们能够看到富文本中呈现了多种不同的富文本字体。这是由于 NSTextStorage 会主动调用 -[NSMutableAttributedString fixAttributesInRange:] 方法,对富文apple id密码重置apple watch的特点进行批容器中有某种酒精含量的酒精溶液改,枸杞详细的描述能够查看 API 的介绍。

@interface NSMutableAttributedString (NSAttributedStringAttributeFixing)
// This method fixes attribute inconsistencies inside range. It ensures NSFontAttributeName covers the characters, NSParagraphStyleAttributeName is only changing at paragraph boundaries, and NSTextAttachmentAttributeName is assigned to NSAttachmentCharacter. NSTextStorage automatically invokes this method via -ensureAttributesAreFixedInRange:.
- (void)fixAttributesInRange:(NSRange)range API_AVAILABLE(macos(10.0), ios(7.0));
@end

批改之后,会产生什么apple tv影响呢?咱们来比ios模拟器照一下:

NSTextStorage、YYText踩坑记载

通过比照,咱们发现通过 NSios是什么意思TextStorage 批改往后的尺度会远大于 NSMutableAttributedString字符是什么 需要的尺度。

所以咱们将 NSTextStorage 替换为 NSMutableAttributedString 来调查一下烘托Go作用。

- (void)viewDidLoad {
  [super viewDidLoad];
  self.view.backgroundColor = UIColor.whiteColor;
  NSString *content = @"@ﻩㅤㅤㅤㅤㅤㅤㅤ阿风ㅤㅤㅤㅤ";
  UIFont *font = [UIFont systemFontOfSize:12.0];
  NSDictionary<NSAttributedStringKey, id> *attrs = @{
    NSFontAttributeName : font,
  };
    // ===== 改变 =====
  NSMutableAttributedString *attrStr = [[NSMutableAttributedString alloc] initWithString:content attributes:attrs];
    // ===== 改变 =====
    CGSize size = [attrStr boundingRectWithSize:CGSizeMake(200, 0) options:NSStringDrawingUsesFontLeading | NSStringDrawingUsesLineFragmentOrigin context:nil].size;
  YYTextContainer *container = [YYTextContainer containerWithSize:CGSizeMake(size.width, CGFLOAT_MAX)];
  container.maximumNumberOfRows = 1;
  container.truncationType = YYTextTruncationTypeEnd;
  YYTextLayout *textLayout = [YYTextLayout layoutWithContainer:container text:attrStr];
  CGSize textSize = textLayout.textBoundingRect.size;
  YYLabel *yyLabel = [[YYLabel alloc] initWithFrame:CGRectMake(0, 0, textSize.width, textSize.height)];
  yyLabel.backgroundColor = UIColor.grayColor;
  yyLabel.textLayout = textLayout;
  [self.view addSubview:yyLabel];
  yyLabel.center = self.view.center;
}
NSTextStorage、YYText踩坑记载

能够看到咱们的烘托作用变得更紧凑了。

终究我也是将【运用 TextKit 来核龚俊算是否发生了切断,并拼接好方针字符串】ios14.4.1更新了什么的这部分逻辑,替换为 YYios下载Text 的完成方法,终究获得了满足的作用。


假如觉得apple tv本文不错,给我点个赞吧~❤️

NSTextStorage、YYText踩坑记载

发表评论

提供最优质的资源集合

立即查看 了解详情