目前我正在为我的第一个Objective-c API做出一些决定。没什么大不了的,只是帮助我自己将来更快地完成任务。
在阅读了几个小时关于不同模式,比如制作类别,单身等等之后,我遇到了一些我喜欢的东西,因为它对我来说似乎很容易维护。我正在制作一套有用的功能,这些功能在任何地方都很有用。
所以我做的是:
1)我创建了两个新文件(.h,.m),并为“class”命名:SLUtilsMath,SLUtilsGraphics,SLUtilsSound等。我认为这是一种“命名空间”,所以所有这些东西总是被称为SLUtils ******。我将它们全部添加到Group SL中,其中包含一个子组SLUtils。
2)然后我只将函数签名放在.h文件中,并将函数的实现放在.m文件中。猜猜看:它有效!!我很高兴它,它很容易使用。关于它的唯一令人讨厌的事情是,我每次需要时都必须包含适当的标题。但那没关系,因为那是正常的。不过,我可以将它包含在头文件前缀pch文件中。
然后,我去了厕所,一个幽灵出现在那里,说:“嘿!制作真正的方法而不是功能是不是更好?你不应该制作课程方法,所以你必须打电话一种方法而不是一种功能?是不是更酷,而且它没有更好的性能?“好吧,为了便于阅读,我更喜欢这些功能。另一方面,他们没有像方法那样的“命名参数”,a.f.a.i.k ..
那么在那种情况下你更喜欢什么?
当然我不想在使用有用的方法或函数之前分配对象。那将是痛苦的。
也许厕所幽灵是对的。有一个更酷的方式。嗯,对我个人而言,这很棒:
MYNAMESPACECoolMath.h
#import <Foundation/Foundation.h>
@interface MYNAMESPACECoolMath : NSObject {
}
+ (float)randomizeValue:(float)value byPercent:(float)percent;
+ (float)calculateHorizontalGravity:(CGPoint)p1 andPoint:(CGPoint)p2;
// and some more
@end
然后在代码中,我只需导入MYNAMESPACECoolMath.h并调用:
CGFloat myValue = [MYNAMESPACECoolMath randomizeValue:10.0f byPercent:5.0f];
没有讨厌的实例化,初始化,分配,什么都有。对我来说,这个模式在java中看起来像一个静态方法,非常好用且易于使用。
据我所知,功能的优势在于代码的可读性更高。在查看CGRectMake(10.0f,42.5f,44.2f,99.11f)时,您可能需要查看这些参数的含义,如果您对它不熟悉的话。但是,当您使用“命名”参数进行方法调用时,您会立即看到参数是什么。
我认为,当谈到可以在任何地方使用的简单有用的方法/功能时,我错过了对单例类产生重大影响的观点。制作特殊类型的随机值不属于任何东西,它是全局的。像草一样。像树一样。像空气一样。每个人都需要它。
答案 0 :(得分:6)
在性能方面, static 类中的静态方法编译成与函数几乎相同的东西。
你所引发的任何真正的性能命中都会出现在对象实例化中,你说你想要避免它,所以这应该不是问题。
就偏好或可读性而言,有一种趋势是使用静态方法超过必要,因为人们正在查看Obj-C是一种“仅OO”语言,如Java或C#。在那个范例中,(几乎)一切都必须属于一个类,所以类方法是常态。事实上,他们甚至可能称他们为功能。这两个术语在那里是可以互换的。但是,这纯粹是惯例。公约甚至可能过于强硬。在其位置使用函数绝对没有错,如果没有需要帮助处理这些方法/函数的类成员(甚至是静态成员),这可能更合适。
答案 1 :(得分:5)
你的方法的问题是它的“util”性质。几乎任何带有“util”字样的东西都表明你已经为你不知道在哪里放入对象模型的东西创建了一个倾倒场。这可能意味着您的对象模型与您的问题空间不一致。
您应该考虑这些函数应该对哪些模型对象进行操作,然后将它们放在这些类上(如果需要,创建类),而不是研究如何打包实用程序函数。
对于Josh而言,虽然ObjC中的函数没有任何问题,但它是一种非常强烈面向对象的语言,直接基于面向对象语言的老爸Smalltalk。你不应该轻易放弃OOP模式;他们是可可的核心。
我一直在创建私有帮助函数,我为某些对象创建公共便利函数(NSLocalizedString()就是一个很好的例子)。但是如果你创建的公共实用函数不是方法的前端,那么你应该重新思考你的模式。第一个警告标志是希望将“util”放在文件名中。
修改强>
根据您添加到问题中的特定方法,您应该关注的是类别。例如,+randomizeValue:byPercent:
是一个非常好的NSNumber类别:
// NSNumber+SLExtensions.h
- (double)randomizeByPercent:(CGFloat)percent;
+ (double)randomDoubleNear:(CGFloat)percent byPercent:(double)number;
+ (NSNumber *)randomNumberNear:(CGFloat)percent byPercent:(double)number;
// Some other file that wants to use this
#import "NSNumber+SLExtensions.h"
randomDouble = [aNumber randomizeByPercent:5.0];
randomDouble = [NSNumber randomDoubleNear:5.0 byPercent:7.0];
如果您获得了很多这些,那么您可能希望将它们分成NSNumber + Random等类别。使用Categories进行操作使其透明地成为现有对象模型的一部分,而不是创建仅用于处理其他对象的类。
答案 2 :(得分:1)
如果您想避免实例化一堆实用程序对象,可以使用singleton instance。
但是使用普通C函数没有任何问题。只知道你无法使用@selector传递它们,例如performSelectorOnMainThread。
答案 3 :(得分:1)
当谈到方法与功能的表现时,Mike Ash在他的帖子"Performance Comparisons of Common Operations"中有一些很好的数字。 Objective-C消息发送操作非常快,所以你必须有一个非常紧凑的计算循环才能看到差异。我认为在您的方法中使用函数与方法将归结为其他人描述的风格设计问题。
答案 4 :(得分:0)
优化系统,而不是函数调用。
实施最容易理解的内容,然后在整个系统运行时,对其进行分析并加快速度。我非常怀疑静态类的objective-c运行时开销会对整个应用程序产生影响。