Difficulties converting to Swift 3 - swift

After converting from Swift 2 to Swift 3 (even after converting edit-> convert -> to current swift syntax) I am getting lots of errors. Especially:
I am shown total 90 errors for my project which was working fine in Swift 2 before i downloaded this beta Xcode 8.0 and converted to Swift 3
Is this a conversion mistake I am making?

Most of them are easy fixes, simply by tapping the red button, and having Xcode fix it for you! Others include:
CGRect
Swift 2:
let frame = CGRectMake(0, 0, 20, 20)
Swift 3:
let frame = CGRect(x: 0, y: 0, width: 20, height: 20)
CGPoint
Swift 2:
let point = CGPointMake(0, 0)
Swift 3:
let point = CGPoint(x: 0, y: 0)
CGSize
Swift 2:
let size = CGSizeMake(20, 20)
Swift 3:
let size = CGSize(width: 20, height: 20)
CGRectGetMidX
Swift 2:
CGRectGetMidX(view)
Swift 3:
view.midX
CGRectGetMidY
Swift 2:
CGRectGetMidY(view)
Swift 3:
view.midY
UIColor
Swift 2:
let color = UIColor.redColor()
Swift 3:
let color = UIColor.red
"NS"
Swift 2:
NSTimer
NSData
NSError
Swift 3:
Timer
Data
Error
UserDefaults
Swift 2:
NSUserDefaults.standardUserDefaults().//something
Swift 3:
UserDefaults.standard.//something

And always remember to use the helpful "Fix all in Scope" function which can be found at Editor -> Fix all in Scope

I was converting a project and Xcode was not helping me with any fixes so I resorted to a couple of regex search-and-replaces:-
CGPointMake\((.*),[ ]*([^\)]+)\)
CGPoint(x:$1, y:$2)
CGSizeMake\((.*),[ ]*([^\)]+)\)
CGSize(width:$1, height:$2)
Note they are not aware of nested parentheses , but probably good enough for 90% of cases.

Related

Mysterious UIColor behaviour with UIView and in General in Swift

Recently I came across an interesting(may be naive) problem regarding UIColor in Swift..
import UIKit
let view = UIView(frame: CGRect(x: 0,
y: 0,
width: 50,
height: 50))
view.backgroundColor = .systemBlue
let a = UIColor.systemBlue
switch a {
case .red:
print("red")
case .systemBlue:
print("blue")
default:
print("unknown")
}
Following code prints "blue" on playground perfectly fine, but changing
let a = UIColor.systemBlue
to
let a = view.backgroundColor ?? .red
prints "unknown" in playground, May someone help what is happening here? I could not resolve it.. Is it something related to value type or reference type at some point?? Please help!!
Printing the two values gives you the explanation:
print(UIColor.systemBlue)
<UIDynamicSystemColor: 0x600000b47880;
name = systemBlueColor
>
print(view.backgroundColor!)
<UIDynamicModifiedColor: 0x60000058bed0;
contrast = normal,
baseColor = <UIDynamicSystemColor: 0x600000b47880;
name = systemBlueColor
>
>
When setting the backgroundColor property, UIKit wraps the color in a private class UIDynamicModifiedColor.
If you compare the resolved colors using the view's traits, you'll get true:
UIColor.systemBlue.resolvedColor(with: view.traitCollection) ==
view.backgroundColor!.resolvedColor(with: view.traitCollection)
The resolved color is an absolute color:
print(UIColor.systemBlue.resolvedColor(with: view.traitCollection))
UIExtendedSRGBColorSpace 0 0.478431 1 1
A color such as UIColor.systemBlue is a dynamic color that might result in different colors, depending on the view's traits, which include factors such as high-contrast mode and dark/light mode.
From the docs of UIColor.systemBlue:
A blue color that automatically adapts to the current trait environment.

Why are UIScreen.bounds incorrect in iOS11

Please don't mark as duplicate. Available threads haven't provided an answer. Behavior is iOS11 only.
Updating a project from Xcode 8 to Xcode 9, using now iOS11 but still Swift 3, I have the following experience:
print("UIScreen.main.bounds.width = \(UIScreen.main.bounds.width)")
print("self.view.frame.width = \(self.view.frame.width)")
let rect = CGRect(
x: 0,
y: 0,
width: UIScreen.main.bounds.width,
height: UIScreen.main.bounds.height * 0.25
)
prints:
UIScreen.main.bounds.width = 414.0
self.view.frame.width = 600.0
The view is supposed to be from screen edge to screen edge. Therefore I have used UIScreen.main.bounds.width. But the value far too small for the actual view controller size of self.view.frame.width.
Why is that? What am I missing? Help is very appreciated.
Physical device. Same behavior using UIScreen.main.bounds.width
I had a similar problem with incorrect fetching of UIScreen.main.bounds size. The size was less than a physical screen. The solution was to add the next line into info.plst:
Key:
Launch screen interface file base name
Type:
String
Value:
LaunchScreen
So check your info.plist to see if it contains this line. If it's not, just add it. Hope this helps.
screen shot of info.plst

What is the benefit of define constant by closure in Swift 3

let a: UIView = {
let a = UIView()
a.frame = CGRect(x: 0, y: 0, width: 20, height: 20)
return a
}()
I saw a lot of people's Swift source code defining let as this way. I just curious what is the benefit of this way?
In this case, there is no benefit, but if the variable in question were a value type then the benefit would be that you could perform some mutating setup code and still get a constant out of it.
It also lets you hide temporary variables that were only needed to initialize the constant, since they'll only exist inside the closure's scope.

Why is 'nil' not compatible with 'UnsafePointer<CGAffineTransform>' in Swift 3?

Trying to create a CGMutablePath() as such:
let path = CGMutablePath()
CGPathMoveToPoint(path, nil, 30, 0)
but the compiler keeps on giving me the following error: 'nil' not compatible with expected argument type 'UnsafePointer<CGAffineTransform>'. What am I doing wrong? I can't seem to find anything else online.
(Yes I've tried converting the Ints to CGFloats but it doesn't seem to make a difference.)
Try this:
let path = CGMutablePath()
path.move(to: CGPoint(x: 30, y: 0))
CGPath APIs are now imported as instance methods in Swift 3.
You can check them with Command-clicking on CGMutablePath.
Or see the latest reference of CGMutablePath.
I was getting this error when trying to draw inside a CGRect
This solved it for me:
let framePath : CGMutablePath = CGMutablePath()
framePath.addRect(frameRect)
I hope this saves you countless hours trying to solve this. :)

How to Create a CGSize in Swift?

How can I create a CGSize in Swift? This is what I have tried so far (but doesn't work):
var s:CGSize = {10,20}
var s:CGSize = CGMakeSize(10,20)
Your first attempt won't work because C structs don't exist in Swift. You need:
let size = CGSize(width: 20, height: 30)
Or (before Swift 3 only, and even then, not preferred):
let size = CGSizeMake(20,30)
(Not MakeSize).
As of Swift 3 you can no longer use CGSizeMake
The solution for Swift 3 is var size = CGSize(width: 20, height: 30)