【发布时间】:2014-09-13 22:15:18
【问题描述】:
在 Objective-C 中,NSObject 有一个名为 load 的类方法,该方法在第一次加载类时被调用。 Swift 中的等价物是什么?
@implementation MyClass
+ (void)load
{
[self registerClass];
}
@end
【问题讨论】:
标签: objective-c swift
在 Objective-C 中,NSObject 有一个名为 load 的类方法,该方法在第一次加载类时被调用。 Swift 中的等价物是什么?
@implementation MyClass
+ (void)load
{
[self registerClass];
}
@end
【问题讨论】:
标签: objective-c swift
斯威夫特 5
方法'load()'定义了Objective-C类方法'load',Swift不允许这样做
您现在不能覆盖load() 方法,但是有一种合法的方法可以在应用启动时调用您的swift 类的自定义swift_load() 方法。需要使 ObjC 类将其自己的 load() 方法重定向到您的 swift 类。
只需将下一个SwiftLoader.m 文件添加到您的项目中:
// SwiftLoader.m
@interface SwiftLoader : NSObject
@end
@implementation SwiftLoader
+ (void)load {
SEL selector = @selector(swift_load);
int numClasses = objc_getClassList(NULL, 0);
Class* classes = (Class *)malloc(sizeof(Class) * numClasses);
numClasses = objc_getClassList(classes, numClasses);
for (int i = 0; i < numClasses; i++) {
Class class = classes[i];
Method method = class_getClassMethod(class, selector);
if (method != NULL) {
IMP imp = method_getImplementation(method);
((id (*)(Class, SEL))imp)(class, selector);
}
}
free(classes);
}
现在您可以将swift_load 类方法添加到您的任何 swift 类中以进行设置任务:
class MyClass {
@objc
class func swift_load() {
print("load")
}
}
【讨论】:
在this PR 中删除了使用此方法的功能。
它提供了一些理由:
Swift 的语言模型不保证会真正使用类型元数据,这使得覆盖
initialize()容易出错,并且并不比手动调用初始化函数更好。为 Swift 3 的兼容性发出警告,并拒绝在 Swift 4 中覆盖+initialize的尝试。
【讨论】:
Swift 中的等价物是什么?
没有。
与存储实例属性不同,您必须始终为存储类型属性赋予默认值。这是因为类型本身没有初始化器,可以在初始化时为存储的类型属性赋值。
来源:“Swift 编程语言”,Apple 出品
类型在 Swift 中根本没有初始化器。正如这里的几个答案所建议的那样,您可以通过使用 Objective-C 桥并让您的 Swift 类继承自 NSObject 或使用 Objective-C 加载程序引导代码来解决这个问题,但如果您有一个 100% 的 Swift 项目,你基本上只有两种选择:
class MyCoolClass {
static func initClass ( ) {
// Do your init stuff here...
}
}
// Somewhere in a method/function that is guaranteed to be called
// on app startup or at some other relevant event:
MyCoolClass.initClass()
class MyCoolClass {
private static var classInitialized: Bool = {
// Do your init stuff here...
// This code will for sure only run once!
return true
}()
private static func ensureClassIsInitialized ( ) {
_ = self.classInitialized
}
func whateverA ( ... ) {
MyCoolClass.ensureClassIsInitialized()
// Do something...
}
func whateverB ( ... ) {
MyCoolClass.ensureClassIsInitialized()
// Do something...
}
func whateverC ( ... ) {
MyCoolClass.ensureClassIsInitialized()
// Do something...
}
}
这遵循一个干净的模式,即 Swift 中没有代码“自动”运行,代码只有在其他代码指示它运行时才会运行,这提供了清晰和可跟踪的代码流。
对于特殊情况可能有更好的解决方案,但您尚未提供任何信息说明您为什么需要该功能。
【讨论】:
在 Swift 1.2 之前:
override class func load() {
NSLog("load");
}
编辑:
从 Swift 1.2 开始,您不能再覆盖 load 方法。请查看 initialize 方法,但它的行为与加载不同,它在第一次在某处引用该类时被调用,而不是在应用程序初始加载时调用
【讨论】:
NSObject。
import Foundation @objc class MyClass { class func load() { println("sdfsdf") } }
internal override class func initialize() { } 用于 NSObject 子类。我没有发现 initialize() 可以在纯 Swift 对象中使用。
initialize。
在 Swift 2.0 中,请使用此方法
public override class func initialize()
【讨论】:
@objc。
我得到了 swift 1.2~5 可行方法的结论:
Doable |swift-load |swift-initialze|bridgeToOC-load|bridgeToOC-initialze|
--- |---- |--- |--- |--- |
swift1.2~4.2|X |O |O |O |
swift4.2~5.0|X |X |O |O |
swift5.0~? |X |X |X |O |
以及如何制作?看这里
https://medium.com/post-mortem/using-nsobjects-load-and-initialize-from-swift-f6f2c6d9aad0
但我认为这是另一种让它更快的方法。在没有加载/初始化的情况下使用运行时和协议。
http://jordansmith.io/handling-the-deprecation-of-initialize/
【讨论】:
更新:从 Swift 5 开始,Swift 类上的类扩展和类别不允许有 +load 方法,不过 +initialize 似乎没有被禁止。
虽然 Swift 不提供直接等效,但使用 Objective-C 和类别可以相对优雅地实现这一点。 Foo 仍应继承自 NSObject 并具有类/静态非私有 swiftyLoad/Initialize 方法,这些方法可从 Loader.m 中的 Objective-C 调用,您将其与 Foo.swift 一起包含在编译源中:
# Loader.m
#import <Foundation/Foundation.h>
#import <MyProject/MyProject-Swift.h>
// This was a more concise solution in Swift 4.2 and earlier. If you try
// this with Swift 5 you'd get "Swift class extensions and categories
// on Swift classes are not allowed to have +load methods" runtime error.
// @implementation Foo (private)
// + (void)load { [self swiftyLoad]; }
// + (void)initialize { [self swiftyInitialize]; }
// @end
// This is what you'd want to use with Swift 5 onwards, basically
// just a pure Objective-C defined class.
@interface Loader : NSObject
@end
@implementation Loader : NSObject
+ (void)load { [Foo swiftyLoad]; }
+ (void)initialize { [Foo swiftyInitialize]; }
@end
# Foo.swift
import Foundation
public class Foo: NSObject {
@objc public static func swiftyLoad() {
Swift.print("Rock 'n' roll!")
}
@objc public static func swiftyInitialize() {
Swift.print("Hello initialize!")
}
}
最好的部分是不需要弄乱桥接头或其他任何东西,它就可以工作。有几个陷阱,尤其是在静态库中使用这种方法时,请查看 Medium 上的完整 post 了解详细信息! ✌️
【讨论】:
NSObject noo :(
对于 Swift 2 或 3(即后 Swift 1.2),您可以使用:
class MySwiftClass: NSObject {
internal override class func initialize() {
DoStuff()
super.initialize()
}
}
但是,如您所见,您的类需要(直接或间接)继承自 NSObject。这是必需的,因为 initialize() 由 ObjC 运行时调用。
并且initialize()方法只会在MySwiftClass被引用时被调用。所以不会像load()那么神奇。
但它也会更安全。例如:包含一个框架(比如说,只需将其添加到您的Podfile)不会让框架在您的应用程序启动后神秘地开始运行,而无需在您的应用程序中添加一行代码项目(至少……我希望!?)。
【讨论】:
在 Swift 1.2 中删除了对覆盖加载的支持
【讨论】: