2011年9月6日星期二

调试安装到设备的ios程序

程序真机上崩溃以后通常会留下一个.crash的日志文件,可以通过这个crash文件迅速查找到哪里崩溃了,当然仅仅这个crash日志文件是不够的,还需要一个.dsym文件,该文件保存了些调试需要的信息。 xode默认是设置编译时生成.dsym文件的,编译程序时,会在app的同级目录生成该文件。同时应该明确一个事情,每个dsym文件只和同时编译的app匹配。

1.生成.dsym

Xcode's "Archive" command makes it easy keeping the matching binary and the .dSYM. When you use the "Archive" command (by choosing "Archive" from the "Product" menu or by pressing Shift+Command+B), Xcode will gather the application binary and the .dSYM containing symbol information together and store them in a location in your home folder. You can find all of your archived applications in the Xcode Organizer under the "Archived" section. Xcode will automatically search archived applications when symbolicating crash reports, and you can submit archived applications directly to iTunes Connect ensuring that the application and .dSYM that you have archived match what you release.
Xcode will automatically symbolicate all crash reports that it encounters, if it has the .dSYM and application binary that produced the crash report. Given a crash report, the matching binary, and its .dSYM file, all you need to do for symbolication is to add the crash report to the Xcode Organizer. Open the Xcode Organizer, select the “Devices” tab, select “Device Logs” under “LIBRARY” on the top of the sidebar, click the "Import" button and select the .crash file. When it's done, Xcode will automatically symbolicate the crash report and display the results.

2.获取设备中的crash日志


当用itunes同步设备后,crash日志会被拷贝到一下目录  Mac OS X: ~/Library/Logs/CrashReporter/MobileDevice/<DEVICE_NAME>
Windows XP: C:\Documents and Settings\<USERNAME>\Application Data\Apple Computer\Logs\CrashReporter\MobileDevice\<DEVICE_NAME>
Windows Vista or 7: C:\Users\<USERNAME>\AppData\Roaming\Apple Computer\Logs\CrashReporter\MobileDevice\<DEVICE_NAME>

3.使用工具symbolicatecrash 获取crash日志中的具体内容,将错误日志中的崩溃的函数地址转换为实际的函数名称


$ sudo cp /Developer/Platforms/iPhoneOS.platform/Developer/Library/Xcode/Plug-ins/iPhoneRemoteDevice.xcodeplugin/Contents/Resources/symbolicatecrash /usr/local/bin/

$ symbolicatecrash report.crash MobileLines.app.dSYM > report-with-symbols.crash

更多资料可参考:

  • http://www.anoshkin.net/blog/2008/09/09/iphone-crash-logs/      IPhone Crash Logs
  • http://kbase.wincent.com/old/knowledge-base/DWARF_with_dSYM_debug_information.html       DWARF with dSYM debug information
  • http://www.cimgf.com/2009/12/23/automatically-save-the-dsym-files/    Automatically save the dSYM files.
  • http://developer.apple.com/library/ios/#technotes/tn2151/_index.html   Understanding and Analyzing iPhone OS Application Crash Reports
=====================

Extracting the Debugging Information to a Separate File

http://developer.apple.com/tools/xcode/symbolizingcrashdumps.html



     It should be obvious by now that you need a build process that strips the final executable file of all debugging information while simultaneously saving that information for future debugging. Instead of merely stripping the debug information from the final executable, a better solution is to extract the debugging information and save it to a separate location. The application is built only once, and the extracted debugging information is available to the developer but is no longer embedded in the final product.

    Beginning with version 2.4, Xcode supports the Debugging with Attributed Record Formats (DWARF) with dSYM file format. Setting the Debug Information Format to DWARF with dSYM causes the linker to produce a separate file package, with the dSYM extension, that contains a copy of the symbol information in the executable. A small reference is added to the executable so that debugging tools know that a dSYM file for the program was produced.
    
    The embedded debug information can now be safely stripped from the executable. When loading a stripped executable, the GNU debugger will check for its companion dSYM file. If present, it will automatically use the DWARF debugging information contained therein. A dSYM file must be in the same directory as the product (simple executable or application bundle) for this to occur.

    In the Release configuration of the application target, enable dSYM-style debugging information, as Table 3 shows.


  • Build Setting Value
  • Generate Debug Symbols YES
  • Debug Information Format DWARF with dSYM File
