设置标签 ‘Obj-C’

保存用户密码的安全方法

作为一名iPhone开发者, 你需要对你的用户安全负责. 请问, 你是怎么保存用户的密码的?

直接保存到plist里?
加密? AES? DES? 能保证你的代码不被反编译拿到你的加密Key?

这也未免太不苹果了吧. 我Google了一下, 国内的开发者根本没有注意到这个问题.
苹果系统中有个程序叫”钥匙串” (Keychain), 它不仅仅是你申请开发证书用的, 哈哈. 它可以存密码!
这也是苹果给出的保存密码的最佳解决方案.

iPhone中也有Keychain, 用过PushFix破解包(就是那个修复推送的小工具)的国内iPhone破解用户应该还有印象.

用原生的Security.framework就可以实现钥匙串的访问, 读写, 但是只能在真机上进行, 模拟器会出错. 在Github上, 有个封装的非常好的类 来实现这个功能, 让你既能在模拟器又能在真机上访问钥匙串.


//获取密码
+ (NSString *) getPasswordForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error;

//保存密码
+ (void) storeUsername: (NSString *) username andPassword: (NSString *) password forServiceName: (NSString *) serviceName updateExisting: (BOOL) updateExisting error: (NSError **) error;

//删除密码
+ (void) deleteItemForUsername: (NSString *) username andServiceName: (NSString *) serviceName error: (NSError **) error;

类的地址: http://github.com/ldandersen/scifihifi-iphone/tree/master/security

如何让某个ViewController支持屏幕旋转 来自Mars

看到这篇不错, 直接转载过来了, 没什么可解释的,一看就明白 :)

出处: http://www.marsiphone.cn/tag/uidevice/

整个程序需要支持横竖屏切换得时候,会比较简单,在每个ViewController 的

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

方法中,return YES; 就好。

可如果只是要某个VC( = View Controller)支持横竖屏切换呢?单独在那个view controller中像上面那样做是没有效果的。

这个时候我们可以取 UIDevice的 Orientation来判定:

1、在VC中注册 UIDevice 的 UIDeviceOrientationDidChangeNotification 通知:

NSNotificationCenter *center = [NSNotificationCenter defaultCenter];

[center addObserver:self selector:@selector(doRotate:) name:UIDeviceOrientationDidChangeNotification object:nil];

2、在自己的 doRotate函数里面处理:

- (void)doRotate:(NSNotification *)notification{

UIDevice *myDevice = [UIDevice currentDevice];

UIDeviceOrientation deviceOrientation = [myDevice orientation];

UIApplication *app = [UIApplication sharedApplication];

[app setStatusBarOrientation:deviceOrientation];

}

3.

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

也是要 return YES;

开发技巧: 利用lipo 编译合并iPhone模拟器和真机通用的静态类库

如何编译静态类库,大家已经比较熟悉了,而且现在网上也有很多教程,就不多罗唆了. 现在问题是, 我们编译好了会是两个版本的.a文件 分别用于模拟器和iPhone真机, 因为Mac和iPhone的CPU不同, 才造成了这样的情况. 有点像 PowerMac 和 InterMac.

屏幕快照 2010-01-01 下午09.34.54.png

在使用静态类库的时候, 我们如果想在模拟器调试, 就必须把用于模拟器版本的lib加到项目里, 同理要想运行在iPhone上, 我们又必须把真机lib也加到项目, 这样确保两个平台都能运行, 但问题是我们总有一个类库是不需要了, 在Snow Leopard的Xcode 3.2中编译的时候会出现一个警告: 没必要加上***.a. Xcode 3.1 也偶尔出现, 没有总结出规律来.

OK, 我们来解决这个问题!

假设两个版本的lib分别是 libIMIUI.s.a , libIMIUI.d.a 我们的目标是 把他们合并成无敌超级通用版的libIMIUI.a :)
打开命令行 Terminal.app 输入:

lipo -create

然后依次把两个.a文件拖到终端窗口, 命令行会变成这样:

