-

一、iOS 相关

(一)给一整个View加渐变

  1. 如果我给一个View设置了maskView加了渐变,那是不是所有加到View上的subView展示的样式都会收到View.mastView的影响?

是的,如果给一个UIView设置了maskView并加了渐变,那么所有加到UIView上的subView展示的样式都会受到UIView.maskView的影响。

UIView.maskView属性会将一个UIView实例设置为另一个UIView实例的遮罩视图,即遮罩视图会覆盖在被遮罩的UIView上。因此,所有加到被遮罩的UIView上的subView都会被遮罩视图遮挡或显示。如果遮罩视图是一个带有渐变的UIView实例,那么所有加到被遮罩的UIView上的subView都会受到渐变的影响。

需要注意的是,如果某个subView的alpha值小于1.0,那么它的展示效果可能与其他subView不同。因为遮罩视图是根据alpha通道来遮挡或显示被遮罩的UIView的部分区域的,而alpha值小于1.0的subView可能会透过遮罩视图的alpha通道,从而影响展示效果。因此,在给一个UIView设置maskView时,需要注意subView的alpha值,以确保展示效果正确。

效果:

代码:

// 0 - 0.6 : 渐变
// 0.6 - 0.9 : 消失
gradientLayer.locations = @[ @(0), @(0.6), @(0.9), @(1) ];
gradientLayer.colors = @[ (__bridge id)inputColor0.CGColor,
(__bridge id)inputColor1.CGColor ,
(__bridge id)inputColor1.CGColor ,
(__bridge id)inputColor0.CGColor ];

// 0.1 - 0.4 : 渐变 ,前后都需要补充保护带,前 [0,0.1],后[0.4,0.401]
// 0.7 - 0.9 : 消失 ,前后都需要补充保护带,前 [0.699,0.7],后[0.9,0.901]
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0.1) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0.4) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0.401) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0.699) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0.7) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0.9) color:inputColor1]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0.901) color:inputColor0]];
[modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(1) color:inputColor0]];

完整测试代码:

