Git Product home page Git Product logo

yyasynclayer's Introduction

YYAsyncLayer

License MIT  Carthage compatible  CocoaPods  CocoaPods  Support  Build Status

iOS utility classes for asynchronous rendering and display.
(It was used by YYText)

Simple Usage

@interface YYLabel : UIView
@property NSString *text;
@property UIFont *font;
@end

@implementation YYLabel

- (void)setText:(NSString *)text {
    _text = text.copy;
    [[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)] commit];
}

- (void)setFont:(UIFont *)font {
    _font = font;
    [[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)] commit];
}

- (void)layoutSubviews {
    [super layoutSubviews];
    [[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)] commit];
}

- (void)contentsNeedUpdated {
    // do update
    [self.layer setNeedsDisplay];
}

#pragma mark - YYAsyncLayer

+ (Class)layerClass {
    return YYAsyncLayer.class;
}

- (YYAsyncLayerDisplayTask *)newAsyncDisplayTask {
    
    // capture current state to display task
    NSString *text = _text;
    UIFont *font = _font;
    
    YYAsyncLayerDisplayTask *task = [YYAsyncLayerDisplayTask new];
    task.willDisplay = ^(CALayer *layer) {
        //...
    };
    
    task.display = ^(CGContextRef context, CGSize size, BOOL(^isCancelled)(void)) {
        if (isCancelled()) return;
        NSArray *lines = CreateCTLines(text, font, size.width);
        if (isCancelled()) return;
        
        for (int i = 0; i < lines.count; i++) {
            CTLineRef line = line[i];
            CGContextSetTextPosition(context, 0, i * font.pointSize * 1.5);
            CTLineDraw(line, context);
            if (isCancelled()) return;
        }
    };
    
    task.didDisplay = ^(CALayer *layer, BOOL finished) {
        if (finished) {
            // finished
        } else {
            // cancelled
        }
    };
    
    return task;
}
@end

Installation

CocoaPods

  1. Add pod 'YYAsyncLayer' to your Podfile.
  2. Run pod install or pod update.
  3. Import <YYAsyncLayer/YYAsyncLayer.h>.

Carthage

  1. Add github "ibireme/YYAsyncLayer" to your Cartfile.
  2. Run carthage update --platform ios and add the framework to your project.
  3. Import <YYAsyncLayer/YYAsyncLayer.h>.

Manually

  1. Download all the files in the YYAsyncLayer subdirectory.
  2. Add the source files to your Xcode project.
  3. Import YYAsyncLayer.h.

Documentation

Full API documentation is available on CocoaDocs.
You can also install documentation locally using appledoc.

Requirements

This library requires iOS 6.0+ and Xcode 8.0+.

License

YYAsyncLayer is provided under the MIT license. See LICENSE file for details.



中文介绍

iOS 异步绘制与显示的工具类。
(该工具是从 YYText 提取出来的独立组件)

简单用法

@interface YYLabel : UIView
@property NSString *text;
@property UIFont *font;
@end

@implementation YYLabel

- (void)setText:(NSString *)text {
    _text = text.copy;
    [[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)] commit];
}

- (void)setFont:(UIFont *)font {
    _font = font;
    [[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)] commit];
}

- (void)layoutSubviews {
    [super layoutSubviews];
    [[YYTransaction transactionWithTarget:self selector:@selector(contentsNeedUpdated)] commit];
}

- (void)contentsNeedUpdated {
    // do update
    [self.layer setNeedsDisplay];
}

#pragma mark - YYAsyncLayer

+ (Class)layerClass {
    return YYAsyncLayer.class;
}

- (YYAsyncLayerDisplayTask *)newAsyncDisplayTask {
    
    // capture current state to display task
    NSString *text = _text;
    UIFont *font = _font;
    
    YYAsyncLayerDisplayTask *task = [YYAsyncLayerDisplayTask new];
    task.willDisplay = ^(CALayer *layer) {
        //...
    };
    
    task.display = ^(CGContextRef context, CGSize size, BOOL(^isCancelled)(void)) {
        if (isCancelled()) return;
        NSArray *lines = CreateCTLines(text, font, size.width);
        if (isCancelled()) return;
        
        for (int i = 0; i < lines.count; i++) {
            CTLineRef line = line[i];
            CGContextSetTextPosition(context, 0, i * font.pointSize * 1.5);
            CTLineDraw(line, context);
            if (isCancelled()) return;
        }
    };
    
    task.didDisplay = ^(CALayer *layer, BOOL finished) {
        if (finished) {
            // finished
        } else {
            // cancelled
        }
    };
    
    return task;
}
@end

