Dav*_*.ca 9 iphone cocoa objective-c
我是Objective-c的新手,我想在我的OC类中实现流畅的界面模式.这是我项目中更新和简化的案例:
// .h file
@interface MyLogger : NSObject {
...
}
- (MyLogger*) indent:(BOOL)indent;
- (MyLogger*) debug:(NSString*)message, ...;
- (id) warning:(NSString*)message, ...;
....
@end
// .m file
@implement MyLogger {
- (MyLogger*) indent:(BOOL)indent {
// some codes to set indent or unindent
return self; // I think it should return [self autorelease];
}
- (MyLogger*) debug:(NSString*)message, ... {
// build message and log the message
return [self autorelease];
}
- (id) warning:(NSString*)message, ... {
// similar as above, but log a warning message
return self;
}
//. usage in another .m
-(id) initAnotherClass {
if (self = [supper init]) {
// ...
// instance was defined as MyLogger in .h as class var
instance = [[[MyLogger alloc] initWithContext:@"AnotherClassName"] retain];
//...
}
return self;
}
-(void)method1 {
[[instance debug:@"method1"] indent:YES];
...
[instance warning:@"some debug message with obj: %@", var];
...
[[instance indent:NO] debug:@"method1 DONE"];
}
// in my Xcode output I'll see debug output like
[date time] [app id] [DEBUG] AnotherClassName - method1
[date time] [app id] [WARNING] AnotherClassName - some debug message with obj: ...
[date time] [app id] [DEBUG] AnotherClassName - method1 DONE
Run Code Online (Sandbox Code Playgroud)
在这里indent,我回归自我,而在debug:我回来了[self autorelease].如果我只是self像以前一样回来,它的工作正常debug.但是,我认为我应该总是以与以下相同的方式返回debug:在OC内存管理方面.有什么建议?
更新:我添加了另一个warning返回类型为id的方法.我应该在OC中将自己作为id类型还是我的类类型返回?它似乎都工作正常,没有编译错误或警告.我似乎Cocoa框架类返回id.例如,以下是NSString.h中的一些方法
+ (id)string;
+ (id)stringWithString:(NSString *)string;
Run Code Online (Sandbox Code Playgroud)
似乎Cocoa有一些FI模式就像方法一样.应该是id类型比类本身更好吗?
更新:正如Pat Wallace的建议,我实际上是在iPhone项目中使用这种模式.
bbu*_*bum 36
哦,回忆....
Wayyy回到NS*前缀之前到处使用,它是所有方法的标准return self;,现在有(void)返回类型.
目标是实现任意深度方法链接.我想这就是你们这些天幼儿们所说的FLUENT.
在实践中,它很糟糕.而在"实践中",我的意思是"在保持数十万行严密链接方法调用Objective-C代码后,我得出的结论是,方法链接是一个巨大的痛苦,最终,要避免".
具体来说,我在谈论:
[[[[[[self foo] bar] baz] bob] fred] eatMe];
Run Code Online (Sandbox Code Playgroud)
并不是:
x = [self foo];
x = [x bar];
x = [x baz];
x = [x bob];
x = [x fred];
x = [x eatMe];
Run Code Online (Sandbox Code Playgroud)
(添加了x =原来缺少的那个表达式不同.)
前者是完全链式的形式,后者是你今天看到的代码模式,两者都出现在FLUENT的各种描述中.
当设计OpenStep API时 - 您的孩子现在称之为Cocoa - 设计者得出了相同的结论,因此,在(void)整个框架中采用了默认为返回类型的约定.
模式存在许多问题(其中一些是Objective-C的直接后果,其中一些是由于底层工具).其中一些当然是意见.带上一粒盐:
调试是彻头彻尾的痛苦; 您不能在单行fluent-y表单中的任意子链方法调用上设置断点.通过流畅的链式方法表达"向上"或"向下"可能会令人困惑; 又是哪个子表达?
意想不到nil的更糟糕.在上面,说-baz意外返回nil.要弄清楚这一点,你必须在所有后续方法上设置一个断点(至少),或者你必须将它分开,然后测试子表达式的结果,或跳过其他方法来计算它出.
它使重构代码更加繁琐.如果您发现需要插入一个新的子表达式,检查中间的值,或者使用表达式进行捣乱,则必须先将其分解.第二种形式更容易处理.
我个人认为链式方法更难以阅读.它不再像一系列步骤(它确实是这样)而读取,而是更像是一个句子.这听起来很整洁,但是 - 在实践中 - 它实际上是一系列表达 - 一系列步骤 - 并且这样处理它通常更直观.
它从您的API中删除了一个非常有价值的指标.一个(void)非常明确地返回的方法说"我用参数做事,然后我就完成了".一个返回值 - 请记住,(id)如果涉及子类化,你通常必须声明返回类型(ObjC根本不做共同变化) - 说"嘿,伙计,我做了一些东西,这是你的结果,处理它."
具有非void返回类型使得分布式对象的效率显着降低.非空返回类型必须通过线路回传.一个(void)回报要求没有这样的代理,并(oneway void)可以通过线路发送,并从本地端异步执行,还要更快.
在任何情况下,回答你原来的问题:不,你几乎不会return [[self retain] autorelease];从这样的FLUENT-y方法上下文.正如其他人所说的那样,self有点特殊,而且你甚至执行方法的事实意味着self至少与方法执行一样长(线程被诅咒).
Ben*_*tto 10
这里有几点说明:
当您从方法返回现有对象时,如果您仍然"关心"该对象,则不会自动释放它,只需将其返回即可.在这种情况下,由于即使在调用者获得对它的引用之后你仍然"保留"自己的对象,也不要向它发送autorelease消息.不要认为这种模式是"返回一个自动释放的对象"; 只有在方法内部创建对象时,才能执行此操作,并希望在不自行保留引用的情况下返回该对象.如果调用者想要保留引用它返回,则可以自由地保留它.
self无论如何,它是一种特殊的引用,并且发送self任何内存管理消息是非常罕见的,可能除了init方法内部.
虽然您可以创建一个Fluent模式的消息链接,就像您正在尝试做的那样,只需注意这不是常见的/惯用的Objective-C,并且您的代码可能与其他代码不能很好地混合,并且可能会使其他人感到困惑它.仅供参考.