RSS

Category Archives: Objective-C

解决SBJSON中存在的线程安全问题

iOS平台上的JSON库有很多,除了SBJSON(原JSON Framework),iOS5中系统提供了NSJSONSerialization,其他优秀的JSON库还有JSONKit,TouchJSON等。由于历史原因,我目前所在的项目使用SBJSON。

SBJSON中对SBJsonStreamParserState和SBJsonStreamWriterState使用了单例模式,代码如下:

#define SINGLETON \
+ (id)sharedInstance { \
    static id state = nil; \
    if (!state) state = [[self alloc] init]; \
    return state; \
}

这段代码显然不是线程安全的,所以可能出现创建多个实例,同时在ARC下,对state再次赋值,会release之前的state。

同时SBJsonStreamParser与SBJsonStreamWriter中state属性是unsafe_unretained的(如下):

@property (nonatomic, unsafe_unretained) SBJsonStreamParserState *state;

这就导致了state已经没有了strong的引用,会被系统回收。这时再向state发送消息的话,就会发生message send to dealloced object或者[Class] can not respond to selector [Selector]之类的错误,进而发生Crash。

解决上述问题最直接的方法就是将SINGLETON改为线程安全的(如下):

#define SINGLETON \
+ (id)sharedInstance { \
    static id state = nil; \
    static dispatch_once_t once = 0; \
    dispatch_once(&once, ^{state = [[self alloc] init];}); \
    return state; \
}

相关的代码改动请查阅github上的提交:
https://github.com/AlenZhou/json-framework/commit/64e112f6f6a057ebcd65d14ba7f26e52cfb269cc


 
添加留言

Posted by on 七月 30, 2012 in Objective-C

 

Tags: , , , ,

危险的dictionaryWithObjectsAndKeys

使用NSDictionary的时候,最常见的就是采用[dic dictionaryWithObjectsAndKeys:....,nil];初始化一个NSDictionary,但是这种用法也许会带来意想不到的问题。

比方说如下代码:

    NSString* string1 = nil;
    NSString* string2 = @"string2";
    NSDictionary* dic = [NSDictionary dictionaryWithObjectsAndKeys:
                         string1, @"string1",
                         string2, @"string2",
                         @"string3", @"string3", nil];

string1为nil,不仅会使从dic中取string2时发现string2为nil,并且在取我们认为肯定不为nil的string3时,string3也为nil,这就有可能引发各种意外。

那么解决方案就是当object有可能为nil的时候,采用setObject:forKey:

    NSString* string1 = nil;
    NSString* string2 = @"string2";
    NSMutableDictionary* dic = [NSMutableDictionary dictionary];
    if (string1) {
        [dic setObject:string1 forKey:@"string1"];
    }
    if (string2) {
        [dic setObject:string2 forKey:@"string2"];
    }
    [dic setObject:@"string3" forKey:@"string3"];

当然还有更便捷的方法,使用setValue:forKey:

    NSString* string1 = nil;
    NSString* string2 = @"string2";
    NSMutableDictionary* dic = [NSMutableDictionary dictionary];
    [dic setValue:string1 forKey:@"string1"];
    [dic setValue:string2 forKey:@"string2"];
    [dic setValue:@"string3" forKey:@"string3"];

请注意,setValue:forKey:与setObject:forKey:不完全等同,最大的区别有两点:

1. setValue:forKey:只接受NSString*类型的key
2. setValue:forKey:当value为nil时,将调用removeObjectForKey:

 
添加留言

Posted by on 五月 21, 2012 in Objective-C

 

Tags: , , , ,

__bridge,__bridge_retained和__bridge_transfer的意思,区别与使用

使用ARC能帮我们减轻不少内存管理方面的负担,尤其是对用惯了Java的程序员来说。但是像我这种Java基础本身就不牢固,做了两年的iOS已经习惯手动管理内存的半吊子,使用ARC还是经常碰壁。

最近碰到了CFObject和NSObject转换的问题,由于ARC不能管理Core Foundation Object的生命周期,所以在Core Foundation和ARC之间,我们需要使用到__bridge,__bridge_retained和__bridge_transfer三个转换关键字。

根据苹果官方的文档(https://developer.apple.com/library/ios/#releasenotes/ObjectiveC/RN-TransitioningToARC/Introduction/Introduction.html):

__bridge只做类型转换,但是不修改对象(内存)管理权;

__bridge_retained(也可以使用CFBridgingRetain)将Objective-C的对象转换为Core Foundation的对象,同时将对象(内存)的管理权交给我们,后续需要使用CFRelease或者相关方法来释放对象;

__bridge_transfer(也可以使用CFBridgingRelease)将Core Foundation的对象转换为Objective-C的对象,同时将对象(内存)的管理权交给ARC。

 
添加留言

Posted by on 三月 20, 2012 in Objective-C

 

Tags: , , , , , ,

Mac OS X中通过程序修改系统网络设置的proxies

希望在Mac OS X中通过SSH代理上网的朋友请查看Mac OS X中使用SSH连接Dreamhost建立SOCKS代理上网。本文仅探讨通过程序(Objective-C或者Shell)修改设置中的代理选项。

遇到的问题:
在Mac OS X中,希望通过程序修改System Preferences->Network->AirPort->Advanced->Proxies->SOCKS Proxy的勾选或者说是SOCKSEnable的状态。

解决方案:
使用命令行工具/ usr/sbin/networksetup,networksetup -setsocksfirewallproxystate “AirPort” “on” 即可启用AirPort的SOCKS Proxy,networksetup -setsocksfirewallproxy “AirPort” “127.0.0.1″ “7070″ 即可修改AirPort的SOCKS Proxy Server为127.0.0.1,端口为7070,同时启用SOCKS Proxy。
知道networksetup之后,再通过NSTask执行上述的命令相信大家都会,就不再赘述了。
当然,networksetup实际上是非常强大的,想要了解更多networksetup的用法请查看networksetup Mac OS X的Manual Page

至于通过SystemConfiguration Framework和Security Framework的Authorization来修改Mac OS X的网络设置,目前SCDynamicStoreSetNotificationKeys是可以监测网络设置的变动,但是即使AuthorizationCopyRights成功之后,SCDynamicStoreSetValue依然失败,会返回如下信息:
Error Domain=com.apple.SystemConfiguration Code=1003 “The operation couldn’t be completed. (com.apple.SystemConfiguration error 1003 – Permission denied)” UserInfo=….{NSDescription=Permission denied}“ 。
如果之后有时间回头再看看SystemConfiguration Framework和Security Framework,并解决了这个问题,我也会更新在这里的。

详情如下: 查看全文 »

 
2 Comments

Posted by on 一月 5, 2012 in Mac OS, Objective-C

 

Tags: , , , , , , , , ,