如何使用GCD

什么是GCDGrand Central Dispatch (GCD)是Apple开发的一个多核编程的解决方法。该方法在Mac OS X 10.6雪豹中首次推出,并随后被引入到了iOS4.0中。GCD是一个替代诸如NSThread, NSOperationQueue, NSInvocationOperation等技术的很高效和强大的技术,它看起来象就其它语言的闭包(Closure)一样,但苹果把它叫做 blocks。
应用举例让我们来看一个编程场景。我们要在iphone上做一个下载网页的功能,该功能非常简单,就是在iphone上放置一个按钮,点击该按钮时,显示一个转动的圆圈,表示正在进行下载,下载完成之后,将内容加载到界面上的一个文本控件中。
不用GCD前虽然功能简单,但是我们必须把下载过程放到后台线程中,否则会阻塞UI线程显示。所以,如果不用GCD, 我们需要写如下3个方法:

* someClick 方法是点击按钮后的代码,可以看到我们用NSInvocationOperation建了一个后台线程,并且放到NSOperationQueue中。后台线程执行download方法。
* download 方法处理下载网页的逻辑。下载完成后用performSelectorOnMainThread执行download_completed 方法。
* download_completed 进行clear up的工作,并把下载的内容显示到文本控件中。
这3个方法的代码如下。可以看到,虽然 开始下载 -> 下载中 -> 下载完成 这3个步骤是整个功能的三步。但是它们却被切分成了3块。他们之间因为是3个方法,所以还需要传递数据参数。如果是复杂的应用,数据参数很可能就不象本例 子中的NSString那么简单了,另外,下载可能放到Model的类中来做,而界面的控制放到View Controller层来做,这使得本来就分开的代码变得更加散落。代码的可读性大大降低。
static NSOperationQueue * queue;
- (IBAction)someClick:(id)sender {
self.indicator.hidden = NO;
[self.indicator startAnimating];
queue = [[NSOperationQueue alloc] init];
NSInvocationOperation * op = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download) object:nil] autorelease];
[queue addOperation:op];
}
- (void)download {
NSURL * url = [NSURL URLWithString:@"http://blog.iosxcode4.com"];
NSError * error;
NSString * data = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
if (data != nil) {
[self performSelectorOnMainThread:@selector(download_completed:) withObject:data waitUntilDone:NO];
} else {
NSLog(@”error when download:%@”, error);
[queue release];
}
}
- (void) download_completed:(NSString *) data {
NSLog(@”call back”);
[self.indicator stopAnimating];
self.indicator.hidden = YES;
self.content.text = data;
[queue release];
}

使用GCD后如果使用GCD,以上3个方法都可以放到一起,如下所示:
// 原代码块一
self.indicator.hidden = NO;
[self.indicator startAnimating];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 原代码块二
NSURL * url = [NSURL URLWithString:@"http://blog.iosxcode4.com"];
NSError * error;
NSString * data = [NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
if (data != nil) {
// 原代码块三
dispatch_async(dispatch_get_main_queue(), ^{
[self.indicator stopAnimating];
self.indicator.hidden = YES;
self.content.text = data;
});
} else {
NSLog(@”error when download:%@”, error);
}
});

首先我们可以看到,代码变短了。因为少了原来3个方法的定义,也少了相互之间需要传递的变量的封装。
另外,代码变清楚了,虽然是异步的代码,但是它们被GCD合理的整合在一起,逻辑非常清晰。如果应用上MVC模式,我们也可以将View Controller层的回调函数用GCD的方式传递给Modal层,这相比以前用@selector的方式,代码的逻辑关系会更加清楚。
GCD的定义简单GCD的定义有点象函数指针,差别是用 ^ 替代了函数指针的 * 号,如下所示:
// 申明变量
(void) (^loggerBlock)(void);
// 定义
loggerBlock = ^{
NSLog(@”Hello world”);
};
// 调用
loggerBlock();

但是大多数时候,我们通常使用内联的方式来定义它,即将它的程序块写在调用的函数里面,例如这样:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// something
});

系统提供的dispatch方法为了方便地使用GCD,苹果提供了一些方法方便我们将block放在主线程 或 后台线程执行,或者延后执行。使用的例子如下:
// 后台执行:
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// something
});
// 主线程执行:
dispatch_async(dispatch_get_main_queue(), ^{
// something
});
// 一次性执行:
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// code to be executed once
});
// 延迟2秒执行:
double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
// code to be executed on the main queue after delay
});

