【问题标题】:CATextLayer shows its content only after a whileCATextLayer 仅在一段时间后显示其内容
【发布时间】:2014-12-12 08:36:08
【问题描述】:

我知道这听起来很奇怪,但问题恰恰在于:我有一个ViewController,它加载一个与 Grand Central Dispatch 异步的 CSV 文件(该文件代表一个直方图)。我还有一个名为HistogramView 的自定义视图。当控制器完成加载 CSV 文件时,它会在 HistogramView 上调用函数 invalidate。在该函数中,视图解析从文件中读取的数据并创建:

  1. 一些表示直方图条形的 CAShapeLayer
  2. 一些表示条形标签的 CATextLayer

对于形状层没问题,一切都很好。文本层出现问题:最初只显示背景。文本仅在几秒钟后出现:-/ 这很奇怪。这是invalidate函数的代码(这个函数,正如我所说,在自定义视图中)。

-(void)invalidate{
    float tempX = 0;
    float tempHeight = 0;
    NSArray *data;

    if([self.dataSource getHistogramData] != nil){
        data = [self.dataSource getHistogramData];
        tempX = [self getStartingX];
        [self getDataMaxValue];

        for (int i=0; i<[data count]; i+=2) {

            //THE SHAPE LAYER THAT REPRESENTS AN HISTOGRAM BAR
            tempHeight = [self uniformValue:[[data objectAtIndex:i+1] intValue]];
            CAShapeLayer *rectLayer = [CAShapeLayer layer];
            CGRect rect = CGRectMake(tempX, tempHeight, barWidth, height - tempHeight - spaceForLabels);
            rectLayer.path = CGPathCreateWithRect(rect, nil);
            [rectLayer setBackgroundColor:[UIColor colorWithRed:1 green:1 blue:1 alpha:1].CGColor];
            [self.layer addSublayer:rectLayer];


            //THE TEXT LAYER THAT REPRESENTS A LABEL FOR THE BAR
            CATextLayer *textLayer = [CATextLayer layer];
            textLayer.frame = CGRectMake(tempX, height - spaceForLabels, barWidth, spaceForLabels);
            textLayer.font = CFBridgingRetain([UIFont boldSystemFontOfSize:18].fontName);
            textLayer.fontSize = 18;
            textLayer.foregroundColor = [UIColor redColor].CGColor;
            textLayer.backgroundColor = [UIColor yellowColor].CGColor;
            textLayer.alignmentMode = kCAAlignmentCenter;
            textLayer.string = @"example";
            [self.layer addSublayer:textLayer];


            tempX += barWidth + spaceBetweenBars;
        }

    }
}

如您所见,我以相同的方式在同一点创建了条形图和标签。提前谢谢你。

编辑: 在我的视图控制器中,我以这种方式在 viewDidLoad 方法中完成工作:

- (void)viewDidLoad {
    [super viewDidLoad];

    //create the channel with which read the CSV file
    dispatch_io_t ch = dispatch_io_create_with_path(DISPATCH_IO_STREAM, [[[NSBundle mainBundle] pathForResource:@"histogram1" ofType:@"csv"] UTF8String], O_RDONLY, 0, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), nil);

    //read the CSV file async with GCD
    [self readCSVFile:ch];

    //set the delegates for the histogram view
    self.histogramView.delegate = self;
    self.histogramView.dataSource = self;
}

-(void)readCSVFile:(dispatch_io_t)ch{

    //the string that represents the content of CSV file
    NSMutableString __block *stringFromData;

    //read the whole file
    dispatch_io_read(ch, 0, SIZE_MAX, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(bool done, dispatch_data_t dataRead, int error) {

        if(!error && !done){

            //convert from dispatch_data_t to NSString
            size_t dataSize = dispatch_data_get_size(dataRead);
            stringFromData = [[NSMutableString alloc]initWithCapacity:dataSize];
            dispatch_data_apply(dataRead, ^bool(dispatch_data_t region, size_t offset, const void *buffer, size_t size) {
                [stringFromData appendFormat:@"%.*s", (unsigned int)size, buffer];
                return true;
            });
        }else{
            dispatch_io_close(ch, 0);
            data = [stringFromData componentsSeparatedByCharactersInSet:
                       [NSCharacterSet characterSetWithCharactersInString:@"\n,"]];

            //AND NOW I CALL INVALIDATE ON THE VIEW
            [self.histogramView invalidate];
        }

    });
}

【问题讨论】:

  • 主线程是否调用了invalidate?
  • 嗯...实际上没有。因为我传递给视图的数据是从读取的异步文件中加载的(感谢 Grand Central Dispatch)。我从 dispatch_io_read 末尾执行的代码块中调用“无效”。检查我的编辑。那是问题吗?感谢您的帮助!

标签: ios objective-c view core-graphics cashapelayer


【解决方案1】:

好的,我明白了。我要感谢 rdelmar,他的建议为我指出了问题所在。正如他所说,invalidate 不是从主线程调用的,而是从后台线程(读取文件的线程)调用的。这是错误的,因为必须从主线程更新视图。所以,我以这种方式简单地调用invalidate 方法来解决这个问题:

-(void)readCSVFile:(dispatch_io_t)ch{

    //the string that represents the content of CSV file
    NSMutableString __block *stringFromData;

    //read the whole file
    dispatch_io_read(ch, 0, SIZE_MAX, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^(bool done, dispatch_data_t dataRead, int error) {

        if(!error && !done){

            //convert from dispatch_data_t to NSString
            size_t dataSize = dispatch_data_get_size(dataRead);
            stringFromData = [[NSMutableString alloc]initWithCapacity:dataSize];
            dispatch_data_apply(dataRead, ^bool(dispatch_data_t region, size_t offset, const void *buffer, size_t size) {
                [stringFromData appendFormat:@"%.*s", (unsigned int)size, buffer];
                return true;
            });
        }else{
            dispatch_io_close(ch, 0);
            data = [stringFromData componentsSeparatedByCharactersInSet:
                       [NSCharacterSet characterSetWithCharactersInString:@"\n,"]];

            //HERE IS THE SOLUTION
            [[NSOperationQueue mainQueue]addOperationWithBlock:^{
                [self.histogramView invalidate];
            }];
        }

    });
}

【讨论】:

    猜你喜欢
    • 2020-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-04-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多