lipo -create /Users/Travis/Desktop/libIMIUI.d.a /Users/Travis/Desktop/libIMIUI.s.a

然后接着输入 -output 目标文件路径,如:

-output /Users/Travis/Desktop/libIMIUI.a

最后现在这样一条命令:

lipo -create /Users/Travis/Desktop/libIMIUI.d.a /Users/Travis/Desktop/libIMIUI.s.a -output /Users/Travis/Desktop/libIMIUI.a

回车! 好了, 这样就会生成我们需要的通用类库 libIMIUI.a

如果大家嫌麻烦, 请留言回复, 超过10个 我会给大家写一个自动生成的小工具 :)

使Xcode在任何抛出异常时候进入断点

有好多异常,无法正常进入断点,程序会直接退出,比如:
screen 2

这时候我们甚至不知道使在哪出现的这个错误,OK,打开Run>>Debugger 找到程序退出位置:

screen 4

然后添加一个软断点 Run->Manage Breakpoints -> Add symbolic breakpoint, 并输入 objc_exception_throw
screen 12

重新运行调试
screen 11

错在哪儿是不是很容易就找到了 :)

Obj-C不用数组 传不定长度参数 的方法

这是从Cocos2D里看到的, 但也有局限性, 就是参数必须类型相同! 其实像NSString 里的的stringWithFormat也是用这个实现的

+(id) actions: (FiniteTimeAction*) action1, …
{
va_list params;
va_start(params,action1);

FiniteTimeAction *now;
FiniteTimeAction *prev = action1;

while( action1 ) {
now = va_arg(params,FiniteTimeAction*);
if ( now )
prev = [Sequence actionOne: prev two: now];
else
break;
}
va_end(params);
return prev;
}

IMISound (iPhone OpenAL Sound Engine) update

IMISound bug修复:播放多声音时, 声音错误, 强烈建议升级!

同时静态类库升级 下载地址: http://imi.googlecode.com/files/IMIFramework_0.6.zip

我已经不会写AS了

今天想把首页做个全Flash的, 直接读取博客内容显示在首页上.
但是, 但是, 我写不出来了…
太恐怖了, 撒手还不到一年, 全忘了, 干干净净的!!!
亏我还整天自吹多少多少年写AS!

原因主要有两个:
1. Objective-C 和 Action Script是完全不同的语言, 完全不同的编码思想
2. 我不喜欢Flash了! 潜意识里, 已经把它忘了, 这个我当年说要拿它来养家糊口的Flash

Autorelease Pools

1,Autorelease Pools概要
一个”Autorelease Pool”实例中“包含”其它各种调用了”autorelease”方法的对象。当它释放时,其中所有被管理对象都会收到”relrease”的消信。注意,同一个对象可以被多次调用”autorelease”方法,并可以放到同一个”Autorelease Pool”中。引入这个自动释放池机制,对象的”autorelease”方法代替”relrease”方法可以延长它的生命周期,直接到当前”Autorelrease Pool”释放。如果想让此对象的生命周期超过”Autorelease Pool”,还可以再次”retain”,呵呵,有意思吧〜且让我慢慢道来。