dispatch_queue_t 也可以自己定义,如要要自定义queue,可以用dispatch_queue_create方法,示例如下:
dispatch_queue_t urls_queue = dispatch_queue_create(“blog.devtang.com”, NULL);
dispatch_async(urls_queue, ^{
// your code
});
dispatch_release(urls_queue);

另外,GCD还有一些高级用法,例如让后台2个线程并行执行,然后等2个线程都结束后,再汇总执行结果。这个可以用dispatch_group, dispatch_group_async 和 dispatch_group_notify来实现,示例如下:

dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
// 并行执行的线程一
});
dispatch_group_async(group, dispatch_get_global_queue(0,0), ^{
// 并行执行的线程二
});
dispatch_group_notify(group, dispatch_get_global_queue(0,0), ^{
// 汇总结果
});

后台运行GCD的另一个用处是可以让程序在后台较长久的运行。在没有使用GCD时,当app被按home键退出后,app仅有最多5秒钟的时候做一些保存或 清理资源的工作。但是在使用GCD后,app最多有10分钟的时间在后台长久运行。这个时间可以用来做清理本地缓存,发送统计数据等工作。
总结
总体来说,GCD能够极大地方便开发者进行多线程编程。如果你的app不需要支持iOS4.0以下的系统,那么就应该尽量使用GCD来处理后台线程和UI线程的交互。
转载自:唐巧的技术博客 http://blog.devtang.com/blog/2012/02/22/use-gcd/

Posted in iphone开发 | Tagged , , , , , | Leave a comment

iOs5用openurl打开设置选项

在代码中调用如下代码:

NSURL*url=[NSURL URLWithString:@"prefs:root=WIFI"];
[[UIApplication sharedApplication] openURL:url];
即可跳转到设置页面的对应项。

About — prefs:root=General&path=About
Accessibility — prefs:root=General&path=ACCESSIBILITY
Airplane Mode On — prefs:root=AIRPLANE_MODE
Auto-Lock — prefs:root=General&path=AUTOLOCK
Brightness — prefs:root=Brightness
Bluetooth — prefs:root=General&path=Bluetooth
Date & Time — prefs:root=General&path=DATE_AND_TIME
FaceTime — prefs:root=FACETIME
General — prefs:root=General
Keyboard — prefs:root=General&path=Keyboard
iCloud — prefs:root=CASTLE
iCloud Storage & Backup — prefs:root=CASTLE&path=STORAGE_AND_BACKUP
International — prefs:root=General&path=INTERNATIONAL
Location Services — prefs:root=LOCATION_SERVICES
Music — prefs:root=MUSIC
Music Equalizer — prefs:root=MUSIC&path=EQ
Music Volume Limit — prefs:root=MUSIC&path=VolumeLimit
Network — prefs:root=General&path=Network
Nike + iPod — prefs:root=NIKE_PLUS_IPOD
Notes — prefs:root=NOTES
Notification — prefs:root=NOTIFICATIONS_ID
Phone — prefs:root=Phone
Photos — prefs:root=Photos
Profile — prefs:root=General&path=ManagedConfigurationList
Reset — prefs:root=General&path=Reset
Safari — prefs:root=Safari
Siri — prefs:root=General&path=Assistant
Sounds — prefs:root=Sounds
Software Update — prefs:root=General&path=SOFTWARE_UPDATE_LINK
Store — prefs:root=STORE
Twitter — prefs:root=TWITTER
Usage — prefs:root=General&path=USAGE
VPN — prefs:root=General&path=Network/VPN
Wallpaper — prefs:root=Wallpaper
Wi-Fi — prefs:root=WIFI


Posted in xcode4 | Tagged , | Leave a comment

iOS支持Gif格式图片动画

//AnimatedGif.h
#import <UIKit/UIKit.h>

@interface AnimatedGifFrame : NSObject
{
NSData *data;
NSData *header;
double delay;
int disposalMethod;
CGRect area;
}

@property (nonatomic, copy) NSData *header;
@property (nonatomic, copy) NSData *data;
@property (nonatomic) double delay;
@property (nonatomic) int disposalMethod;
@property (nonatomic) CGRect area;

