文章

Mac Xcode

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));

本文由作者按照 CC BY 4.0 进行授权