安装

CocoaPods

  1. 在 Podfile 中添加 pod 'YYAsyncLayer'
  2. 执行 pod installpod update
  3. 导入 <YYAsyncLayer/YYAsyncLayer.h>。

Carthage

  1. 在 Cartfile 中添加 github "ibireme/YYAsyncLayer"
  2. 执行 carthage update --platform ios 并将生成的 framework 添加到你的工程。
  3. 导入 <YYAsyncLayer/YYAsyncLayer.h>。

手动安装

  1. 下载 YYAsyncLayer 文件夹内的所有内容。
  2. 将 YYAsyncLayer 内的源文件添加(拖放)到你的工程。
  3. 导入 YYAsyncLayer.h

文档

你可以在 CocoaDocs 查看在线 API 文档,也可以用 appledoc 本地生成文档。

系统要求

该项目最低支持 iOS 6.0Xcode 8.0

许可证

YYAsyncLayer 使用 MIT 许可证,详情见 LICENSE 文件。

相关文章

iOS 保持界面流畅的技巧

yyasynclayer's People

Contributors

ibireme avatar irshadpc avatar zeveisenberg avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

yyasynclayer's Issues

CALayer 内部并没有属性 疑问

对象的调整也经常是消耗 CPU 资源的地方。这里特别说一下 CALayer:CALayer 内部并没有属性,当调用属性方法时,它内部是通过运行时 resolveInstanceMethod 为对象临时添加一个方法,并把对应属性值保存到内部的一个 Dictionary 里,同时还会通知 delegate、创建动画等等,非常消耗资源。UIView 的关于显示相关的属性(比如 frame/bounds/transform)等实际上都是 CALayer 属性映射来的,所以对 UIView 的这些属性进行调整时,消耗的资源要远大于一般的属性。对此你在应用中,应该尽量减少不必要的属性修改。

其中提到的CAlayer内部没有属性,你是怎么知道的?如何做的测试. 我尝试了交换 resolveInstanceMethod这个类方法,去调查给CALayer赋值一个属性,会不会走我交换的函数.结果是没有进入我的交换函数.

请指教.

NSOperationQueue 和 NSOperation 方式

YY 大神你好,请教一个问题:

你用多个串行队列来实现并发、控制线程数量,避免GCD在并行队列上执行耗时任务时开辟过多线程、消耗系统资源。如果通过NSOperationQueue 和 NSOperation的方式,控制maxConcurrentOperationCount 为YYAsyncLayerGetDisplayQueue中的queueCount,能够实现同样的效果嘛?

使用 YYAsyncLayer 异步绘制图片内存占用高的问题

YY 大神你好,我尝试着对你的微博 List 进行了优化,cell 上的一些细小的视图(比如人名、日期、来源等)这些控件使用了 YYAsyncLayer 异步绘制成了 layercontents,减少了视图层级,在流畅性上获得了很好的提升。虽然我用 Xcode 的 Debug Session 查看发现即使的暴力滑动的情况下内存依然控制在 20M 左右,但是使用 Instruments 的 Allocations 一调试,发现 UIGraphicsBeginImageContextWithOptionsUIGraphicsGetImageFromCurrentImageContext 两个方法内存占用竟然有几百兆。

2016-03-08 4 30 26

我尝试在 SO 上寻找解决方案,试着给绘制代码加了 autoreleasepool

    task.display = { [weak self] (context, size, isCancelled) in
      if isCancelled() {
        return
      }
      autoreleasepool({ () -> () in
        self?.draw(context,size: size) // 这里是具体的绘制代码
      })
    }

draw 的具体代码类似如下:

  private func draw(context: CGContextRef, size: CGSize) {
    //background color
    kWeiboStatusViewBackgroundColor.set()
    CGContextFillRect(context, CGRect(x: 0, y: 0, width: size.width, height: size.height))

    //timeline
    kWeiboStatusViewTimelineColor.set()
    CGContextFillRect(context, CGRectMake(kWeiboStatusCellLeftMargin+kWeiboStatusCellAvatarSize/2, 0, 1, height))

    //...
    retweetIcon.drawInRect(iconRect)
    //...
    retweetString.drawAtPoint(CGPoint(x: iconRect.origin.x + 3 + iconRect.width, y: retweet ? (iconRect.origin.y - 4) : (iconRect.origin.y - 3)))

  }

可是无果。想请教您指点,感谢。

请教一个关于计数器 YYSentinel 的问题

在看源码的过程中,对及时退出绘制任务的实现方案的理解有点拿不准,特来求证一下。
首先我一直很好奇,什么时候会 value != sentinel.value;,换言之,得滑到多快,才能让 value != sentinel.value;