@end

@interface AnimatedGif : NSObject
{
NSData *GIF_pointer;
NSMutableData *GIF_buffer;
NSMutableData *GIF_screen;
NSMutableData *GIF_global;
NSMutableArray *GIF_frames;

bool busyDecoding;

int GIF_sorted;
int GIF_colorS;
int GIF_colorC;
int GIF_colorF;

int dataPointer;

}

@property bool busyDecoding;

+ (id)gifWithPath:(NSString*)absolutePath;
- (id)initWithPath:(NSString*)absolutePath;
- (void) decodeGIF:(NSData *)GIF_Data;
- (void) GIFReadExtensions;
- (void) GIFReadDescriptor;
- (bool) GIFGetBytes:(int)length;
- (bool) GIFSkipBytes: (int) length;
- (NSData*) getFrameAsDataAtIndex:(int)index;
- (NSArray *)frames;

@end

//AnimatedGif.m
#import “AnimatedGif.h”

@implementation AnimatedGifFrame

@synthesize data, delay, disposalMethod, area, header;

- (void) dealloc
{
[data release];
[header release];
[super dealloc];
}

@end

@implementation AnimatedGif

@synthesize busyDecoding;

+ (id)gifWithPath:(NSString*)absolutePath
{
AnimatedGif* gif = [[AnimatedGif alloc] initWithPath:absolutePath];

return [gif autorelease];
}

- (id) init
{
self = [super init];
if (self) {

}
return self;
}

- (id)initWithPath:(NSString*)absolutePath
{
self = [self init];
if (self) {
[self decodeGIF:[NSData dataWithContentsOfFile:absolutePath]];

}
return self;
}

- (void) dealloc
{
if (GIF_buffer != nil)
{
[GIF_buffer release];
}

if (GIF_screen != nil)
{
[GIF_screen release];
}

if (GIF_global != nil)
{
[GIF_global release];
}

[GIF_frames release];

[super dealloc];
}

//
- (void)decodeGIF:(NSData *)GIFData
{
GIF_pointer = GIFData;

if (GIF_buffer != nil)
{
[GIF_buffer release];
}

if (GIF_global != nil)
{
[GIF_global release];
}

if (GIF_screen != nil)
{
[GIF_screen release];
}

[GIF_frames release];

GIF_buffer = [[NSMutableData alloc] init];
GIF_global = [[NSMutableData alloc] init];
GIF_screen = [[NSMutableData alloc] init];
GIF_frames = [[NSMutableArray alloc] init];

// Reset file counters to 0
dataPointer = 0;

[self GIFSkipBytes: 6]; // GIF89a, throw away
[self GIFGetBytes: 7]; // Logical Screen Descriptor

// Deep copy
[GIF_screen setData: GIF_buffer];

// Copy the read bytes into a local buffer on the stack
// For easy byte access in the following lines.
int length = [GIF_buffer length];
unsigned char aBuffer[length];
[GIF_buffer getBytes:aBuffer length:length];

if (aBuffer[4] & 0×80) GIF_colorF = 1; else GIF_colorF = 0;
if (aBuffer[4] & 0×08) GIF_sorted = 1; else GIF_sorted = 0;
GIF_colorC = (aBuffer[4] & 0×07);
GIF_colorS = 2 << GIF_colorC;

if (GIF_colorF == 1)
{
[self GIFGetBytes: (3 * GIF_colorS)];

// Deep copy
[GIF_global setData:GIF_buffer];
}

unsigned char bBuffer[1];
while ([self GIFGetBytes:1] == YES)
{
[GIF_buffer getBytes:bBuffer length:1];

if (bBuffer[0] == 0x3B)
{ // This is the end
break;
}

switch (bBuffer[0])
{
case 0×21:
// Graphic Control Extension (#n of n)
[self GIFReadExtensions];
break;
case 0x2C:
// Image Descriptor (#n of n)
[self GIFReadDescriptor];
break;
}
}

// clean up stuff
[GIF_buffer release];
GIF_buffer = nil;

[GIF_screen release];
GIF_screen = nil;

[GIF_global release];
GIF_global = nil;
}