Table 3: Target Build Settings in the Release Configuration

   
    Note that the dSYM file format can’t be used with ZeroLink and is generally useful only for producing a stripped product while retaining a copy of the debugging information. In your development build configurations, continue to use the regular stabs or DWARF formats.

   And, like the previous solution, enable stripping of the final executable in the project build settings, as Table 4 shows.


  • Build Setting Value
  • Deployment Postprocessing YES
  • Strip Linked Product YES
  • Use Separate Strip YES
  • Strip Debug Symbols During Copy NO
Table 4: Project Build Settings in the Release Configuration


    This solution meets the first and second goals and is easy to maintain. You can archive the finished application for future debugging simply by preserving the dSYM file. You can debug the release build of the application without any special steps; simply start the debugging session with the dSYM file present. The application, sans the dSYM file, can be freely distributed and contains no symbol information.

A Note About Debugging Optimized Code



     Be aware that you could encounter subtle problems when trying to debug optimized code. During debugging, code generally isn’t optimized because optimization can destroy the one-to-one relationship between the source code and the compiled object code, which could make it impossible to correlate an execution address with a line of code in the original source (or vice versa). Another artifact might be unexpected order of execution (i.e., the statement on line 9 executes before the statement on line 8). This behavior sometimes makes it difficult to set breakpoints or control execution in the debugger.

    There’s no real solution to this problem. The very nature of optimizers means that the compiler might rewrite code expressed in source code for better performance.

 Symbolizing Crash Dumps



Should your application crash, the system crash reporter facility creates a crash log. This crash log contains a stack trace annotated with whatever program symbol information was found in the application and frameworks. The standard system frameworks contain basic symbol information, but if the application has been stripped of its debugging information, no useful information about the application’s stack will be logged. Listing 2 shows a portion of the TempConverter.crash.log.


Thread 0 Crashed:


0 com.yourcompany.TempConverter 0x00002b84 0×1000 + 7044


1 com.apple.Foundation 0x929ea9c8 _NSSetObjectValueAndNotify + 136


2 com.apple.Foundation 0x929ea6f4 -[NSObject(NSKeyValueCoding) setValue:forKeyPath:] + 180





27 com.apple.AppKit 0x937f887c NSApplicationMain + 452


28 com.yourcompany.TempConverter 0x000029dc 0×1000 + 6620


29 com.yourcompany.TempConverter 0x000026e0 0×1000 + 5856


Listing 2: Excerpt from TempConverter.crash.log


Because the TempConverter executable has no symbol information, program locations in the TempConverter code segment are listed as hexadecimal offsets. You can use the atos (“address to symbol”) tool to convert these addresses back to their symbolic names. If enough debugging information is available, the tool also supplies the source file name and line number for the address. Open a Terminal window, and set the current directory to the TempConverter D/build/Release folder. Then, issue the command that Listing 3 shows.


atos -o Debug/TempConverter.app/Contents/MacOS/TempConverter 0x00002b84


-[ConverterApplicationDelegate setCentigradeTemperature:] (in TempConverter) (ConverterApplicationDelegate.m:42)


Listing 3: Using atos to Translate Memory Address to Symbol


The atos tool reads the symbols contained in the TempConverter executable file and uses that information to convert the address 0x00002b84 to its symbolic equivalent, complete with source file name and line number. If you’re using DWARF dSYM files, you must be using the version of atos included in Xcode 3 (Mac OS X version 10.5).

The atos command accepts multiple address arguments or can read a list of addresses from stdin. While useful enough for converting a few addresses, atos becomes cumbersome for large stack traces or multiple crash logs. Fortunately, you can automate the process with a script like the one Listing 4 shows.



#!/bin/bash

