3

我有 NSAttributedString 之类的(只有一个符号 - s 和属性):

s{
    CTForegroundColor = "<CGColor 0x8878330> [<CGColorSpace 0x717da80> (kCGColorSpaceDeviceGray)] ( 0 0 )";
CTRunDelegate = "<CTRunDelegate 0x8878270 [0x16e14d8]>";
NSFont = "CTFont <name: HelveticaNeue-Light, size: 15.000000, matrix: 0x0>\nCTFontDescriptor <attributes: <CFBasicHash 0x88720f0 [0x16e14d8]>{type = mutable dict, count = 1,\nentries =>\n\t1 : <CFString 0x2a9838 [0x16e14d8]>{contents = \"NSFontNameAttribute\"} = <CFString 0x886f5f0 [0x16e14d8]>{contents = \"HelveticaNeue-Light\"}\n}\n>";

我创建了框架设置器和框架(它们不是零)并想要获取行:

NSArray *lines = (__bridge NSArray *)CTFrameGetLines(frame);

但是这个数组是空的。我不明白为什么。
提前致谢。

UPD:我的框架是

CTFrame: visible string range = (0, 0)<CGPath 0x75a63f0><CFArray 0x759a5d0 [0x16e14d8]>{type = mutable-small, count = 0, values = ()}

似乎核心文本没有看到属性字符串

UPD:添加了运行委托的代码

    CTFontRef fontRef = CTFontCreateWithName((__bridge CFStringRef)kSBTextFontAttribute, kSBFontSize, NULL);
    CTRunDelegateCallbacks callbacks;
    callbacks.version = kCTRunDelegateVersion1;
    callbacks.getAscent = ascentCallback;
    callbacks.getDescent = descentCallback;
    callbacks.getWidth = widthCallback;
    callbacks.dealloc = 0;

 NSDictionary *imgAttributes = [NSDictionary dictionaryWithObjectsAndKeys:
                             @kSmileWidth, kSBCallbackWidth,
                             @kSmileHeight, kSBCallbackHeight,
                             nil];

    CTRunDelegateRef delegate = CTRunDelegateCreate(&callbacks, CFBridgingRetain(imgAttributes));
    NSDictionary *attrDictionaryDelegate = [NSDictionary dictionaryWithObjectsAndKeys:
                                            //set the delegate
                                            (__bridge id)delegate, (NSString*)kCTRunDelegateAttributeName,
                                            (id)kSmileFontColor, kCTForegroundColorAttributeName,
                                            (__bridge id)fontRef,       kCTFontAttributeName,
                                            nil];

     /////////

     static void deallocCallback( void* ref ){
      ref = nil;
    }
    static CGFloat ascentCallback( void *ref ){
      return [(NSString*)[(__bridge NSDictionary*)ref objectForKey:kSBCallbackHeight]  floatValue];
     }
     static CGFloat descentCallback( void *ref ){
        return [(NSString*)[(__bridge NSDictionary*)ref objectForKey:kSBCallbackDescending] floatValue];
     }
     static CGFloat widthCallback( void* ref ){
         return [(NSString*)[(__bridge NSDictionary*)ref objectForKey:kSBCallbackWidth] floatValue];
     }
4

1 回答 1

3

由于您CTFrame是空的(“可见字符串范围=(0,0)”),这表明框架设置器无法布置任何文本。有几个原因可能是真的:

  • CTFramesetterCreateWithAttributedString中,您可能传递了一个空的属性字符串。您可能没有传递您认为自己是的对象,或者该对象的创建时间晚于框架设置器。用调试器检查。

  • CTFramesetterCreateFrame中,您可能传递的路径太小而无法包含任何文本。我通常喜欢画出我的路径drawRect:,这样我就可以看到它是否是我认为应该的形状。对于一个非常简单的路径,您也许可以在调试器中弄清楚它的形状。

  • 不太可能,但可能,在 中CTFramesetterCreateFrame,您可能传递了一个位于字符串末尾的范围。同样,调试器是这里显而易见的工具。


您需要不断分解这个问题,直到找到最简单的失败案例。我发现您实际发布的代码没有问题(内存管理错误除外;CFRelease()释放时需要使用字典)。以下完整示例对我来说很好:

NSString * const kSBCallbackHeight = @"kSBCallbackHeight";
NSString * const kSBCallbackDescending = @"kSBCallbackDescending";
NSString * const kSBCallbackWidth = @"kSBCallbackWidth";

const CGFloat kSmileWidth = 10.0;
const CGFloat kSmileHeight = 10.0;

static void deallocCallback( void* ref ){
  CFRelease(ref); // FIXED
}

static CGFloat ascentCallback( void *ref ){
  return [(NSString*)[(__bridge NSDictionary*)ref objectForKey:kSBCallbackHeight]  floatValue];
}
static CGFloat descentCallback( void *ref ){
  return [(NSString*)[(__bridge NSDictionary*)ref objectForKey:kSBCallbackDescending] floatValue];
}
static CGFloat widthCallback( void* ref ){
  return [(NSString*)[(__bridge NSDictionary*)ref objectForKey:kSBCallbackWidth] floatValue];
}

void testDelegate()
{
  CTRunDelegateCallbacks callbacks;
  callbacks.version = kCTRunDelegateVersion1;
  callbacks.getAscent = ascentCallback;
  callbacks.getDescent = descentCallback;
  callbacks.getWidth = widthCallback;
  callbacks.dealloc = deallocCallback;  // FIXED

  NSDictionary *imgAttributes = @{ kSBCallbackWidth: @(kSmileWidth),  // Switched to const rather than #define
                                   kSBCallbackHeight: @(kSmileHeight)
                                  };

  CTRunDelegateRef delegate = CTRunDelegateCreate(&callbacks, (void*)CFBridgingRetain(imgAttributes));
  NSDictionary *attrDictionaryDelegate = @{ (id)kCTRunDelegateAttributeName: (__bridge id)delegate };

  NSAttributedString *as = [[NSAttributedString alloc] initWithString:@"s" attributes:attrDictionaryDelegate];
  CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString((__bridge CFTypeRef)as);
  CTFrameRef frame = CTFramesetterCreateFrame(framesetter,
                                              CFRangeMake(0, 0),
                                              [[UIBezierPath bezierPathWithRect:CGRectMake(0, 0, 100, 100)] CGPath],
                                              NULL);
  NSArray *lines = (__bridge id)CTFrameGetLines(frame);

  NSLog(@"%@", lines);
}
于 2013-09-09T21:13:45.017 回答