//
// Returns a subframe as NSMutableData.
// Returns nil when frame does not exist.
//
// Use this to write a subframe to the filesystems (cache etc);
- (NSData*) getFrameAsDataAtIndex:(int)index
{
if (index < [GIF_frames count])
{
return ((AnimatedGifFrame *)[GIF_frames objectAtIndex:index]).data;
}
else
{
return nil;
}
}

//
// Returns a subframe as an autorelease UIImage.
// Returns nil when frame does not exist.
//
// Use this to put a subframe on your GUI.
- (UIImage*) getFrameAsImageAtIndex:(int)index
{
NSData *frameData = [self getFrameAsDataAtIndex: index];
UIImage *image = nil;

if (frameData != nil)
{
image = [UIImage imageWithData:frameData];
}

return image;
}

//
// This method converts the arrays of GIF data to an animation, counting
// up all the seperate frame delays, and setting that to the total duration
// since the iPhone Cocoa framework does not allow you to set per frame
// delays.
//
// Returns nil when there are no frames present in the GIF, or
// an autorelease UIImageView* with the animation.

- (void)GIFReadExtensions
{
// 21! But we still could have an Application Extension,
// so we want to check for the full signature.
unsigned char cur[1], prev[1];
[self GIFGetBytes:1];
[GIF_buffer getBytes:cur length:1];

while (cur[0] != 0×00)
{

// TODO: Known bug, the sequence F9 04 could occur in the Application Extension, we
//       should check whether this combo follows directly after the 21.
if (cur[0] == 0×04 && prev[0] == 0xF9)
{
[self GIFGetBytes:5];

AnimatedGifFrame *frame = [[AnimatedGifFrame alloc] init];

unsigned char buffer[5];
[GIF_buffer getBytes:buffer length:5];
frame.disposalMethod = (buffer[0] & 0x1c) >> 2;
//NSLog(@”flags=%x, dm=%x”, (int)(buffer[0]), frame.disposalMethod);

// We save the delays for easy access.
frame.delay = (buffer[1] | buffer[2] << 8);

unsigned char board[8];
board[0] = 0×21;
board[1] = 0xF9;
board[2] = 0×04;

for(int i = 3, a = 0; a < 5; i++, a++)
{
board[i] = buffer[a];
}

frame.header = [NSData dataWithBytes:board length:8];
[GIF_frames addObject:frame];
[frame release];
break;
}

prev[0] = cur[0];
[self GIFGetBytes:1];
[GIF_buffer getBytes:cur length:1];
}
}

- (void) GIFReadDescriptor
{
[self GIFGetBytes:9];

// Deep copy
NSMutableData *GIF_screenTmp = [NSMutableData dataWithData:GIF_buffer];

unsigned char aBuffer[9];
[GIF_buffer getBytes:aBuffer length:9];

CGRect rect;
rect.origin.x = ((int)aBuffer[1] << 8 ) | aBuffer[0];
rect.origin.y = ((int)aBuffer[3] << 8 ) | aBuffer[2];
rect.size.width = ((int)aBuffer[5] << 8 ) | aBuffer[4];
rect.size.height = ((int)aBuffer[7] << 8 ) | aBuffer[6];

AnimatedGifFrame *frame = [GIF_frames lastObject];
frame.area = rect;

if (aBuffer[8] & 0×80) GIF_colorF = 1; else GIF_colorF = 0;

unsigned char GIF_code = GIF_colorC, GIF_sort = GIF_sorted;

if (GIF_colorF == 1)
{
GIF_code = (aBuffer[8] & 0×07);

if (aBuffer[8] & 0×20)
{
GIF_sort = 1;
}
else
{
GIF_sort = 0;
}
}

int GIF_size = (2 << GIF_code);

size_t blength = [GIF_screen length];
unsigned char bBuffer[blength];
[GIF_screen getBytes:bBuffer length:blength];

bBuffer[4] = (bBuffer[4] & 0×70);
bBuffer[4] = (bBuffer[4] | 0×80);
bBuffer[4] = (bBuffer[4] | GIF_code);

if (GIF_sort)
{
bBuffer[4] |= 0×08;
}

NSMutableData *GIF_string = [NSMutableData dataWithData:[[NSString stringWithString:@"GIF89a"] dataUsingEncoding: NSUTF8StringEncoding]];
[GIF_screen setData:[NSData dataWithBytes:bBuffer length:blength]];
[GIF_string appendData: GIF_screen];

if (GIF_colorF == 1)
{
[self GIFGetBytes:(3 * GIF_size)];
[GIF_string appendData:GIF_buffer];
}
else
{
[GIF_string appendData:GIF_global];
}

// Add Graphic Control Extension Frame (for transparancy)
[GIF_string appendData:frame.header];

char endC = 0x2c;
[GIF_string appendBytes:&endC length:sizeof(endC)];

size_t clength = [GIF_screenTmp length];
unsigned char cBuffer[clength];
[GIF_screenTmp getBytes:cBuffer length:clength];

cBuffer[8] &= 0×40;

[GIF_screenTmp setData:[NSData dataWithBytes:cBuffer length:clength]];

[GIF_string appendData: GIF_screenTmp];
[self GIFGetBytes:1];
[GIF_string appendData: GIF_buffer];

while (true)
{
[self GIFGetBytes:1];
[GIF_string appendData: GIF_buffer];

unsigned char dBuffer[1];
[GIF_buffer getBytes:dBuffer length:1];

long u = (long) dBuffer[0];

if (u != 0×00)
{
[self GIFGetBytes:u];
[GIF_string appendData: GIF_buffer];
}
else
{
break;
}

}

endC = 0x3b;
[GIF_string appendBytes:&endC length:sizeof(endC)];

// save the frame into the array of frames
frame.data = GIF_string;
}

/* Puts (int) length into the GIF_buffer from file, returns whether read was succesfull */
- (bool) GIFGetBytes: (int) length
{
if (GIF_buffer != nil)
{
[GIF_buffer release]; // Release old buffer
GIF_buffer = nil;
}

if ([GIF_pointer length] >= dataPointer + length) // Don’t read across the edge of the file..
{
GIF_buffer = (id)[[GIF_pointer subdataWithRange:NSMakeRange(dataPointer, length)] retain];
dataPointer += length;
return YES;
}
else
{
return NO;
}
}

/* Skips (int) length bytes in the GIF, faster than reading them and throwing them away.. */
- (bool) GIFSkipBytes: (int) length
{
if ([GIF_pointer length] >= dataPointer + length)
{
dataPointer += length;
return YES;
}
else
{
return NO;
}

}

- (NSArray *)frames
{
NSMutableArray *frames = [NSMutableArray arrayWithCapacity:100];
for(int i=0; i<100; i++)
{
UIImage *aImage = [self getFrameAsImageAtIndex:i];
if(!aImage)
break;
else
[frames addObject:aImage];
}
return frames;
}

@end

初始化方法

LoadingAnimationView继承自UIImageView

@implementation LoadingAnimationView
@synthesize gifs = _gifs;

- (id)initWithFrame:(CGRect)frame{

self = [super initWithFrame:frame];
if (self) {

self.backgroundColor = [UIColor clearColor];
AnimatedGif *aniGif = [[AnimatedGif alloc] init];
NSString *path = [[NSBundle mainBundle] pathForResource:@”loading” ofType:@”gif”];
[aniGif decodeGIF:[NSData dataWithContentsOfFile:path]];

_gifs = [[aniGif frames] retain];
self.animationImages = _gifs;
self.animationDuration = 0.1f*[_gifs count];
self.animationRepeatCount = 9999;
[aniGif release];
}
return self;
}

-(void)startAnimating
{
if(self.hidden)
self.hidden = NO;
[super startAnimating];
}

-(void)stopAnimating
{
[super stopAnimating];
self.hidden = YES;
}

- (void)dealloc {
[_gifs release];
[super dealloc];
}

Posted in iphone开发 | Tagged , , | Leave a comment

iPhone应用中资源Png图片的处理

 

有时候我们看到一个App,想看看他的一些界面是如何实现的,这个时候需要查看一下它的图片资源,不过iOS的png图片编译后一般的图片阅读器都是没法查看的,本文将告诉的原因和转换出原图的方法(得安装XCode)。

ipa 解压,将png相关文件夹拷贝出来,在命令行下使用/Developer/Platforms/iPhoneOS.platform/Developer /usr/bin/pngcrush -revert-iphone-optimizations xxx.png yyy.png