Cocoa总是认为当前至少有一个”Autorelease Pool”对象是可用的。若此对象并不存在,你调用的”autorelease”的所有对象都不会被自动释放掉,可想而知,造成内存泄露。Cocoa把这个错误信息写入日志〜〜仅仅是为了以后分析。
你可以用”alloc”与”init”方法创建一个”NSAutoreleasePool”对象,并且可以调用”release”或”drain”(”release”与”drain”的区别是”drain”在有GC的环境中会引起GC回收操作,”release”反之。但在非GC环境中,两者相同。官方的说法是为了程序的兼容性,应该考虑用”drain”代替”release”,)方法来回收它(调用它的”autorelease”或”retain”方法会引起异常)。在一个完整的上下文最后”Autorelease Pool”对象应该被”release”掉(在方法内或一段循环体内创建的”Autorelease Pool”对象)。
“Autorelease Pools”的所有实例在栈中管理(我们暂时叫他“自动释放池栈”),并且它们是可以被嵌套的(父生子,子生孙。。。子子孙孙 ^_^)。例如,当我们创建一个”Autorelease Pool”对象后,它就被自动放到“自动释放池栈”的栈顶。当本池对象回收时,它就随之从这个栈中POP掉。那么也就是说,当任何一个对象调用”autorelease”方法后,它会被放入当前线程中当前栈顶的自动释放池中。
接下来我们聊聊”Autorelease Pools”的嵌套问题。在你的应用中,你可以任意多的创建”Autorelease Pool”对象,而这些对象被当前线程的“自动释放池栈”所管理。那么除了一个接一个的顺序创建并销毁它的情况外,还有一种使用方式,就是嵌套式的创建与使用。例如:在你的主函数创建了一个”autorelease pool”,然后又调用了创建了”autorelease pool”实例的其它方法;或是在外循环中创建了”Autorelease Pool”的实例,而内循环中也做了相同的事情。有意思吧,呵呵,嵌套的机制使父Pool实例释放后,它的所有子Pool也将释放。但这里还存在一些副作用,后续文章会详细讨论。
“Application kit”在一个事件循环里会自动创建一个”autorelease pool”。像鼠标键的按下与释放,所以你编写的代码通常不需要考虑太多这方面的事情。当然,有以下三种情况你会创建与销毁自己的Pool实例:
1,应用不是基于”Application Kit”,像”Command-line tool”,因为它并没有内置的”autorelease pools”的支持。
2,创建线程,你必需在线程开始时创建一个”Autorelease Pool”实例。反之,会造成内存池露(会在以后的文章详细说明线程与池的技巧)。
3,一个循环内创建了太多的临时对象,你应该为他们创建一个”Autorelease Pool”对象,并在下次循还前销毁它们。
2,自动释放池中的”Non-AppKit”应用
在”Non-AppKit”应用中使用自动释放池的机制其实是相当简单的事情。你仅仅需要在main()起始处创建”Autorelease Pool”对象,并在结尾处释放掉它。就像在Xcode的Foundation Tool的创建模版里写的一样。这个确保你在应用生命周期内至少有一个”Autorelease Pool”是可用的。但是,这也使所有在此期间的所有”autorelease”的对象都必需在应用结束后才被释放。这也许会引起在应用的使用中不断的增长,所以,你仍然考虑在不同的作用域创建新的”Autorelease Pool”。
大多应用中都存在各种级别的循环机制。在这些应用中,你可以在每个循环内的开头创建一个”Autorelease Pool”对象,并在结尾处释放掉它。
例如:
void main()
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSArray *args = [[NSProcessInfo processInfo] arguments];
unsigned count, limit = [args count];
for (count = 0; count < limit; count++)
{
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
NSString *fileContents;
NSString *fileName;
fileName = [args objectAtIndex:count];
fileContents = [[[NSString alloc] initWithContentsOfFile:fileName] autorelease];
// this is equivalent to using stringWithContentsOfFile:
/* Process the file, creating and autoreleasing more objects. */
[loopPool release];
}
/* Do whatever cleanup is needed. */
[pool drain];
exit (EXIT_SUCCESS);
}
在命令行中处理所有以参数传来的文件。一次循环处理一个文件。在循环的开头创建一个”NSAutoreleasePool”对象,并在循环结束时释放掉。因此,任何在其中创建并调用“autorelease”的对象都将添加到这个Pool实例中,当本池被释放后,这些对象也将被回收。注意,任何在作用域内创建的”autoreleased”对象(像”fileName”),虽然并没有显示的调用”autorelease”方法,但都将被当前池所管理并释放。

iPhoneSide

feed://www.iphoneside.com/feed/

回到顶部

关于我:

  • iPhone 开发者. 自由职业者.
  • 苹果忠实用户. 完美主义者.
  • Email/iChat/MSN/GTalk: i@imi.im
  • Twitter/Sina: @TraWor
  •  

    Switch to our mobile site