+ (UIView *)createGradientMaskViewRenderFrame:(CGRect)renderFrame blankArea:(CGRect)blankArea targetView:(UIView *)targetView {
    CGFloat parentWidth = targetView.width;
    CGFloat parentHeight = targetView.height;

    UIView *gradientMaskView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, parentWidth, parentHeight)];
    gradientMaskView.isAccessibilityElement = NO;
    CAGradientLayer *gradientLayer = [CAGradientLayer layer];
    gradientLayer.frame = CGRectMake(0, 0, parentWidth, parentHeight);
    gradientLayer.startPoint = CGPointMake(0, 0);
    gradientLayer.endPoint = CGPointMake(1, 0);

    // 以blankArea为优先,处理重叠区域
    renderFrame = [self.class subtractRect:renderFrame withRect:blankArea];

    // 计算渐变和抹掉区域
    CGFloat renderStart = MIN(MAX(renderFrame.origin.x / parentWidth, 0), 1.0);
    CGFloat renderEnd = MIN(MAX((renderFrame.origin.x + renderFrame.size.width) / parentWidth, 0), 1.0);
    BOOL renderValid = renderStart >= 0 && renderEnd >= 0;

    CGFloat blankStart = MIN(MAX(blankArea.origin.x / parentWidth, 0), 1.0);
    CGFloat blankEnd = MIN(MAX((blankArea.origin.x + blankArea.size.width) / parentWidth, 0), 1.0);
    BOOL blankValid = blankStart >= 0 && blankEnd >= 0;

    WCFinderDebug(@"NavBar renderStart:%f,renderEnd:%f,blankStart:%f,blankEnd:%f,parentWidth:%f,parentHeight:%f",
                  renderStart,
                  renderEnd,
                  blankStart,
                  blankEnd,
                  parentWidth,
                  parentHeight);

    if (!renderValid && !blankValid) {
        WCFinderError(@"Error render blank frame");
        return nil;
    }

    /*
     四种情况:
     1. 渐变 x 抹掉
     2. 抹掉 x 渐变
     3. 渐变
     4. 抹掉
     
     Tips:
     1. 下面描述加保护带的原因是要迅速完成颜色转变。
     2. 这里说的渐变都是右边更模糊,左边清晰
     */

    NSMutableArray<WCFinderGradientColorModel *> *modelArray = [NSMutableArray array];
    UIColor *inputColor0 = [UIColor blueColor];
    UIColor *inputColor1 = UIColor.clearColor;
    if (renderValid && blankValid) {
        // {渐变 + 抹掉}
        if (fabs(renderEnd - blankStart) < 0.05) {
            // 无缝接壤
            if (renderEnd > blankStart) {
                // 渐变 + 抹掉
                // renderStart - renderEnd : 渐变 , 无保护带
                // renderEnd/blankStart - blankEnd : 抹掉, 后面要加保护带,后[blankEnd,blankEnd + 0.01]
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderStart) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd) color:inputColor1]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd) color:inputColor1]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd + 0.01) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(1.0) color:inputColor0]];
            } else {
                // 抹掉 + 渐变
                // blankStart - blankEnd : 抹掉 , 前面要加保护带,前 [blankStart - 0.01,blankStart]
                // blankEnd/renderStart - renderEnd : 渐变, 前后面要加保护带,前[blankEnd, blankEnd + 0.01],后[renderEnd,renderEnd +     0.01]
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart - 0.01) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart) color:inputColor1]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd) color:inputColor1]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd + 0.01) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd) color:inputColor1]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd + 0.01) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(1.0) color:inputColor0]];
            }
        } else {
            // 有间隙
            if (renderEnd > blankStart) {
                // 渐变 + 抹掉
                // renderStart - renderEnd : 渐变 ,后面有保护带 , [renderEnd, renderEnd + 0.01]
                // blankStart - blankEnd : 抹掉, 前后要加保护带,前:[blankStart - 0.01 , blankStart],后[blankEnd,blankEnd + 0.01]
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderStart) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd) color:inputColor1]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd + 0.01) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart - 0.01) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart) color:inputColor1]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd) color:inputColor1]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd + 0.01) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(1.0) color:inputColor0]];
            } else {
                // 抹掉 + 渐变
                // blankStart - blankEnd : 抹掉, 前后要加保护带,前:[blankStart - 0.01 , blankStart],后[blankEnd,blankEnd + 0.01]
                // renderStart - renderEnd : 渐变 ,后面有保护带 ,[renderEnd, renderEnd + 0.01]

                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart - 0.01) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart) color:inputColor1]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd) color:inputColor1]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd + 0.01) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderStart) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd) color:inputColor1]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd + 0.01) color:inputColor0]];
                [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(1.0) color:inputColor0]];
            }
        }
    } else if (renderValid) {
        // 纯渐变
        // renderStart - renderEnd : 渐变 ,后面有保护带 ,[renderEnd, renderEnd + 0.01]
        [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0) color:inputColor0]];
        [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderStart) color:inputColor0]];
        [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd) color:inputColor1]];
        [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(renderEnd + 0.01) color:inputColor0]];
        [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(1.0) color:inputColor0]];
    } else if (blankValid) {
        // 纯抹掉
        // blankStart - blankEnd : 抹掉, 前后要加保护带,前:[blankStart - 0.01 , blankStart],后[blankEnd,blankEnd + 0.01]
        [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(0) color:inputColor0]];
        [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart - 0.01) color:inputColor0]];
        [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankStart) color:inputColor1]];
        [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd) color:inputColor1]];
        [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(blankEnd + 0.01) color:inputColor0]];
        [modelArray addObject:[[WCFinderGradientColorModel alloc] initWithLocation:@(1.0) color:inputColor0]];
    }

    WCFinderGradientLayerModel *model = [WCFinderGradientLayerModel genGradientModel:modelArray];
    gradientLayer.locations = model.locations;
    gradientLayer.colors = model.colors;
    [gradientMaskView.layer addSublayer:gradientLayer];

    return gradientMaskView;
}   

(二)动画库的选择

《视频号直播动画框架》

2023年05月18日15:16:50

Lottie && PAG

  • Pag 能力更强大

PAG 3.0 -> 4.0

  • 性能Pag4.0和Pag3.0相当
  • Pag4.0支持三维

动画卡顿时的处理方法:

  • PAG资源优先级
  • 重pag降低刷新频率
  • 降低其它类型的点赞的pag、停掉不可见的pag

直播应用动画的框架:

  • PAG
  • 小游戏动画引擎
  • WeVision

当在iOS项目中需要嵌入脚本语言时,Lua是一个非常不错的选择。下面是一些Lua在iOS项目中的应用场景:

  1. 游戏开发:Lua在游戏开发中非常流行,因为它可以用来编写游戏逻辑和游戏脚本。在iOS游戏中,Lua可以用来编写关卡逻辑、AI行为、游戏界面等。

  2. 应用程序扩展:Lua可以用来编写应用程序的插件和扩展。例如,你可以使用Lua编写一个插件,使得你的应用程序可以通过脚本来自定义功能。

  3. 用户脚本:Lua可以用来编写用户脚本,这些脚本可以用来自定义应用程序的行为。例如,你可以使用Lua编写一个脚本,使得你的应用程序可以根据用户的需求来自定义UI界面。

  4. 数据处理:Lua可以用来处理数据,例如解析JSON数据、处理XML数据等。在iOS项目中,Lua可以用来处理从服务器获取的数据,以及在应用程序中存储的本地数据。