我们都知道一个编译好的iPhone app 其中的png图片一般普通的图片阅读器是无法直接读取的,这是因为XCode在编译的过程中,将图片进行了优化,实际上它已经不是一个png图片了。 这边有一些apple iPhone png自己格式的一些说明 http://iphonedevwiki.net/index.php/CgBI_file_format

在Png数据中,我们最关心的莫过于png的数据块,其中包含了png每一个像素的信息,当然了为了减少存储空间,这些像素信息都是压缩保存的。而且是使用zlib进行压缩的,压缩后 包含zlib header 信息,还有由于解压验证的crc信息。 而iPhone的CgBI格式的png则将原始的png图片作如下变化:

  • 增加一个新的关键块 CgBI Chunk 四个字节
  • zlib的header和CRC信息全部从IDAT中移除
  • 红蓝交换,每一个像素(RGBA)中的R和B进行调换变成BGRA ,解压后每一个像素有四个字节组成,也就是将每一个像素的 第一个字节和第三个字节调换
  • 透明像素处理 Premultiplied Alpha,这个的意思是为了图像加载变得更快,预先将Alpha的信息乘到像素的颜色信息中去,这样后期计算的时候就可以减少CPU或者GPU计算了

把一个正常的PNG图片优化成iPhone 的png图片格式可以使用XCode自带的工具 /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/pngcrush -iphone 还有一个第三方的开源工具也可以 https://github.com/DHowett/pincrush

如果你想把一个经过优化后的图片还原成普通图片阅读器可以查看的png图片,就是对上面的过程进行反向处理。 现在可以找到的第三方的转换的一般有如下几个 ipin.py(Python版本) http://www.axelbrz.com.ar/?mod=iphone-png-images-normalizer iPhonePNG(C版本) http://www.newsfirerss.com/blog/?p=176

经过本人测试,上面的这些转换工具都没有对图片alpha相关信息的做任何处理,也可能是别的原因,有一些图片转换后的结果和原始图片还是有出入的。

编译后如果使用第三方的python或者C版本的代码来转换,转换后的图片都是这样的,感觉边角的像素有点问题,不过大部分情况下 ,图片都是ok的

我尝试通过修改第三方的代码,想将Premultiplied Alpha 还原过去,但是还是存在各种问题,最终没有结果。
只能最终采用XCode自带的工具进行转换 `/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/pngcrush -revert-iphone-optimizations 1.png 2.png`
这个pngcrush是apple改自开源的pngcrush 只可惜苹果修改后的版本却没有开源出来。

为了避免每次都需要在命令行中进行操作,你可以通过automator新建一个shell的service

for path in "$@"
do mv "$path" "$path".tmp
/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin/pngcrush -revert-iphone-optimizations "$path".tmp "$path"
rm "$path".tmp
done 

当然你可以修改脚本,并可以作用于文件和文件夹,对目标进行判断,文件夹则递归文件夹中的png文件进行逐个处理。

原文:http://geeklu.com/2011/10/iphone-cgbi-png-format/

 

Posted in iphone开发 | Tagged , , , | Leave a comment

iOS下用sqlite数据库存储图片

在iOS下用sqlite数据库存储图片,先把你的图片转换成 NSData 形式,然后在数据库添加一行 blob 数据,代码如下(data就是图片) :

NSMutableString *insertSql = [[NSMutableString alloc] initWithString:@”INSERT INTO “];
[insertSql appendString:BLOB];
[insertSql appendString:@" ("];
[insertSql appendString:BLOB_DATA];
[insertSql appendString:@") VALUES(?1)"];
sqlite3_stmt *insert_statement = nil;
sqlite3 *database = 你的数据库;
if (sqlite3_prepare_v2(database, [insertSql UTF8String], -1, &insert_statement, NULL) == SQLITE_OK) {
sqlite3_bind_blob(insert_statement, 1, [data bytes], [data length], NULL);
if(sqlite3_step(insert_statement) != SQLITE_DONE) {
NSLog(@”Db error %s”, sqlite3_errmsg(database));
}
} else {
NSLog(@”Db error %s”, sqlite3_errmsg(database));
}
sqlite3_finalize(insert_statement);
[insertSql release];
原贴:http://heidianfeng.blog.163.com/blog/static/6184345620114164373763/

Posted in comefrom, iphone开发 | Tagged , | Leave a comment