Mac Xcode
#
查询xcode编译宏
clang -dM -E -arch armv7 -x c /dev/null » armv7.txt clang -dM -E -arch armv7s -x c /dev/null » armv7s.txt clang -dM -E -arch arm64 -x c /dev/null » arm64.txt clang -dM -E -arch i386 -x c /dev/null » i386.txt clang -dM -E -arch x86_64 -x c /dev/null » x86_64.txt
用于在代码中区分不同的CPU或者运行环境 #define ARM_ARCH_7A 1 #define ARM_ARCH_7S 1 #define ARM64_ARCH_8 1 arm64 #define i386 1 #define x86_64 1
MAC 显示 RGB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
NSImage *imageFromRGB32(unsigned char*buf, int width, int height)
{
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CFDataRef data = CFDataCreateWithBytesNoCopy(kCFAllocatorDefault, buf, width*4*height,kCFAllocatorNull);
CGDataProviderRef provider = CGDataProviderCreateWithCFData(data);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGImageRef cgImage = CGImageCreate(width,height,8,32,width*4, colorSpace,
bitmapInfo, provider,
NULL,NO, kCGRenderingIntentDefault);
CGColorSpaceRelease(colorSpace);
NSImage *image = [[NSImage alloc] autorelease];
NSSize nssize;
nssize.width = width;
nssize.height = height;
[image initWithCGImage:cgImage size:nssize];
CGImageRelease(cgImage);
CGDataProviderRelease(provider);
CFRelease(data);
return image;
}
解析json
1
2
3
4
5
6
7
8
9
10
11
12
- (IBAction)btnPressIOS5Json:(id)sender {
NSError *error;
//加载一个NSURL对象
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://m.weather.com.cn/data/101180601.html"]];
//将请求的url数据放到NSData对象中
NSData *response = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
//IOS5自带解析类NSJSONSerialization从response中解析出数据放到字典中
NSDictionary *weatherDic = [NSJSONSerialization JSONObjectWithData:response options:NSJSONReadingMutableLeaves error:&error];
NSDictionary *weatherInfo = [weatherDic objectForKey:@"weatherinfo"];
txtView.text = [NSString stringWithFormat:@"今天是 %@ %@ %@ 的天气状况是:%@ %@ ",[weatherInfo objectForKey:@"date_y"],[weatherInfo objectForKey:@"week"],[weatherInfo objectForKey:@"city"], [weatherInfo objectForKey:@"weather1"], [weatherInfo objectForKey:@"temp1"]];
NSLog(@"weatherInfo字典里面的内容为--》%@", weatherDic );
}
ios 读取资源文件
iPhone中如何从Application Bundle中读取文件
首先必须将文件加入Xcode工程的Resources目录。然后可以如下访问文件,假设文件为MyFile.txt:
1
2
3
4
5
6
7
8
9
10
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"MyFile" ofType:@"txt"];
NSData *myData = [NSData dataWithContentsOfFile:filePath];
if (myData) {
// do something useful
}
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"MyFile" ofType:@"txt"];
NSData *myData = [NSData dataWithContentsOfFile:filePath];
if (myData) {
// do something useful
}
一段将help文本文件读入UIWebView的完整示例:
Java代码
1
2
3
4
5
6
7
8
9
10
11
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"HelpDoc" ofType:@"htm"];
NSData *htmlData = [NSData dataWithContentsOfFile:filePath];
if (htmlData) {
[webView loadData:htmlData MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:[NSURL URLWithString:@"http://iphoneincubator.com"]];
}
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"HelpDoc" ofType:@"htm"];
NSData *htmlData = [NSData dataWithContentsOfFile:filePath];
if (htmlData) {
[webView loadData:htmlData MIMEType:@"text/html" textEncodingName:@"UTF-8" baseURL:[NSURL URLWithString:@"http://iphoneincubator.com"]];
}
如果想将文件读入字符串,则可以用UITextView显示,例如:
Java代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"important" ofType:@"txt"];
if (filePath) {
NSString *myText = [NSString stringWithContentsOfFile:filePath];
if (myText) {
textView.text= myText;
}
}
NSString *filePath = [[NSBundle mainBundle] pathForResource:@"important" ofType:@"txt"];
if (filePath) {
NSString *myText = [NSString stringWithContentsOfFile:filePath];
if (myText) {
textView.text= myText;
}
}
–
macosx 显示隐藏文件
打开终端,输入:
此命令显示隐藏文件
defaults write com.apple.finder AppleShowAllFiles -bool true
此命令关闭显示隐藏文件
defaults write com.apple.finder AppleShowAllFiles -bool false
objc 计算运行时间
第一种:(最简单的NSDate)
1
2
3
NSDate* tmpStartData = [NSDate date]; //You code here...
double deltaTime = [[NSDate date] timeIntervalSinceDate:tmpStartData];
NSLog(@"cost time = %f", deltaTime);
第二种:(将运行代码放入下面的Block中,返回时间)
1
2
3
4
5
6
7
8
9
10
11
12
import <mach/mach_time.h> // for mach_absolute_time() and friends
CGFloat BNRTimeBlock (void (^block)(void)) {
mach_timebase_info_data_t info;
if (mach_timebase_info(&info) != KERN_SUCCESS)
return -1.0;
uint64_t start = mach_absolute_time ();
block ();
uint64_t end = mach_absolute_time ();
uint64_t elapsed = end - start;
uint64_t nanos = elapsed * info.numer / info.denom;
return (CGFloat)nanos / NSEC_PER_SEC;
}
第三种:
1
2
3
4
5
6
7
double t(double last, char_ key){
clock_t now = clock();
printf("time:%fs \t key:%s \n", (last != 0) ? (double)(now - last) / CLOCKS_PER_SEC : 0, key);
return now;
}
double t1 = t(0, "");
//do something t(t1, "end");
iOS9适配中出现的坑
网络请求默认HTTPS Bitcode 设置信任 字体 iOS8中,字体是Helvetica,中文的字体有点类似于“华文细黑”。只是苹果手机自带渲染,所以看上去可能比普通的华文细黑要美观。iOS9中,中文系统字体变为了专为中国设计的“苹方” 有点类似于一种word字体“幼圆”。字体有轻微的加粗效果,并且最关键的是字体间隙变大了!所以很多原本写死了width的label可能会出现“…”的情况。
64位升级笔记
ios64位升级记录 首先要升级底层库,添加arm64编译库,考虑到调试需求,还需要编译x86_64库 submodules/build/iphone-config.site 文件添加两种host,arm64和x86_64.建议在host里面把arm64改为aarch64,否则老版本有很多configure不识别arm64 这种host 其中x86_64 属于模拟器架构, 编译选项添加 -arch x86_64 arm64数据真机架构,编译选项添加 -arch arm64 64位架构的时候,CFLAGS添加 -DANTLR3_USE_64BIT=1,用于antlr3 的64位bit处理
在makefile 添加 build_x64: make -f builder-iphone-os.mk host=x86_64-apple-darwin $(LINPHONE_OPTIONS) all build_arm64: make -f builder-iphone-os.mk host=arm64-apple-darwin $(LINPHONE_OPTIONS) all 可以执行 make build_arm64 或者 make build_x64 来编译底层库 arm64 的问题前面提到过,主要是某些configure 不识别 arm64, 可以通过改config相关文件,或者改为aarch64-apple-darwin 来通过脚本处理 x86_64 的问题在于某些底层库,比如mediastreamer2 认为这个属于macosx真机架构,底层脚本和iphone-config.site提供的cflags mios-simulator-version-min 有冲突,在configure文件把x86_64-apple-darwin 改为ios架构就可以了 编译好脚本库后,需要通过 lipo 来合并不同架构的底层库
UI层
在Project和Target添加arm64 x86_64架构 在XXVideoSettingViwController.m添加 #import <sys/sysctl.h> 避免 sysctlbyname 函数找不到定义 xxphone_iphone_log_handler在64位时运行会crash,禁用掉,程序可以通过编译 这时程序就可以在模拟器和真机上运行了 其它功能运行正常,但是视频呼叫会crash,禁用log会导致看不到debug信息,跟踪v2phone_iphone_log_handler,会发现 NSString* formatedString = [[NSString alloc] initWithFormat:format arguments:args]; 这个地方有时候会crash,但是NSLogv(format, args);不会。通过NSLogv(format, args);来跟踪ios运行步骤,crash发生在coreapi部分,最后的步骤中有一个指针地址为0x08 的,但是上一步指针正常,在上一步进行类型转换也一样。仔细看看,发现这是一个回调函数,而且还是变参的!!!!修改回调函数类型位固定参数,然后根据build返回的错误修改coreapi 和相关代码,编译正常后运行XXphone,视频通信也正常了。
xxphone原来自带的ffmpeg+x264 不支持aarch 的汇编,在arm64下编解码不能使用neon加速。需要更换ffmpeg+x264 的版本
x264 更换还好,configure的时候加一个 –disable-opencl 就可以了
ffmpeg比较困难,更新版本后,arm64 汇编可以启用 , armv7 armv7s 汇编启用失败,查明原因是 gas-preporcess.pl脚本版本不对,更新即可。
重新编译底层库,运行xxPhone,视频功能也正常,但是查看IPCamera会Crash,查明原因是mediastreamer2库的videodec.c 里面视频解码函数 AVFrame orig没有初始化造成的,修改后xxphone正常。
ios SQLite 封装库 FMDB
一、什么是FMDB
OS中原生的SQLite API在使用上大部分都是C语言代码,在使用时,非常不便,因此便出现了很多针对SQLite封装的第三方框架,其中FMDB就是其中一个优秀的框架,FMDB以OC的方式封装了SQLite的C语言API, 它的出现使操作SQLite变得更简洁易用,相比苹果自带的Core Data框架,FMDB显得更加轻量级,灵活。
FMDB的下载地址:https://github.com/ccgus/fmdb 在FMDB下载文件后,工程中必须导入如下文件,并使用 libsqlite3.dylib 依赖包
二、FMDB常用类
FMDatabase : 一个单一的SQLite数据库,用于执行SQL语句。 FMResultSet :执行查询一个FMDatabase结果集。 FMDatabaseQueue :在多个线程来执行查询和更新时会使用这个类
三、操作数据库 1、创建并且打开数据库
1、获取数据库对象
1
2
3
NSString *path=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
path=[path stringByAppendingPathComponent:@"test.sqlite"];
dataBase=[FMDatabase databaseWithPath:path];
2、打开数据库,如果不存在则创建并且打开
1
2
3
4
BOOL open=[dataBase open];
if(open){
NSLog(@"数据库打开成功");
}
3、创建表
1
2
3
4
5
NSString * create1=@"create table if not exists t_user(id integer autoincrement primary key,name varchar)";
BOOL c1= [dataBase executeUpdate:create1];
if(c1){
NSLog(@"创建表成功");
}
4、插入、删除、修改数据
1
NSString * insertSql=@"insert into t_user(id,name) values(?,?)";
插入语句1
1
bool inflag1=[dataBase executeUpdate:insertSql,@(2),@"admin"];
插入语句2
1
bool inflag2=[dataBase executeUpdate:insertSql withArgumentsInArray:@[@"admin",@(5)]];
插入语句3
1
bool inflag3=[dataBase executeUpdateWithFormat:@"insert into t_user(id,name) values(%@,%d)",@"admin",6];
删除语句
1
2
3
NSString * delete=@"delete from t_user";
BOOL dflag= [dataBase executeUpdate:delete];
if(dflag){ NSLog(@"删除成功"); }
修改语句
1
2
3
4
5
NSString *update=@" update t_user set name=? ";
BOOL flag= [dataBase executeUpdate:update,@"zhangsan"];
if(flag){
NSLog(@"修改成功");
}
查询数据
FMDB的FMResultSet提供了多个方法来获取不同类型的数据
1
2
3
4
5
6
7
8
9
NSString * sql=@" select * from t_user ";
FMResultSet *result=[dataBase executeQuery:sql];
while(result.next){
int ids=[result intForColumn:@"id"];
NSString * name=[result stringForColumn:@"name"];
int ids=[result intForColumnIndex:0];
NSString * name=[result stringForColumnIndex:1];
NSLog(@"%@,%d",name,ids);
}
如果应用中使用了多线程操作数据库,那么就需要使用FMDatabaseQueue来保证线程安全了。 应用中不可在多个线程中共同使用一个FMDatabase对象操作数据库,这样会引起数据库数据混乱。
为了多线程操作数据库安全,FMDB使用了FMDatabaseQueue,使用FMDatabaseQueue很简单,首先用一个数据库文件地址来初使化FMDatabaseQueue,然后就可以将一个闭包(block)传入inDatabase方法中。 在闭包中操作数据库,而不直接参与FMDatabase的管理
2、多线程操作
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
NSString *path=NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)[0];
path=[path stringByAppendingPathComponent:@"test.sqlite"];
FMDatabaseQueue * queue=[FMDatabaseQueue databaseQueueWithPath:path];
[queue inDatabase:^(FMDatabase *db) {
NSString * create=@"create table if not exists t_book(id integer,name varchar)";
BOOL c1= [db executeUpdate:create];
if(c1){NSLog(@"成功"); } }];
[queue inDatabase:^(FMDatabase *db) {
NSString * insertSql=@"insert into t_book(id,name) values(?,?)";
//插入语句1
bool inflag=[db executeUpdate:insertSql,@(2),@"admin"];
if(inflag){
NSLog(@"插入成功");
} }];
[queue inDatabase:^(FMDatabase *db) {
FMResultSet * data=[db executeQuery:@" select * from t_book "];
while (data.next) {
int ids=[data intForColumn:@"id"];
NSString *name=[data stringForColumn:@"name"];
NSLog(@"%@",name);
NSLog(@"%i",ids);
}
}];
iOS 长连接问题
在开发ios长连接游戏的过程中遇到一个问题:在游戏运行过程中玩家按下home键或者其他原因游戏被挂起,socket连接不会断开,服务器为了节省资源,在一段时间后会主动关闭这个连接。当玩家再次切回到游戏后,前端并不知道这个连接已经断开了,继续通过断开的socket发送消息,这时候send函数会触发SIGPIPE异常导致程序崩溃。
解决这个问题我们需要在send的时候检测到服务器已经关闭连接,进行重新连接。正常情况下send函数返回-1表示发送失败,但是在IOS上SIGPIPE在send返回之前就终止了进程,所以我们需要忽略SIGPIPE,让send正常返回-1,然后重新连接服务器。
查阅资料后找到了两个方法: 1) 使用 signal(SIGPIPE, SIGIGN) 忽略SIGPIPE。经实验在ios7模拟器上虽然xcode还是会捕获SIGPIPE,但是程序不会崩溃,继续后可以执行。但是在真机上依然会崩溃。 2) 使用 SONOSIGPIPE。 经实验在多个ios版本下都不再触发SIGPIPE,完美解决问题。
int set = 1; setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&set, sizeof(int));