Skip to content

Instantly share code, notes, and snippets.

@skyline75489
Created August 8, 2016 08:35
Show Gist options
  • Save skyline75489/4c2bf228263eacfa133de4c8a468469b to your computer and use it in GitHub Desktop.
Save skyline75489/4c2bf228263eacfa133de4c8a468469b to your computer and use it in GitHub Desktop.
//
// NSAttributedString+CoreTextHelper.m
// TutorTeacherHD
//
// Created by skyline on 16/8/8.
// Copyright © 2016年 skyline. All rights reserved.
//
#import "NSAttributedString+CoreTextHelper.h"
#import <CoreText/CoreText.h>
#import <objc/runtime.h>
static char lastLineWidthCacheKey;
static char lineCountCacheKey;
@implementation NSAttributedString (CoreTextHelper)
- (NSMutableDictionary *)lastLineWidthCache {
NSMutableDictionary *cache = objc_getAssociatedObject(self, &lastLineWidthCacheKey);
if (cache) {
return cache;
}
cache = [NSMutableDictionary dictionary];
objc_setAssociatedObject(self, &lastLineWidthCacheKey, cache, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return cache;
}
- (NSMutableDictionary *)lineCountCache {
NSMutableDictionary *cache = objc_getAssociatedObject(self, &lineCountCacheKey);
if (cache) {
return cache;
}
cache = [NSMutableDictionary dictionary];
objc_setAssociatedObject(self, &lineCountCacheKey, cache, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
return cache;
}
- (NSString *)cacheStoreKeyWithRect:(CGRect)rect {
return [NSString stringWithFormat:@"%@_%@", self.string, NSStringFromCGRect(rect)];
}
- (CGFloat)lastLineWidthWithBoundingRect:(CGRect)rect {
NSNumber *cachedValue = [self.lastLineWidthCache objectForKey:[self cacheStoreKeyWithRect:rect]];
if (cachedValue) {
#if CGFLOAT_IS_DOUBLE
return [cachedValue doubleValue];
#else
return [cachedValue floatValue];
#endif
}
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((CFMutableAttributedStringRef)self);
CGMutablePathRef path = CGPathCreateMutable();
CGPathAddRect(path, NULL, rect);
CTFrameRef frame = CTFramesetterCreateFrame(framesetter, CFRangeMake(0, 0), path, NULL);
CFArrayRef lines = CTFrameGetLines(frame);
NSInteger lineCount = CFArrayGetCount(lines);
[self.lineCountCache setObject:@(lineCount) forKey:[self cacheStoreKeyWithRect:rect]];
CTLineRef lastLine = CFArrayGetValueAtIndex(lines, MAX(lineCount - 1, 0));
CGFloat ascent;
CGFloat descent;
CGFloat leading;
#if CGFLOAT_IS_DOUBLE
double lineWidth = CTLineGetTypographicBounds(lastLine, &ascent, &descent, &leading);
#else
CGFloat lineWidth = (CGFloat)CTLineGetTypographicBounds(lastLine, &ascent, &descent, &leading);
#endif
[self.lastLineWidthCache setObject:@(lineWidth) forKey:[self cacheStoreKeyWithRect:rect]];
CFRelease(path);
CFRelease(frame);
CFRelease(framesetter);
return lineWidth;
}
- (NSInteger)lineCountWithBoundingRect:(CGRect)rect {
NSNumber *cachedValue = [self.lineCountCache objectForKey:[self cacheStoreKeyWithRect:rect]];
if (cachedValue) {
return [cachedValue integerValue];
}
return -1;
}
@end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment