This afternoon, I submitted Swift 3.0 based singularity 2.1.1, mainly adapted to Swift 3.0 + some Bug fixes. In the process of adaptation to Swift 3.0, I have recorded some common problems, I believe that all friends will encounter in the process of adaptation, so summarize such an article to share.

preface

Singularity project is a small Swift pure iOS project with more than ten third-party libraries + over 20,000 lines of code. It is an objective-C project that I have written with Swift since I first got to know Swift in 2014. I later made it into a product and launched it. So one of the values of its existence is to adapt to the new generation of Swift 😂

So when Swift 3.0 came out, I gritted my teeth and decided to adapt immediately. It took me about one night + one day to complete the adaptation work, and at the same time eliminated some incompatible Swift 3 third-party libraries, which can be said to be refreshed.

So let me start by listing the problems and some new concepts I have learned in adapting to Swift.

Any vs AnyObject

Changing AnyObject to Any in a project is probably the first big adaptation you’ll encounter. What explains this change? Prior to Swift 3, we could write a project that represented most instances only with AnyObject, as if we didn’t have to deal with Any. In fact, there is a clear distinction between Any and AnyObject, because Any can stand for struct, class, func, and almost anything else, whereas AnyObject can only stand for instances generated by class.

In Swift 2 we can declare arrays with [AnyObject] and put ints, strings and other structs in them. And that’s because Swift 2 does an Implicit Bridging Conversions for these Int, String, and other structs, so when I insert them in Array, The compiler automatically Bridges it to objective-C NSNumber, NSString, etc., which is why we declare [AnyObject] with structs.

But in Swift 3, in order to achieve a true cross-platform language, the proposals remove Implicit Bridging Conversions. So if you want to put a String struct into an [AnyObject], make sure it is as NSString, these conversions need to be done explicitly — after all, the Linux platform doesn’t have objective-C Runtime by default. This makes performance more consistent across platforms. Of course, this is one of the goals, as can be seen in the discussion of 0116-ID-AS-ANY and related proposals.

The use of the @ discardableResult

Under the Swift 3 compiler, a WARNING is given if a func returns an object that you did not use. This is not tolerable for project cleanliness freaks (you don’t want to see 1 WARNING and 1 ERROR), even though you might not use it on purpose.

There are two ways to resolve this WARNING.

The first is to prefix the func definition with the @discardableresult modifier to indicate that the return value is not used, so that the compiler does not have to warn. We can basically do this on our own definition of func.

But what about objects returned by third-party libraries or system libraries? There’s only two ways to do that:

_ = navigationController? .popViewController(animated: true)Copy the code

I get rid of it by _ like that. It’s ugly, but given Swift is a strict language, bear with it.

The Protocol implementation must be in the corresponding extension

There are some things I didn’t notice when I was writing code, such as UITableViewDelegate and UITableViewDataSource. I used extension to implement them, but I didn’t notice them in the implementation. Put a delegate method into the dataSource extension implementation, and the project works perfectly.

However, with Swift 3.0, if you implement a protocol in an extension, the protocol method must be found in the extension. Not in another extension or in the main class or struct. Otherwise there would be a warning like this:

Objective-C method 'tableView:canEditRowAt:' provided by method 'tableView(_:canEditRowAt:)' does not match the requirement's selector ('tableView:canEditRowAtIndexPath:')
Copy the code

This is also a sign that Swift 3 compilation has become more stringent.

Pit declared Unwrapped Optionals

In the Swift 2 project, we might have code like this that is not particularly secure:

var greetings: String! Greetings = "Hello" print(" greetings ")Copy the code

This will output:

Hello tula dingCopy the code

No problem at all. But in Swift 3, because Optional’s security mechanism works, it becomes:

Optional tula ding (" Hello ")Copy the code

This is not what we wanted. From this we can also see that Swift 3’s IUO behavior has become more secure, making IUO Optional by default. To achieve the same effect as Swift 2, use:

print("\(greetings!) Tula ding ")Copy the code

As you notice, Swift is always in use! I remind you IUO is not safe.

So take this opportunity to refactor old code

Converter has some strange pits

If you are using Xcode’s automatic converter to transfer the Swift 3 project, you should encounter some strange potholes, for example:

  • Uicontrolstate. normal converts to UIControlState(), but other states do not.
  • IndexPath is a Foundation type with NS removed, but there are always things like IndexPath as NSIndexPath that can be removed;
  • All nsnotification. Name can be reconstituted into notification. Name, but the converter does not do this. Meanwhile, the NotificationName that you define as a string can now be uniformly extended with Extension.

Afterword.

After adapting the singularity project of more than 20,000 lines of code, I can actually summarize far more than the above, I just picked some typical ones. What’s more, I’ve only completed the first step of “adaptation”. More work, such as naming the API more Swift 3, refactoring the project to take advantage of some of Swift 3’s features, and so on, has yet to be done.

So in the next road, I will also sum up and learn something. Happy adaptation to Swift 3 😅