源码里面,只要 cell 出现在屏幕上,都会触发一次 setNeedsDisplay:

- (void)setNeedsDisplay {
    [self _cancelAsyncDisplay]; //1
    [super setNeedsDisplay]; //2
}

这里面,//1 处会让计数器加1,我们可以把它认为是标准值;//2 里面会做一次取值:

YYSentinel *sentinel = _sentinel;
int32_t value = sentinel.value; //3

而由于 1、2 操作都是在主线程做的,所以会按先后顺序来。

所以,我的结论就是,源码中只是利用了函数调用的时间差,也就是说,只有当滑动的速度比 1、3 两处函数调用的时间差还要快,才会触发 isCancelled 判断条件。

以上是我的理解,不知道是否正确,特来求证,望指教。

PS:另外,还有一点想法,源码中的 isCancelled 属于主动式获取,必须去调用才知道是否不一致了,不太精准,容易漏掉。有没有可能实现被动式通知,就是一旦触发 value != sentinel.value; 就通知线程退出呢?

错误反馈

您的示例代码因C99无法使用,应该改成这个样子就好了~
screenshot

CALayer内部没有属性的疑问

对象的调整也经常是消耗 CPU 资源的地方。这里特别说一下 CALayer:CALayer 内部并没有属性,当调用属性方法时,它内部是通过运行时 resolveInstanceMethod 为对象临时添加一个方法,并把对应属性值保存到内部的一个 Dictionary 里,同时还会通知 delegate、创建动画等等,非常消耗资源。UIView 的关于显示相关的属性(比如 frame/bounds/transform)等实际上都是 CALayer 属性映射来的,所以对 UIView 的这些属性进行调整时,消耗的资源要远大于一般的属性。对此你在应用中,应该尽量减少不必要的属性修改。

CALayer是出于什么目的,内部没有属性,而去动态解析呢,这样有什么优势吗?还望大神指点。

size.width < 1 || size.height < 1还是size.width < 1 && size.height < 1 ?

if (size.width < 1 || size.height < 1) {
CGImageRef image = (__bridge_retained CGImageRef)(self.contents);
self.contents = nil;
if (image) {
dispatch_async(YYAsyncLayerGetReleaseQueue(), ^{
CFRelease(image);
});
}
if (task.didDisplay) task.didDisplay(self, YES);
CGColorRelease(backgroundColor);
return;
}
这段代码的意思是?

关于CreateCTLines()函数的疑问

readme.md里面的简单用法介绍里, 在- (YYAsyncLayerDisplayTask *)newAsyncDisplayTask 方法里有一个名为CreateCTLines()的函数, 请问这个函数是被包括在某个系统库里吗?

[self setNeedsDisplay] 无效

- (void)contentsNeedUpdated {
    // do update
    [self setNeedsDisplay];
}

此处地方self setNeedsDisplay无效。我也纳闷,因为 view 的 setNeedsDisplay 会自动转发到 layer 的 setNeedsDisplay,而 layerClass 已经指定了 YYAsyncLayer ,按理应该能转发到。请教原因。另外,改成[self.layer setNeedsDisplay] 解决。

RunLoop的作用

大神你好,我看AsyncDisplayKit的代码的时候,它是直接在display时将displayBlock加入到后台线程执行,然后在RunLoop触发Observer回调时提交block的执行结果,然后调用completeBlock,但是我看YYAsyncLayer好像是在RunLoop触发Observer回调时才在display里面将displayBlock添加到后台线程执行,然后执行完后直接向主线程提交结果,好像跟ASDK不太一样,所以这里感觉有点糊涂,到底为什么要在RunLoop上添加Observer呢,为什么不直接将绘制任务添加到后台线程然后将结果返回给主线程呢?

关于最大线程数

define MAX_QUEUE_COUNT 32

    case NSQualityOfServiceUserInteractive: {
        static dispatch_once_t onceToken;
        dispatch_once(&onceToken, ^{
            int count = (int)[NSProcessInfo processInfo].activeProcessorCount;
            count = count < 1 ? 1 : count > MAX_QUEUE_COUNT ? MAX_QUEUE_COUNT : count;
            context[0] = YYDispatchContextCreate("com.ibireme.yykit.user-interactive", count, qos);
        });
        return context[0];
    } break;

关于这段代码,有些疑问向您请教,比如iPhone6,返回count等于2,那么五种不同QOS类型,最多只会产生5*2=10个queues,不知道我的理解是否正确,这个最大值32的意义何在?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.