好的,所以我的项目中有一堆辅助函数,我最初在一个名为Animate的类中。我很想知道声明func vc class func有什么好处。
让我们将其用作示例类:
class Animate{
func moveView(...){
...
}
}
所以我相信如果我有一个类func,我就不必实例化这个类。
Animate.moveView(...)
如果我只用func声明函数,那就是:
Animate().moveView(...)
但是,如果我根本不将该文件声明为类:
func moveView(...){
...
}
当我调用该函数时,它只是:
moveView(...)
没有任何指示代码来自哪里,它可以在项目的任何地方使用。
这三种方式的优点和缺点是什么?是不是宣布一个不好的做法?或者,是否有一些边缘情况,这是非常有用的?例如,在我的情况下,我不需要一个类,因为我只是创建辅助函数而不是对象。
提前感谢您对此有任何见解!
答案 0 :(得分:14)
确定。实例方法与类方法和全局方法。
(术语方法和函数是可互换的。方法意味着由对象实现的函数,所以我更倾向于使用术语方法到术语函数。)
实例方法是由类的实例执行的方法。您必须要与该类进行对话才能调用实例方法。
实例方法可以访问它们所属对象的实例变量,因此该对象可以在调用之间保存状态信息。 (在网络类中,您可以创建多个下载对象,每个下载对象管理来自不同URL的不同文件的单个文件下载,并且每个下载对象可能具有在下载完成时通知的不同委托)
类方法由类本身调用,而不是由实例调用。这可以使调用辅助函数变得简单,而无需管理对象来为您完成这项工作。由于类方法不与类的实例通信,因此它们不能为每个对象保留不同的状态信息。例如,您可能有一个在字符串上执行本地化函数的实用程序类。本地化过程是独立的。你调用一个类函数并传入一个字符串和你希望它本地化的语言,它会把你的结果交给你。无需在呼叫之间保持状态。这样的电话可能看起来像
let frenchString =
LocalizationUtils.localizeString("English String",
toLanguage: "French")
全局函数不属于任何特定类。它们是定义它们的整个模块的全局模块。它们与类函数类似,只是它们不是特定于特定类的。
答案 1 :(得分:3)
我同意(并且赞成)@Duncan C的回答,但只是想我会投入其他一些优点/缺点。
我倾向于喜欢类方法的全局函数,因为全局函数不会使我的类混乱。我喜欢让我的课程变得瘦弱。全局函数可以保存在一个单独的文件中,我可以根据需要将其复制并粘贴或导入到给定项目中。所以我的项目中可能有一个名为AnimateHelperFunctions
的文件,它只是与该类相关的全局函数。一个给定的项目可能只需要它们中的一些,或者大多数,或者那些我发现需要的更多。我可以从文件中删除我不在给定项目中使用的那些,以便保持该文件整洁和修剪。
我只是认为全局函数更加模块化,并且鼓励我将单个任务分解为单个函数 - 一个完美的全局帮助函数完成一件事并完美地完成它有时也可以被抽象化或通用并用于其他情况也是如此。你可能有一个项目,你知道你不需要这个类 - 你只需要它的辅助函数,就在那里。
我更喜欢一百个简单的全局函数,我可以通过一个巨大的膨胀类来挑选。
当然,你可以用扩展来完成同样的事情,并且在某种程度上它是一个品味问题,因为除了使用类方法之外,类方法和全局函数之间几乎没有差别(任何?)你必须拖着整个班级。
与全球国家不同,全球职能没有任何危险。当然,任何人都可以调用它,但类方法也是如此,全局函数只能对传递给它的参数进行操作。
答案 2 :(得分:1)
对我来说,我使用static
或class
方法来控制类级别属性,或者我是否必须返回该特定class
或struct
的自定义实例。例如,考虑我在struct
以下。
struct Person {
let firstName: String
let lastName: String
}
现在,如果我正在编写一些测试用例,我需要在我的许多测试类中使用特定名称Person
初始化John
的实例,我可以创建一个帮助器static
方法
extension Person {
static func john() -> Person {
return Person(firstName: "John", lastName: "Appleseed")
}
}
let john = Person.john() // I could also create a static property instead, but it's a matter of personal choice and situation.
在上面的例子中,我本可以将john
作为全局函数,但对我来说,它会非常模糊且不可读。
我能想到的另一个地方我更喜欢静态方法,它返回enum
的案例数。
enum Mood {
case happy
case angry
case lazy
case high
static func count() -> Int {
return 4
}
}
有些地方,我使用全局功能。我使用全局函数进行日志记录。
func log(screenEvent name: String) {
let tracker = GAI.sharedInstance().defaultTracker
tracker.set(kGAIScreenName, value: screenName)
let builder = GAIDictionaryBuilder.createScreenView()
tracker.send(builder.build() as [NSObject : AnyObject])
}
在内部,该方法使用sharedInstance
,创建一个全局方法使其可以在项目的各个位置轻松访问,就像在控制台中记录输出的print
函数一样,但这是在登录一些自定义服务。
我通常在项目中包含的其他全局函数是GCD助手。
func delay(delay:Double, closure: dispatch_block_t) {
dispatch_after(
dispatch_time(
DISPATCH_TIME_NOW,
Int64(delay * Double(NSEC_PER_SEC))
),
dispatch_get_main_queue(), closure)
}
func backgroundTask(closure: dispatch_block_t) {
dispatch_async(dispatch_get_global_queue(QOS_CLASS_DEFAULT, 0), closure)
}
func mainThreadTask(closure: dispatch_block_t) {
dispatch_async(dispatch_get_main_queue(), closure)
}
这些函数不需要任何关于类的信息,因此将它们设置为全局而不是将它们包装在类中是有意义的。
关于instance
方法,正如@Duncan C所回答的那样,当你想维持状态时,它们会在实例上被调用。下面的示例显示了静态和实例方法的用法。
enum TapType {
case water
case beer
}
struct Tap {
let tapType: TapType
//static method
static func unlimitedBeer() -> Tap {
let beer = Tap(tapType: .beer)
beer.turnOn(forDuration: Float.greatestFiniteMagnitude)
return beer
}
//instance method: will do operation on a particular instance of `Tap`.
func turnOn(forDuration duration: Float) {
//implementation
}
}
let unlimitedBeer = Tap.unlimitedBeer()
您始终可以使用convenience
初始化程序初始化具有自定义行为的对象,但同样,这是一个选择问题。在上面的例子中,我想不出任何能给我无限量啤酒的convenience
初始化器。