AWK_SCRIPT=/tmp/symbolizecrashlog_$.awk
SH_SCRIPT=/tmp/symbolizecrashlog_$.sh
if [[ $# < 2 ]]
then
echo “Usage: $0 [ -arch ] symbol-file [ crash.log, ... ]”
exit 1
fi

ARCH_PARAMS=”

if [[ "${1}" == '-arch' ]]

then

ARCH_PARAMS=”-arch ${2}”

shift 2

fi

SYMBOL_FILE=”${1}”

shift

cat > “${AWK_SCRIPT}” < < _END


/^[0-9]+ +[-._a-zA-Z0-9]+ *\t0x[0-9a-fA-F]+ / {


addr_index = index(\$0,\$3);


end_index = addr_index+length(\$3);


line_legnth = length;


printf("echo '%s'\"\$(symbolize %s '%s')\"\n",substr(\$0,1,end_index),


\$3,substr(\$0,end_index+1,line_legnth-end_index));


next;


}


{ gsub(/'/,"'\\\\''"); printf("echo '%s'\n",\$0); }


_END


function symbolize()
{
# Translate the address using atos
SYMBOL=$(atos -o "${SYMBOL_FILE}" ${ARCH_PARAMS} "${1}" 2>/dev/null)
# If successful, output the translated symbol. If atos returns an address, output the original symbol
if [[ "${SYMBOL##0x[0-9a-fA-F]*}” ]]
then
echo -n “${SYMBOL}”
else
echo -n “${2}”
fi
}

awk -f “${AWK_SCRIPT}” $* > “${SH_SCRIPT}”

. “${SH_SCRIPT}”

rm -f “${AWK_SCRIPT}” “${SH_SCRIPT}”


Listing 4: The symbolizecrashlog Script


Obtain a crash log from the TempConverter without symbol information and a copy of the executable file that includes its debugging information. Invoke the script with the command Listing 5 shows. (This command assumes that all three files are in the current directory.)


./symbolizecrashlog TempConverter TempConverter.crash.log > TempConverter.symbolized.log


Listing 5: Running the symbolizecrashlog Tool


The symbolizecrashlog script takes as input one or more crash logs and uses the debugging information found in the first argument to translate all stack trace addresses to their symbolic equivalents. Addresses that can’t be translated are left unaltered. If no crash log files are given, the script reads the crash log from stdin.


Crash Processor Architecture


Universal binaries contain the executable for multiple processor architectures. Both the atos tool and the symbolizecrashlog script assume that the addresses being converted are for the architecture of the computer on which they’re running. For example, symbolizing a crash log that occurred on a Power Mac (PowerPC) using a Power Mac Pro (Intel) produces invalid results, because atosassumes that addresses apply to the Intel executable. You must tell atos to use the debugging symbols information that belongs to the “ppc” executable, instead. Both atos and symbolizecrashlog accept an -arch option to specify the architecture of the system that should be used to interpret the addresses. Listing 6 shows some examples.


atos -arch ppc TempConverter 0x00002b84


symbolizecrashlog -arch i386 TempConverter TempConverter.crash.log > TempConverter.symbolized.log


Listing 6: Specifying the Architecture when Using atos and symbolizecrashlog
Share:

2011年6月28日星期二

xcode instruments Allocations & Leaks

Allocations

The Allocations instrument tracks memory allocation for an application. This instrument requires that you launch a single process so that it can gather data from the start of the process.

This instrument captures the following information:

Category - typically a Core Foundation object, an Objective-C class, or a raw block of memory.
Net Bytes - the number of bytes of this type currently allocated but not yet released.
# Net - the number of objects or memory blocks of this type currently allocated but not yet released.
Overall Bytes - the total number of bytes of this type that have been allocated, including those that have been released.
# Overall - the total number of objects or memory blocks of this type that have been allocated, including those that have been released.
# Allocations (Net / Overall) - A histogram of the current and total counts. The bars are normally shades of blue. They are colored shades of yellow when the ratio between the total number of objects and the peak, or the ratio between the peak and the current number, is 1/3 or less. The bars are shades of red when the ratio is 1/10 or less.
Although the ratios displayed aren't necessarily bad (often, they're normal over the long run of an application), Instruments colors them to point out allocation patterns that may deserve a further look. If you see categories where the color is red or yellow, you might try to eliminate unnecessary temporary allocations of the given type in your application. Similarly, you might simply try to eliminate the high-water mark in the number of objects.

The data table in the details pane contains a Graph column, which contains a checkbox for each row in the table. When the checkbox for a given category is enabled, the instrument displays the graph for that particular category type in the Track pane. Instruments automatically assigns a color to each graphed category.

When you mouse over category names in the details pane, a more Info button appears next to the category name. Clicking this button displays detailed information about the objects in that category, including the following attributes:

The address of the block.
The function call or class that generated the allocation event. For example, you can see which method in a class retained an object.
The creation time of the object.
The library responsible for creating the object.
For any of these events, you can open the Extended Detail pane to see the stack trace for each object allocation, including the type of allocation and the time at which the event occurred.

For specific instances of an object (or memory block), you can click the more info button in the Object Address column to see the allocation events associated with that object. For each allocation event, this instrument displays the following information:

The category of the object (its type)
The event type.
The timestamp for each event.
The address of the block
The size of the block
The library responsible for allocating the block.
The function that caused the allocation event.
For any allocation event, you can open the Extended Detail pane to see the stack trace, as well as any available event information and the time at which the event occurred.

To further filter information in the Detail pane, you can configure the Allocation Lifespan options. These options let you filter the allocation events based on the following criteria:

All Objects Created - display all objects, regardless of whether they have been deallocated.
Created & Still Living - display only objects that existed in memory when you stopped recording data..
The inspector for the Allocations instrument lets you configure the way the instrument tracks information. From the inspector, you can set the following options:

Record reference counts. Use this option to track the reference count of each object.
Discard unrecorded data on stop. Use this option to discard any data that has been gathered but not yet processed by the Allocations instrument.
For additional information about the Allocations instrument, see “Analyzing Data with the Allocations Instrument.”

Leaks

The Leaks instrument examines a process’s heap for leaked memory. You can use this instrument together with the Allocations instrument to get memory address histories. This instrument requires that you launch a single process so that it can gather data from the start of the process.

This instrument captures the following information:

The number of leaks
The size of each leak
Address of the leaked block
Type of the leaked object
Each view mode in the Detail pane shows the leak data in a slightly different way. In table mode, this instrument shows the individual leaks along with the percentage that each individual leak contributes to the total amount of leaked memory discovered. In outline mode, the data is reorganized so that you can see how much memory is leaked from within a given symbol. For entries in either mode, the Extended Detail pane displays a heavy stack trace showing from where the leak originated.

For additional information about the Leaks instrument, see “Looking for Memory Leaks.”
Share:

2011年5月23日星期一

ios后台播放音乐


1. //后台播放
AVAudioSession *session = [AVAudioSession sharedInstance];
[session setActive:YES error:nil];
[session setCategory:AVAudioSessionCategoryPlayback error:nil];

2. 让后台可以处理多媒体的事件
[[UIApplication sharedApplication] beginReceivingRemoteControlEvents];

Remote-control events originate as commands issued by headsets and external accessories that are intended to control multimedia presented by an application. To stop the reception of remote-control events, you must call endReceivingRemoteControlEvents.

3.系统进入后台运行时,让程序可以运行一段时间。使用此方法争取一定的时间,在程序进入后台后处理一些事情。
- (UIBackgroundTaskIdentifier)beginBackgroundTaskWithExpirationHandler:(void(^)(void))handler
This method lets your application continue to run for a period of time after it transitions to the background.
your application could call this method to ensure that had enough time to transfer an important file to a remote server or at least attempt to make the transfer and note any errors. You should not use this method simply to keep your application running after it moves to the background.
Share:

2011年4月16日星期六

uiimage 转换为像素数据 以及从像素数据生成为uiimage

生成RGBABitmapContext 

CGContextRef CreateRGBABitmapContext (CGImageRef inImage){
CGContextRef context = NULL; CGColorSpaceRef colorSpace;
void *bitmapData;
int bitmapByteCount;
int bitmapBytesPerRow;
size_t pixelsWide = CGImageGetWidth(inImage);
size_t pixelsHigh = CGImageGetHeight(inImage);
bitmapBytesPerRow = (pixelsWide * 4);
bitmapByteCount = (bitmapBytesPerRow * pixelsHigh);
colorSpace = CGColorSpaceCreateDeviceRGB();  if (colorSpace == NULL){
fprintf(stderr, "Error allocating color space");
return NULL;
}

// allocate the bitmap & create context
bitmapData = malloc( bitmapByteCount );
if (bitmapData == NULL){
printf (stderr, "Memory not allocated!");
CGColorSpaceRelease( colorSpace );
return NULL;
}

context = CGBitmapContextCreate (bitmapData,
pixelsWide,
pixelsHigh,
8,
bitmapBytesPerRow,
colorSpace,
kCGImageAlphaPremultipliedLast);

if (context == NULL){
    free (bitmapData);
    fprintf (stderr, "Context not created!");
 }

CGColorSpaceRelease( colorSpace );

 return context;

生成图片的像素数据

// Return Image Pixel data as an RGBA bitmap
unsigned char *RequestImagePixelData(UIImage *inImage) {

CGImageRef img = [inImage CGImage];
CGSize size = [inImage size];
CGContextRef cgctx = CreateRGBABitmapContext(img);
if (cgctx == NULL)
return NULL;

CGRect rect = {{0,0},{size.width, size.height}};
CGContextDrawImage(cgctx, rect, img);
unsigned char *data = CGBitmapContextGetData (cgctx);
CGContextRelease(cgctx);
return data;
}
Share:

2011年2月16日星期三

+ (UIImage *)imageNamed:(NSString *)name导致的内存问题

这种方法在application bundle的顶层文件夹寻找名字的图象 , 如果找到图片, 系统缓存图象。图片内容被加载到系统内存中,使用时直接引用到系统内存。
所以当图片比较大时,程序使用的内存会迅速上升导致内存警告并退出。
特别在使用Interface Builder建立界面时,如果直接拖动UIImageView 并设置image的图片名称。InterfaceBuilder 正是通过UIImage 类的imageName方法加载图片。图片被缓存,导致内存使用较大。且无法释放,即使release掉 UIImageView也无济于事。
所以推荐使用+ (UIImage *)imageWithContentsOfFile:(NSString *)path方法加载图片。

也可以重载 imageNamed方法。
@implementation UIImage(imageNamed_Hack)

+ (UIImage *)imageNamed:(NSString *)name {

    return [UIImage imageWithContentsOfFile:[NSString stringWithFormat:@"%@/%@",
   [[NSBundle mainBundle] bundlePath], name ] ];

}

@end
Note: With this override you will not have any cache loading UIImages, if you need this,you will have to implement your own cache.
Tip: If your applications use much image processing, consider to use de PhotoshopFramework for iPhone. Check here: http://sourceforge.net/projects/photoshopframew/
Share:

2011年2月15日星期二

cocoa 下的正则表达式框架

RegexKit is an Objective-C framework for regular expressions:

  • Support for Mac OS X Cocoa and GNUstep. Mac OS X 10.4 or later required.

  • Mac OS X Universal Binary, including 64-bit support on Mac OS X 10.5.

  • No sub-classing required. Seamlessly adds regular expression support to all NSArray, NSData, NSDictionary, NSSet, and NSString Foundation objects with a rich set of Objective-C category additions.

  • Unicode enabled. Full Unicode support for NSString objects.

  • Extensive, high quality documentation.

  • Full source code with a BSD license.

  • Uses the BSD licensed PCRE Perl Compatible Regular Expressions library for the regular expression engine.


Tuned for high performance, including such features as:

  • Caches the compiled form of the regular expression for speed.

  • Multithreading safe, including multiple reader, single writer multithreaded access to the compiled regular expression cache.

  • Makes minimal use of heap storage (ie, malloc() and free()), instead allocating most temporary buffer needs dynamically from the stack.

  • Uses Core Foundation directly on Mac OS X for additional speed.


Includes support for Mac OS X 10.5 Leopard:

  • 64 bit support. Pre-built for ppc, ppc64, i386, and x86_64.

  • Garbage Collection enabled. Complete support for Leopards Garbage Collection feature.

  • Integrated Xcode 3.0 documentation. Get real time API information via the Research Assistant.

  • Collection of instruments for Instruments.app.

  • RegexKit specific DTrace probe points.


http://regexkit.sourceforge.net/

除了使用正则表达式匹配字符、数组以外,还可以使用NSPredicate做过滤查找。待续...
Share:

2011年2月11日星期五

iPhone中使用自定义字体

步骤:

1) 将字体文件添加到Resources目录.
2) 然后在你的工程的Info.plist文件中新建一行(Add Row),添加key为:UIAppFonts,类型为Array或Dictionary都行;在其下方添加新行   Value为XXX.ttf(你字体的名字)。

3) 添加的字体的文件名称是无关紧要的, 主要是要知道你添加的字体的fontname

如: msjh.ttf   (Window7中的微软正黑体)  , 加入UIAPPFonts
Family name: Microsoft JhengHei
Font name: MicrosoftJhengHeiRegular

则使用的话就需要使用 [UIFont fontWithName:@"Microsoft JhengHei" size:12];

获取程序内支持的字体列表的代码:

NSArray *familyNames = [[NSArray alloc] initWithArray:[UIFont familyNames]];
NSArray *fontNames;
NSInteger indFamily, indFont;
for (indFamily=0; indFamily<[familyNames count]; ++indFamily)
{
NSLog(@"Family name: %@", [familyNames objectAtIndex:indFamily]);
fontNames = [[NSArray alloc] initWithArray:
[UIFont fontNamesForFamilyName:
[familyNames objectAtIndex:indFamily]]];
for (indFont=0; indFont<[fontNames count]; ++indFont)
{
NSLog(@" Font name: %@", [fontNames objectAtIndex:indFont]);
}
[fontNames release];
}
[familyNames release];

Share:

2011年1月20日星期四

iphone开发中文章显示的一种排版技术


1。绘制简单的一行文字

- (void)drawRect:(CGRect)rect
{
// create a font, quasi systemFontWithSize:24.0
CTFontRef sysUIFont = CTFontCreateUIFontForLanguage(kCTFontSystemFontType,
24.0, NULL);

// create a naked string
NSString *string = @"Some Text";

// blue
CGColorRef color = [UIColor blueColor].CGColor;

// single underline
NSNumber *underline = [NSNumber numberWithInt:kCTUnderlineStyleSingle];

// pack it into attributes dictionary
NSDictionary *attributesDict = [NSDictionary dictionaryWithObjectsAndKeys:
(id)sysUIFont, (id)kCTFontAttributeName,
color, (id)kCTForegroundColorAttributeName,
underline, (id)kCTUnderlineStyleAttributeName, nil];

// make the attributed string
NSAttributedString *stringToDraw = [[NSAttributedString alloc] initWithString:string
attributes:attributesDict];

// now for the actual drawing
CGContextRef context = UIGraphicsGetCurrentContext();

// flip the coordinate system
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

// draw
CTLineRef line = CTLineCreateWithAttributedString(
(CFAttributedStringRef)stringToDraw);
CGContextSetTextPosition(context, 10.0, 10.0);
CTLineDraw(line, context);

// clean up
CFRelease(line);
CFRelease(sysUIFont);
[stringToDraw release];
}
2。实现分列的文本显示
实现的效果如下:




- (void)drawRect:(CGRect)rect
{
NSString *longText = @"Lorem ipsum dolor sit amet, "; /* ... */

NSMutableAttributedString *string = [[NSMutableAttributedString alloc]
initWithString:longText];

// make a few words bold
CTFontRef helvetica = CTFontCreateWithName(CFSTR("Helvetica"), 14.0, NULL);
CTFontRef helveticaBold = CTFontCreateWithName(CFSTR("Helvetica-Bold"), 14.0, NULL);

[string addAttribute:(id)kCTFontAttributeName
value:(id)helvetica
range:NSMakeRange(0, [string length])];

[string addAttribute:(id)kCTFontAttributeName
value:(id)helveticaBold
range:NSMakeRange(6, 5)];

[string addAttribute:(id)kCTFontAttributeName
value:(id)helveticaBold
range:NSMakeRange(109, 9)];

[string addAttribute:(id)kCTFontAttributeName
value:(id)helveticaBold
range:NSMakeRange(223, 6)];

// add some color
[string addAttribute:(id)kCTForegroundColorAttributeName
value:(id)[UIColor redColor].CGColor
range:NSMakeRange(18, 3)];

[string addAttribute:(id)kCTForegroundColorAttributeName
value:(id)[UIColor greenColor].CGColor
range:NSMakeRange(657, 6)];

[string addAttribute:(id)kCTForegroundColorAttributeName
value:(id)[UIColor blueColor].CGColor
range:NSMakeRange(153, 6)];

// layout master
CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(
(CFAttributedStringRef)string);

// left column form
CGMutablePathRef leftColumnPath = CGPathCreateMutable();
CGPathAddRect(leftColumnPath, NULL,
CGRectMake(0, 0,
self.bounds.size.width/2.0,
self.bounds.size.height));

// left column frame
CTFrameRef leftFrame = CTFramesetterCreateFrame(framesetter,
CFRangeMake(0, 0),
leftColumnPath, NULL);

// right column form
CGMutablePathRef rightColumnPath = CGPathCreateMutable();
CGPathAddRect(rightColumnPath, NULL,
CGRectMake(self.bounds.size.width/2.0, 0,
self.bounds.size.width/2.0,
self.bounds.size.height));

NSInteger rightColumStart = CTFrameGetVisibleStringRange(leftFrame).length;

// right column frame
CTFrameRef rightFrame = CTFramesetterCreateFrame(framesetter,
CFRangeMake(rightColumStart, 0),
rightColumnPath,
NULL);

// flip the coordinate system
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetTextMatrix(context, CGAffineTransformIdentity);
CGContextTranslateCTM(context, 0, self.bounds.size.height);
CGContextScaleCTM(context, 1.0, -1.0);

// draw
CTFrameDraw(leftFrame, context);
CTFrameDraw(rightFrame, context);

// cleanup
CFRelease(leftFrame);
CGPathRelease(leftColumnPath);
CFRelease(rightFrame);
CGPathRelease(rightColumnPath);
CFRelease(framesetter);
CFRelease(helvetica);
CFRelease(helveticaBold);
[string release];
}

布局功能:

下划线功能:
// pack it into attributes dictionary
NSDictionary *attributesDict = [NSDictionary dictionaryWithObjectsAndKeys:
(id)sysUIFont, (id)kCTFontAttributeName,
color, (id)kCTForegroundColorAttributeName,
underline, (id)kCTUnderlineStyleAttributeName, nil];

Underlining is not a feature of the font itself, but of NSAttributedString, likely because you can underline text in ANY font. These are your options:

None

Single Line

Double Line

Thick Line



These can be bitwise OR combined with several underlining line styles:

Solid Line

Dotted Line

Dashed Line

Dash-Dotted Line

Dash-Dot-Dotted Lin



删除线功能
// add custom attribute
[string addAttribute:@"DTCustomStrikeOut"
  value:[NSNumber numberWithBool:YES]
  range:NSMakeRange(18, 138)];


// reset text position
CGContextSetTextPosition(context, 0, 0);

// get lines
CFArrayRef leftLines = CTFrameGetLines(leftFrame);
CGPoint *origins = malloc(sizeof(CGPoint)*[(NSArray *)leftLines count]);
CTFrameGetLineOrigins(leftFrame,
CFRangeMake(0, 0), origins);
NSInteger lineIndex = 0;

for (id oneLine in (NSArray *)leftLines)
{
CFArrayRef runs = CTLineGetGlyphRuns((CTLineRef)oneLine);
CGRect lineBounds = CTLineGetImageBounds((CTLineRef)oneLine, context);

lineBounds.origin.x += origins[lineIndex].x;
lineBounds.origin.y += origins[lineIndex].y;
lineIndex++;
CGFloat offset = 0;

for (id oneRun in (NSArray *)runs)
{
CGFloat ascent = 0;
CGFloat descent = 0;

CGFloat width = CTRunGetTypographicBounds((CTRunRef) oneRun,
CFRangeMake(0, 0),
&ascent,
&descent, NULL);

NSDictionary *attributes = (NSDictionary *)CTRunGetAttributes((CTRunRef) oneRun);

BOOL strikeOut = [[attributes objectForKey:@"DTCustomStrikeOut"] boolValue];

if (strikeOut)
{
CGRect bounds = CGRectMake(lineBounds.origin.x + offset,
lineBounds.origin.y,
width, ascent + descent);

// don't draw too far to the right
if (bounds.origin.x + bounds.size.width > CGRectGetMaxX(lineBounds))
{
bounds.size.width = CGRectGetMaxX(lineBounds) - bounds.origin.x;
}

// get text color or use black
id color = [attributes objectForKey:(id)kCTForegroundColorAttributeName];

if (color)
{
CGContextSetStrokeColorWithColor(context, (CGColorRef)color);
}
else
{
CGContextSetGrayStrokeColor(context, 0, 1.0);
}

CGFloat y = roundf(bounds.origin.y + bounds.size.height / 2.0);
CGContextMoveToPoint(context, bounds.origin.x, y);
CGContextAddLineToPoint(context, bounds.origin.x + bounds.size.width, y);

CGContextStrokePath(context);
}

offset += width;
}
}

// cleanup
free(origins);


详细介绍:

http://www.cocoanetics.com/2011/01/befriending-core-text/
Share: