官术网_书友最值得收藏!

Setting Objective-C names from Swift

When you write Swift class names, we follow the recommendation of not prefixing our class names or extensions with a two or three letter code. However, back in Objective-C, those conventions are quite important for a number of reasons, but principally to avoid naming collisions with other objects from different frameworks.

Let's consider the following code snippet that defines a movie:

class Movie {
let title: String
let director: String
let year: Int
/* Initializers */
}

As it is right now, it is not possible to use it in Objective-C as the Movie object doesn't inherit NSObject. Also, because you're exposing your class to Objective-C and not following the naming conventions of Objective-C with the prefix, we should probably rename the class with the @objc(...) declaration:

@objc(FVMovie)
class Movie: NSObject {
/* Original code */
}

The previous class will be exposed to Objective-C as FVMovie and not Movie and can be used properly and naturally in your Objective-C code.

Let's now imagine, you have written an extension for String in Swift called leftPad and you'll need it in Objective-C now. In Objective-C, we deal with NSString, not String, so the extensions are not exposed by default:

extension String {
static let padCharacter = " "
func leftPad(to length: Int, with character: String = .padCharacter) -> String {
/* Your left pad implementation */
}
}

There are multiple steps required to expose it to Objective-C:

  • @objc cannot be applied to String as it's a struct, and Swift structs can't be exported to Objective-C
  • The leftPad name should be prefixed, as per Objective-C recommendations
  • String doesn't exist in Objective-C, but NSString does

Let's create an extension on NSString:

extension NSString {
func leftPad(to length: Int, with character: String = .padCharacter) -> String {
return (self as String).leftPad(to: length, with: character)
}
}

You'll realize that the method is still not exposed to Objective-C as the extension is not exposed by default. You can remedy that by marking the full extension @objc:

@objc
extension NSString { /* */ }

Now you can use the leftPad method in Objective-C:

NSString * padded = [@"Hello" leftPadTo:10 with:@" "];
// padded == @" Hello"

There are a few things we should improve before we can move on with that implementation:

  • The default character used in padding (String.padCharacter) isn't available
  • The method name isn't the best for Objective-C
  • This doesn't follow the recommended prefixed naming conventions

In order to expose the default implementation that requires only the target length, we need to add an additional method:

extension NSString {
func leftPad(to length: Int) -> String {
return (self as String).leftPad(to: length)
}
}

This will leverage the original default implementation in Swift, so it's usable in Objective-C as well:

NSString * padded = [@"Hello" leftPadTo:10];
// padded == @" Hello"

Now let's put proper names on the methods:

extension NSString {
@objc(flv_leftPadToLength:)
func
leftPad(to length: Int) -> String

@objc(flv_leftPadToLength:withCharacter:)
func leftPad(to length: Int, with character: String) -> String
}

Now you'll be able to use those implementations in Objective-C with the following:

[@"Hello" flv_leftPadToLength:10]; // @"     Hello"
[@"Hello" flv_leftPadToLength:10 withCharacter:@"*"]; // @"*****Hello"

In this section, we've focused on adapting our Swift code to Objective-C so it's easier to use and more natural in the Objective-C style. In the next section, we'll focus on the opposite, making our Objective-C code more natural to Swift.

主站蜘蛛池模板: 台南县| 旬邑县| 临澧县| 锦屏县| 仙游县| 台东市| 濉溪县| 广昌县| 长汀县| 合水县| 南部县| 萍乡市| 大庆市| 怀来县| 江安县| 女性| 西峡县| 登封市| 喜德县| 海伦市| 炉霍县| 浙江省| 青川县| 灵台县| 余干县| 昂仁县| 祁东县| 封开县| 平顺县| 贞丰县| 梁山县| 湘潭县| 桂林市| 沂水县| 琼中| 夏津县| 孟津县| 嘉荫县| 海南省| 仁怀市| 德阳市|