用ffmpeg与标准的g726解出来,声音一点也分不出来。
如何解决啊?
1楼:顶一下
2楼:听说可以用海思提供的解码库解,但尚未有android版的例子
3楼:打酱油的
4楼:...
Object C 内存管理
一. 基本概念:
1. iPhone系统中的Objective-C的内存管理机制是比较灵活的,即可以拿来像C/C++一样用,也可以加个AutoreleasePool让它升级为半自动化的内存管理语言;2. 引用计数是实例对象的内存回收唯一参考
引用计数(retainCount)是Objective-C管理对象引用的唯一依据。调用实例的release方法后,此属性减一,减到为零时对象的dealloc方法被自动调用,进行内存回收操作,也就是说我们永不该手动调用对象的dealloc方法.
3. “拥有的概念”
1) 拥有一个对象的使用权,我们称为拥有这个对象;对象的拥有者个数至少为1,对象才得以存在,否则它应该立即销毁;
2) 获得一个对象所有权的方法:当对对象做alloc,copy,和retain操作之后;
4. “引用”d的概念
面向对象领域里有个引用的概念,区别于继承,引用常被用来当做偶合性更小的设计。一个实例拥有另一个实例的时候,我们称它为引用了另一个实例。
比如ClassA类的一个属性对象的Setter方法:
- ( void )setMyArray:(NSMutableArray *)newArray {
if (myArray != newArray) {
[ myArray setMyArray:nil ];// 这里不用release思考为什么,(在实例的dealloc方法中会调用myArray的realse方法)
myArray = [newArray retain];
}
}
5. 引用记数:
每个对象都有一个引用记数(retainCount),对象被创建的时候引用记数为1;
6. 2
二. 内存管理API及使用准则:
1. alloc:为一个新对象分配内存,并且它的引用记数为1;调用alloc方法,你便拥有新对象的所有权;
2. copy:制造一个对象的副本,改副本的retainCount为1,调用者拥有对副本的所有权;
3. retain: 使retainCount+1;并且拥有对象所有权;
4. release:使retainCount-1;
5. autorealse: 未来的某个时刻使retainCount-1;
6. dealloc:不要手动调用,而是在系统retainCount为0时自动调用;
- (void)dealloc{
[name release];
[super dealloc];
}变量的release顺序与初始顺序相反;
三. 内存管理的原则:
以 1 2 3为A类,(retainCount+1);
以 4,5为B类:retainCount-1
1 .对于同一个对象所做的,A与B的调用次数保持一致;2. 凡是通过alloc,retain,copy等手段获得对象的所有权;必须在不适用的 使用自己调用release或autoRelease释放;
3. 不要释放不属于自己的对象;
4. autorelease只是意味着延迟发送一个release消息;
5. 对于便利构造器和访问器来说,不用进行释放,因为没有获得对象的使用权;
四. 使用小例子:
1. Person *person1 = [[Person alloc] initWithName:@”张三”]; NSLog(@”name is %@”,person1.name); //假设从这往后,我们一直都不使用person1 了,应该把对象给释放了。 [person1 release];2.
erson *person2 = [Person alloc]initWithName:@”李四”];
NSString *name = person2.name;NSLog(@”%@”,name); //假设从这以后,我们也不使用person2了。
[person2 release];
//不应该释放name,因为name是我们间接获得的,所以没有它的所有权
3. 由便利构造器产生的对象不应当使用者销毁,而是由便利构造器本身完成。
+(id) personWithName:(NSString *)aName
{
Person *person = [[Person alloc]
initWithName:aName];
return person; }
①错误,因为返回person对象后,类失去了释放这个对象的机会;
②如果在return语句前加上:[person release];也错误,因为对象已经销毁,不能使用;
③:正确做法:return语句前加上:[person autorelease];
(二)使用便利构造器创建的对象,不需要进行释放;
如:
-(void) printHello
{
NSString *str = [NSString
stringWithFormat:@”Hello”];
NSLog(@”%@”,str); }
4. 访问器和设置器:
1)在设置器中,保持对新传入对象的所有权,同时放弃旧对象的所有权。
-(void) setName:(NSString *) aName{ if(name!= aName){
[name release];//有疑问,会不会造成多次释放;
name = [aName retain];//or copy }
}
2) 在访问器中,不需要retain或release.
-(NSString *)name{
return name; }
3) 用访问器获得的对象,使用完毕后不需要释放。
-(void) printName{
NSString *name = person.name;
NSLog(@”%@”,name); }
5. 常见错误:
1) 未使用设置器
-(void) reset{
NSString *newName = [[NSString alloc]
initWithFormat:@”theNew”]; name = newName;
[newName release]; }
2)内存泄露
-(void) reset{
NSString *newName = [[NSString alloc]
initWithFormat:@”theNew”];
[self setName:newName];
}
3) 释放没有所有权的对象
-(void) reset{
NSString *newName = [NSString
stringWithFormat:@”theNew”];
[self setName:newName];
[newName release];
}
[深入浅出Cocoa]之消息(二)-详解动态方法决议(Dynamic Method Resolution)
罗朝辉 (http://blog.csdn.net/kesalin/)
如果我们在 Objective C 中向一个对象发送它无法处理的消息,会出现什么情况呢?根据前文《深入浅出Cocoa之消息》的介绍,我们知道发送消息是通过 objc_send(id, SEL, ...) 来实现的,它会首先在对象的类对象的 cache,method list 以及父类对象的 cache, method list 中依次查找 SEL 对应的 IMP;如果没有找到且实现了动态方法决议机制就会进行决议,如果没有实现动态方法决议机制或决议失败且实现了消息转发机制就会进入消息转发流程,否则程序 crash。也就是说如果同时提供了动态方法决议和消息转发,那么动态方法决议先于消息转发,只有当动态方法决议依然无法正确决议 selector 的实现,才会尝试进行消息转发。在前文中,我并没有详细讲解动态方法决议,因此本文将详细介绍之。
本文代码下载:点此下载
一,向一个对象发送该对象无法处理的消息如下代码:
@interface Foo : NSObject -(void)Bar; @end @implementation Foo -(void)Bar { NSLog(@" >> Bar() in Foo"); } @end ///////////////////////////////////////////////// #import "Foo.h" int main (int argc, const char * argv[]) { @autoreleasepool { Foo * foo = [[Foo alloc] init]; [foo Bar]; [foo MissMethod]; [foo release]; } return 0; }
在编译时,XCode 会提示警告:
Instance method '-MissMethod' not found (return type defaults to 'id')
如果,我们忽视该警告运行之,一定会 crash:
>> Bar() in Foo -[Foo MissMethod]: unrecognized selector sent to instance 0x10010c840 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Foo MissMethod]: unrecognized selector sent to instance 0x10010c840' *** Call stack at first throw: ...... terminate called after throwing an instance of 'NSException'
下划线部分就是造成 crash 的原因:对象无法处理 MissMethod 对应的 selector,也就是没有相应的实现。
二,动态方法决议
Objective C 提供了一种名为动态方法决议的手段,使得我们可以在运行时动态地为一个 selector 提供实现。我们只要实现 +resolveInstanceMethod: 和/或 +resolveClassMethod: 方法,并在其中为指定的 selector 提供实现即可(通过调用运行时函数 class_addMethod 来添加)。这两个方法都是 NSObject 中的类方法,其原型为:
+ (BOOL)resolveClassMethod:(SEL)name; + (BOOL)resolveInstanceMethod:(SEL)name;
参数 name 是需要被动态决议的 selector;返回值文档中说是表示动态决议成功与否。但在上面的例子中(不涉及消息转发的情况下),如果在该函数内为指定的 selector 提供实现,无论返回 YES 还是 NO,编译运行都是正确的;但如果在该函数内并不真正为 selector 提供实现,无论返回 YES 还是 NO,运行都会 crash,道理很简单,selector 并没有对应的实现,而又没有实现消息转发。resolveInstanceMethod 是为对象方法进行决议,而 resolveClassMethod 是为类方法进行决议。
下面我们用动态方法决议手段来修改上面的代码:
// // Foo.m // DeepIntoMethod // // Created by 飘飘白云 on 12-11-13. // Copyright (c) 2012年 kesalin@gmail.com All rights reserved. // #import "Foo.h" #include <objc/runtime.h> void dynamicMethodIMP(id self, SEL _cmd) { NSLog(@" >> dynamicMethodIMP"); } @implementation Foo -(void)Bar { NSLog(@" >> Bar() in Foo"); } + (BOOL)resolveInstanceMethod:(SEL)name { NSLog(@" >> Instance resolving %@", NSStringFromSelector(name)); if (name == @selector(MissMethod)) { class_addMethod([self class], name, (IMP)dynamicMethodIMP, "v@:"); return YES; } return [super resolveInstanceMethod:name]; } + (BOOL)resolveClassMethod:(SEL)name { NSLog(@" >> Class resolving %@", NSStringFromSelector(name)); return [super resolveClassMethod:name]; } @end
在前文《深入浅出Cocoa之消息》中已经介绍过 Objective C 中的方法其实就是至少带有两个参数(self 和 _cmd)的普通 C 函数,因此在上面的代码中提供这样一个 C 函数 dynamicMethodIMP,让它来充当对象方法 MissMethod 这个 selector 的动态实现。因为 MissMethod 是被对象所调用,所以它被认为是一个对象方法,因而应该在 resolveInstanceMethod 方法中为其提供实现。通过调用
class_addMethod([self class], name, (IMP)dynamicMethodIMP, "v@:");
就能在运行期动态地为 name 这个 selector 添加实现:dynamicMethodIMP。class_addMethod 是运行时函数,所以需要导入头文件:objc/runtime.h。
再次编译运行前面的测试代码,输出如下:
>> Bar() in Foo. >> Instance resolving MissMethod >> dynamicMethodIMP called. >> Instance resolving _doZombieMe
dynamicMethodIMP 被调用了,crash 没有了!万事大吉!
注意:这里两次调用了 resolveInstanceMethod,而且两次决议的 selector 在不同的系统下是不同的,上面演示的是 10.7 系统下第一个决议 MissMethod,第二个决议 _doZombieMe;在 10.6 系统下两次都是决议 MissMethod。
下面我把 resolveInstanceMethod 方法中为 selector 添加实现的那一行屏蔽了,消息转发就应该会进行:
//class_addMethod([self class], name, (IMP)dynamicMethodIMP, "v@:");
再次编译运行,此时输出:
>> Bar() in Foo. >> Instance resolving MissMethod +[Foo resolveInstanceMethod:MissMethod] returned YES, but no new implementation of -[Foo MissMethod] was found >> Instance resolving _doZombieMe objc[1223]: +[Foo resolveInstanceMethod:MissMethod] returned YES, but no new implementation of -[Foo MissMethod] was found -[Foo MissMethod]: unrecognized selector sent to instance 0x10010c880 *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Foo MissMethod]: unrecognized selector sent to instance 0x10010c880' *** Call stack at first throw: ......
在这里,resolveInstanceMethod 使诈了,它声称成功(返回 YES )决议了 selector,但是并没有真正提供实现,被编译器发觉而提示相应的错误信息。那它的返回值到底有什么作用呢,在它没有提供真正的实现,并且提供了消息转发机制的情况下,YES 表示不进行后续的消息转发,返回 NO 则表示要进行后续的消息转发。
三,源码剖析
让我们来看看运行时系统是如何进行动态方法决议的,下面的代码来自苹果官方公开的源码 objc-class.mm,我在其中添加了中文注释:
1,首先是判断是不是要进行类方法决议,如果不是或决议失败,则进行实例方法决议(请参考:《深入浅出Cocoa之类与对象》):
/*********************************************************************** * _class_resolveMethod * Call +resolveClassMethod or +resolveInstanceMethod and return * the method added or NULL. * Assumes the method doesn't exist already. **********************************************************************/ __private_extern__ Method _class_resolveMethod(Class cls, SEL sel) { Method meth = NULL; if (_class_isMetaClass(cls)) { meth = _class_resolveClassMethod(cls, sel); } if (!meth) { meth = _class_resolveInstanceMethod(cls, sel); } if (PrintResolving && meth) { _objc_inform("RESOLVE: method %c[%s %s] dynamically resolved to %p", class_isMetaClass(cls) ? '+' : '-', class_getName(cls), sel_getName(sel), method_getImplementation(meth)); } return meth; }
2,类方法决议与实例方法决议大体相似,在这里就只看实例方法决议部分了:
/*********************************************************************** * _class_resolveInstanceMethod * Call +resolveInstanceMethod and return the method added or NULL. * cls should be a non-meta class. * Assumes the method doesn't exist already. **********************************************************************/ static Method _class_resolveInstanceMethod(Class cls, SEL sel) { BOOL resolved; Method meth = NULL; // 是否实现了 resolveInstanceMethod,如果没有返回 NULL if (!look_up_method(((id)cls)->isa, SEL_resolveInstanceMethod, YES /*cache*/, NO /*resolver*/)) { return NULL; } // 调用 resolveInstanceMethod,并获取返回值 resolved = ((BOOL(*)(id, SEL, SEL))objc_msgSend)((id)cls, SEL_resolveInstanceMethod, sel); if (resolved) { // 返回值为 YES,表示 resolveInstanceMethod 声称它已经成功添加实现,则再次查找 method list // +resolveClassMethod adds to self meth = look_up_method(cls, sel, YES/*cache*/, NO/*resolver*/); if (!meth) { // resolveInstanceMethod 使诈了,它声称成功添加实现了,但实际没有,给出警告信息,并返回 NULL // Method resolver didn't add anything? _objc_inform("+[%s resolveInstanceMethod:%s] returned YES, but " "no new implementation of %c[%s %s] was found", class_getName(cls), sel_getName(sel), class_isMetaClass(cls) ? '+' : '-', class_getName(cls), sel_getName(sel)); return NULL; } } // 其他情况下返回 NULL return meth; }
这段代码很容易理解:
1,首先判断是否实现了 resolveInstanceMethod,如果没有实现,返回 NULL,进入下一步处理;
2,如果实现了,调用 resolveInstanceMethod,获取返回值;
3,如果返回值为 YES,表示 resolveInstanceMethod 声称它已经提供了 selector 的实现,因此再次查找 method list,如果依然找到对应的 IMP,则返回该实现,否则提示警告信息,返回 NULL,进入下一步处理;
4,如果返回值为 NO,返回 NULL,进入下一步处理;
四,加入消息转发
在前文《深入浅出Cocoa之消息》一文中,我演示了一个消息转发的示例,下面我把动态方法决议部分去除,把消息转发部分添加进来:
// Proxy @interface Proxy : NSObject -(void)MissMethod; @end @implementation Proxy -(void)MissMethod { NSLog(@" >> MissMethod() called in Proxy."); } @end // Foo @interface Foo : NSObject -(void)Bar; @end @implementation Foo - (void)forwardInvocation:(NSInvocation *)anInvocation { SEL name = [anInvocation selector]; NSLog(@" >> forwardInvocation for selector %@", NSStringFromSelector(name)); Proxy * proxy = [[[Proxy alloc] init] autorelease]; if ([proxy respondsToSelector:name]) { [anInvocation invokeWithTarget:proxy]; } else { [super forwardInvocation:anInvocation]; } } - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { return [Proxy instanceMethodSignatureForSelector:aSelector]; } -(void)Bar { NSLog(@" >> Bar() in Foo."); } @end
运行测试代码,输出如下:
>> Bar() in Foo. >> forwardInvocation for selector MissMethod >> MissMethod() called in Proxy.
如果我把动态方法决议部分代码也加入进来输出又是怎样呢?下面只列出了 Foo 的实现代码,其他代码不变动。
@implementation Foo +(BOOL)resolveInstanceMethod:(SEL)name { NSLog(@" >> Instance resolving %@", NSStringFromSelector(name)); if (name == @selector(MissMethod)) { class_addMethod([self class], name, (IMP)dynamicMethodIMP, "v@:"); return YES; } return [super resolveInstanceMethod:name]; } +(BOOL)resolveClassMethod:(SEL)name { NSLog(@" >> Class resolving %@", NSStringFromSelector(name)); return [super resolveClassMethod:name]; } - (void)forwardInvocation:(NSInvocation *)anInvocation { SEL name = [anInvocation selector]; NSLog(@" >> forwardInvocation for selector %@", NSStringFromSelector(name)); Proxy * proxy = [[[Proxy alloc] init] autorelease]; if ([proxy respondsToSelector:name]) { [anInvocation invokeWithTarget:proxy]; } else { [super forwardInvocation:anInvocation]; } } - (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector { return [Proxy instanceMethodSignatureForSelector:aSelector]; } -(void)Bar { NSLog(@" >> Bar() in Foo."); } @end
此时,输出为:
>> Bar() in Foo. >> Instance resolving MissMethod >> dynamicMethodIMP called. >> Instance resolving _doZombieMe
注意到了没,消息转发没有进行!在前文中说过,消息转发只有在对象无法正常处理消息时才会调用,而在这里我在动态方法决议中为 selector 提供了实现,使得对象可以处理该消息,所以消息转发不会继续了。官方文档中说:
If you implement resolveInstanceMethod: but want particular selectors to actually be forwarded via the forwarding mechanism, you return NO for those selectors.
文档里的说法其实并不准确,只有在 resolveInstanceMethod 的实现中没有真正为 selector 提供实现,并返回 NO 的情况下才会进入消息转发流程;否则绝不会进入消息转发流程,程序要么调用正确的动态方法,要么 crash。这也与前面的源码不太一致,我猜测在比上面源码的更高层次的地方,再次查找了 method list,如果提供了实现就能够找到该实现。
下面我把 resolveInstanceMethod 方法中为 selector 添加实现的那一行屏蔽了,消息转发就应该会进行:
//class_addMethod([self class], name, (IMP)dynamicMethodIMP, "v@:");
再次编译运行,此时输出正如前面所推断的那样:
>> Bar() in Foo. >> Instance resolving MissMethod objc[1618]: +[Foo resolveInstanceMethod:MissMethod] returned YES, but no new implementation of -[Foo MissMethod] was found >> forwardInvocation for selector MissMethod >> MissMethod() called in Proxy. >> Instance resolving _doZombieMe
进行了消息转发!而且编译器很善意地提示(见前面源码剖析):哎呀,你不能欺骗我嘛,你说添加了实现(返回YES),其实还是没有呀!然后编译器就无奈地去看能不能消息转发了。当然如果把返回值修改为 NO 就不会有该警告出现,其他的输出不变。
五,总结
从上面的示例演示可以看出,动态方法决议是先于消息转发的。
如果向一个 Objective C 对象对象发送它无法处理的消息(selector),那么编译器会按照如下次序进行处理:
1,首先看是否为该 selector 提供了动态方法决议机制,如果提供了则转到 2;如果没有提供则转到 3;
2,如果动态方法决议真正为该 selector 提供了实现,那么就调用该实现,完成消息发送流程,消息转发就不会进行了;如果没有提供,则转到 3;
3,其次看是否为该 selector 提供了消息转发机制,如果提供了消息了则进行消息转发,此时,无论消息转发是怎样实现的,程序均不会 crash。(因为消息调用的控制权完全交给消息转发机制处理,即使消息转发并没有做任何事情,运行也不会有错误,编译器更不会有错误提示。);如果没提供消息转发机制,则转到 4;
4,运行报错:无法识别的 selector,程序 crash;
六,引用
官方运行时源代码:http://www.opensource.apple.com/source/objc4/objc4-532/runtime/
Objective-C Runtime Programming Guide
深入浅出Cocoa之消息
深入浅出Cocoa之类与对象