总之,Lua在iOS项目中有很多应用场景,它可以用来编写游戏逻辑、应用程序扩展、用户脚本和数据处理等。如果你正在开发一个iOS项目,并且需要嵌入脚本语言,那么Lua是一个非常不错的选择。

(三)JSCore优化

  1. 帮我介绍一下JIT优化
    当我们运行一个编译型语言编写的程序时,代码会被编译成机器码,然后直接在CPU上执行。而当我们运行一个解释型语言编写的程序时,代码会被解释器逐行解释执行。这种解释执行的方式会导致程序的运行速度比较慢。

JIT(即时编译)优化是一种优化技术,它可以在程序运行时将解释执行的代码编译成机器码,然后直接在CPU上执行。这种方式可以大大提高程序的运行速度。

在iOS开发中,JIT优化可以用来提高应用程序的性能。例如,我们可以使用JIT优化来提高游戏的帧率,或者使用JIT优化来提高应用程序的启动速度。

在iOS开发中,可以使用一些支持JIT优化的框架和库,例如LuaJIT、JavaScriptCore等。这些框架和库可以让我们使用JIT优化来提高应用程序的性能,同时也可以让我们更加方便地编写高性能的应用程序。

总之,JIT优化是一种非常有用的优化技术,它可以大大提高程序的运行速度。在iOS开发中,可以使用一些支持JIT优化的框架和库来提高应用程序的性能。

  1. TaggedPointer

用指针去存储内容。

  1. Hermes

Hermes是Facebook开发的一款JavaScript引擎,它专门用于React Native应用程序的开发。相比于iOS系统自带的JavaScriptCore引擎,Hermes有以下几个优点:

  1. 更快的启动速度:Hermes的启动速度比JavaScriptCore更快,这可以提高React Native应用程序的启动速度。

  2. 更小的内存占用:Hermes的内存占用比JavaScriptCore更小,这可以减少React Native应用程序的内存占用。

  3. 更好的性能:Hermes的性能比JavaScriptCore更好,这可以提高React Native应用程序的性能。

  4. 更好的调试支持:Hermes提供了更好的调试支持,可以方便地调试React Native应用程序。

在iOS开发中,我们可以使用Hermes作为React Native应用程序的JavaScript引擎。使用Hermes可以提高React Native应用程序的启动速度、性能和内存占用,并且可以提供更好的调试支持。同时,Hermes也可以与其他React Native工具和库一起使用,例如React Native CLI、Expo等。

总之,Hermes是一款非常有用的JavaScript引擎,它可以提高React Native应用程序的性能、启动速度和内存占用,并且提供了更好的调试支持。如果你正在开发React Native应用程序,那么可以考虑使用Hermes作为JavaScript引擎。

但是!! Hermes 现在有很多恶心的bug!!要小心使用!!

(四)使用yoga时重新触发布局: makeDirty

[self.likeBtn configureLayoutWithBlock:^(YGLayout *_Nonnull layout) {
    layout.isEnabled = self.likeBtn.isHidden == NO ? YES : NO;
    layout.width = YGPointValue(targetWidth);
}];

[self.likeBtn.yoga markDirty];

(五)layoutIfNeededsetNeedsLayout

在iOS开发中,UIView类提供了两个方法来触发视图的布局:layoutIfNeededsetNeedsLayout

setNeedsLayout方法是UIView的方法,它会标记当前视图及其子视图需要重新布局。但是它并不会立即触发布局,而是将布局标记为“需要”,然后在下一个run loop周期中,系统会调用layoutSubviews方法来进行布局。

示例代码如下:

1
2
// 标记当前视图需要重新布局
[self.view setNeedsLayout];

layoutIfNeeded方法是UIView的方法,它会立即触发布局计算,并更新视图的位置和大小。如果视图已经标记为“需要”布局,那么layoutIfNeeded方法会立即进行布局计算并更新视图;如果视图没有标记为“需要”布局,那么layoutIfNeeded方法不会进行任何操作。

示例代码如下:

1
2
// 如果视图需要重新布局,则立即进行布局计算
[self.view layoutIfNeeded];

因此,setNeedsLayout方法只是标记视图需要重新布局,而layoutIfNeeded方法则会立即进行布局计算并更新视图。在实际开发中,我们可以根据需要选择使用这两个方法。

(六)无符号整形的计算方法

NSUInteger abc = 0;
print(abc - 5); // 会溢出变成很大