Is There an Alternative to Initialize() in MACos Now That Swift Has Deprecated It

Swift 3.1 deprecates initialize(). How can I achieve the same thing?

Easy/Simple Solution

A common app entry point is an application delegate's applicationDidFinishLaunching. We could simply add a static function to each class that we want to notify on initialization, and call it from here.

This first solution is simple and easy to understand. For most cases, this is what I'd recommend. Although the next solution provides results that are more similar to the original initialize() function, it also results in slightly longer app start up times. I no longer think
it is worth the effort, performance degradation, or code complexity in most cases. Simple code is good code.

Read on for another option. You may have reason to need it (or perhaps parts of it).


Not So Simple Solution

The first solution doesn't necessarily scale so well. And what if you are building a framework, where you'd like your code to run without anyone needing to call it from the application delegate?

Step One

Define the following Swift code. The purpose is to provide a simple entry point for any class that you would like to imbue with behavior akin to initialize() - this can now be done simply by conforming to SelfAware. It also provides a single function to run this behavior for every conforming class.

protocol SelfAware: class {
static func awake()
}

class NothingToSeeHere {

static func harmlessFunction() {

let typeCount = Int(objc_getClassList(nil, 0))
let types = UnsafeMutablePointer<AnyClass>.allocate(capacity: typeCount)
let autoreleasingTypes = AutoreleasingUnsafeMutablePointer<AnyClass>(types)
objc_getClassList(autoreleasingTypes, Int32(typeCount))
for index in 0 ..< typeCount { (types[index] as? SelfAware.Type)?.awake() }
types.deallocate(capacity: typeCount)

}

}

Step Two

That's all good and well, but we still need a way to actually run the function we defined, i.e. NothingToSeeHere.harmlessFunction(), on application startup. Previously, this answer suggested using the Objective-C code to do this. However, it seems that we can do what we need using only Swift. For macOS or other platforms where UIApplication is not available, a variation of the following will be needed.

extension UIApplication {

private static let runOnce: Void = {
NothingToSeeHere.harmlessFunction()
}()

override open var next: UIResponder? {
// Called before applicationDidFinishLaunching
UIApplication.runOnce
return super.next
}

}

Step Three

We now have an entry point at application startup, and a way to hook into this from classes of your choice. All that is left to do: instead of implementing initialize(), conform to SelfAware and implement the defined method, awake().

Swift equivalent to ObjC Module Initializers

Currently, Swift does not have this functionality. You can either just define an initialization function for your framework and ask your clients to call it before using any other APIs, or you can just mix in an Objective-C file into the project.

How to replace deprecated .animation() in SwiftUI?

You need tell Xcode what exactly should be animated! With given a variable that conform to Equatable protocol. That could be State or Binding or any other wrapper that allow you to update the value of it.

Example:

struct ContentView: View {

@State private var offset: CGFloat = 200.0

var body: some View {

Image(systemName: "ant")
.font(Font.system(size: 100.0))
.offset(y: offset)
.shadow(radius: 10.0)
.onTapGesture { offset -= 100.0 }
.animation(Animation.easeInOut(duration: 1.0), value: offset)

}
}

Result:

Sample Image

Is the fetchAssetCollections method deprecated in latest version of Photos library?

The only way to fix it is by recreating the project.

How to manually deprecate members

You can use the Available tag, for example :

@available(*, deprecated)
func myFunc() {
// ...
}

Where * is the platform (iOS, iOSApplicationExtension, macOS, watchOS, tvOS, * for all, etc.).

You can also specify the version of the platform from which it was introduced, deprecated, obsoleted, renamed, and a message :

@available(iOS, deprecated:6.0)
func myFunc() {
// calling this function is deprecated on iOS6+
}

Or

@available(iOS, deprecated: 6.0, obsoleted: 7.0, message: "Because !")
func myFunc() {
// deprecated from iOS6, and obsoleted after iOS7, the message "Because !" is displayed in XCode warnings
}

If your project targets multiple platforms, you can use several tags like so :

@available(tvOS, deprecated:9.0.1)
@available(iOS, deprecated:9.1)
@available(macOS, unavailable, message: "Unavailable on macOS")
func myFunc() {
// ...
}

More details in the Swift documentation.



Related Topics



Leave a reply



Submit