swift 2.2: failable initializers in lazy properties - swift

First very appreciate for your help. I just upgraded Xcode yesterday which contains swift 2.2. I've faced a few issues but I fixed them quickly by following the "what's new in swift 2.2" topics from Natashatherobot. But there is one issue I cannot fix. It's about failable initializers of UIFont which was introduced in swift 2.2. Attached is a simple piece of code that will report error in swift 2.2. It might not report the error immediately, until I cleaned the project.
lazy var somelabel: UILabel = {
let label = UILabel()
let font = UIFont(name: "somefont", size: 10) ?? UIFont.systemFontOfSize(10) //this line gave me error
label.font = font
label.text = "Calculating..."
return label
}()
Here is the screenshot of the error
The error is : (name: String, size: CGFloat) -> UIFont' is not convertible to '(name: String, size: CGFloat) -> UIFont?'
I can fix it in two ways:
Method 1: don't put this line:
let font = UIFont(name: "somefont", size: 10) ?? UIFont.systemFontOfSize(10)
in the 'lazy instantiation' closure. (Put it in computed properties reports no error)
Method 2: instead of using:
UIFont(name: "somefont", size: 10)
use the below instead( However I don't think this should be the right approach because it makes the initializer more "objc" style):
UIFont.init(name: "somefont", size: 10)
But I still don't understand why it would report me error in the lazy property closure. I will be very appreciated if someone can give me some explanations.

This might be a bug of the latest version xcode. Those whose project was set up before the upgrade might face this problem. Anyone who is luck enough to face such issue can try to start a new project in swift 2.2 environment.

Related

Swift Xcode warning / Expression implicitly coerced from '[NSAttributedString.Key : UIFont?]' to '[NSAttributedString.Key : Any]' [duplicate]

Someone else must have received this message while (or after) converting an iOS project to Swift 3, yet when I do a Google search, I get no relevant results.
Anyway, after converting to Swift 3, I have about 30 warnings that say:
Expression implicitly coerced from 'UIView?' to Any
But the warnings do not point to any specific line of code. They only reference the class where the warning exists.
Does anyone have an insight into this warning or how I might go about silencing them?
In my case it was an issue related to a dictionary without explicit type:
let dict = ["key": value]
Than I solved specifying the type:
let dict: [String: Any] = ["key": value]
In your case you can specify your value type:
let dict: [String: UIView] = ["key": value]
This will happen when the function you are calling has a parameter of type Any, and you are passing an optional.
For example:
let color: UIColor? = UIColor.red
UIBarButtonItem.appearance().setTitleTextAttributes([NSFontAttributeName: color], for: .normal)
Notice that color is of type UIColor? and that setTitleTextAttributes expects a dictionary of type [String: Any]?.
In order to avoid the warning you have to either force unwrap your optional, or cast it to Any.
UIBarButtonItem.appearance().setTitleTextAttributes([NSFontAttributeName: color!], for: .normal)
or
UIBarButtonItem.appearance().setTitleTextAttributes([NSFontAttributeName: color as Any], for: .normal)
Looks like a bug in the Swift compiler:
https://bugs.swift.org/browse/SR-2921
Currently, I'm seeing this with Xcode 8.1 and 8.2 beta 1.
In your case, the warning should identify the source file, but not the line - as you stated. You will have to hunt around for calls to functions with Any parameters.
Good new is that it appears fixed in an upcoming Swift toolchain.
I believe this is fixed in Xcode 8.3 beta 1 (but have not confirmed)
Problem
The expected type is Any but the type provided was UIView?
The problem is with the optional, just make sure an instance of UIView is passed and things would work.

Unresolved identifier 'CALayerContentsGravity' in Swift 4

The below code works well with "Swift 3" but giving error of "unresolved identifier CALayerContentsGravity" in "Swift 4"
static func create(image: UIImage, size: Double) -> CALayer {
let containerLayer = createContainerLayer(size)
let imageLayer = createContainerLayer(size)
containerLayer.addSublayer(imageLayer)
imageLayer.contents = image.cgImage
imageLayer.contentsGravity = CALayerContentsGravity.resizeAspect
return containerLayer
}
In swift4 CALayerContentsGravity is not working.
To set contentsGravity of layer you should use constant string which is available in swift4.
imageLayer.contentsGravity = kCAGravityResizeAspect
Hope it will work.
i had this problem after I imported the Cosmos pod. I spoke to the author and he said I need to check the pod's target and the Swift language it used.
When I check the Cosmos target the Swift version was 4 but my main project used Swift 4.2. Once I changed the Cosmos pod's version from 4 to 4.2 the error went away.
suggestion from Cosmos author
This is how you check the Cosmos pod Swift version
It needs to match what's in your main project's target:

Erratic error in SnapKit

The following is my viewDidAppear() method with which I'm trying to prototype a feature for my app. The graphicsView instance variable is bound via the storyboard to an instance of a subclass of NSView I've written that in turn is enclosed in an NSScrollView within an NSSplitView. This code is within the view controller for that view.
override func viewWillAppear() {
super.viewWillAppear()
let red = CGColor.init(red: 1, green: 0, blue: 0, alpha: 1)
self.view.layer?.backgroundColor = red
let box = NSTextView()
self.graphicsView.addSubview(box)
box.snp.makeConstraints { (make) -> Void in
make.edges.equalTo(self.graphicsView).inset(NSEdgeInsetsMake(100, 100, self.graphicsView.bounds.height - 200, self.graphicsView.bounds.width - 300))
}
box.textStorage?.append(NSAttributedString(string: "Hello Sailor"))
box.alignCenter(self)
}
When executed, I get the error Cannot form weak reference to instance (0x6000001224e0) of class NSTextView. It is possible that this object was over-released, or is in the process of deallocation. along with the usual EXC_BAD_INSTRUCTION fault on the closing bracket of the trailing closure for the constraints.
As far as I can see, the NSTextView will be strongly retained by box, and so I'm at a loss to see the source of the error. The error shows up at the first line of ConstraintItem.init(target: AnyObject?, attributes: ConstraintAttributes). Per the instructions in the readme I'm posting here; can someone on the SnapKit team perhaps shed any additional light on the error? (The app works normally if I remove the box-related code.)
Added information:
The exception happens at line 37 of ConstraintItem.swift, which is self.target = target. I set a breakpoint right before that line and executed e target in the debugger; here's what I got:
(lldb) e target
(AnyObject?) $R1 = (instance_type = 0x0000608000164c80) {
instance_type = 0x0000608000164c80 {
AppKit.NSTextView = {
baseNSText#0 = <extracting data from value failed>
}
title = "some random text"
minimumWidth = 100
}
}
I found several answers.
How you search Google remains important. I varied my searches some more and came upon this here on SO, the short version of which is that it says you can't form a weak reference specifically to NSTextView and includes a link to explanatory Clang documentation.
Perhaps more interestingly, I also found the answer for "erratic" errors I mentioned in the title - one of the machines I develop on turns out to have Swift 3.1, but the other has 3.0.2. The more recent version does not exhibit the error forming the weak link, suggesting Apple has upgraded the NSTextView implementation.

NSStringDrawingUsesLineFragmentOrigin unresolved?

I'm developing a Swift app in Xcode 6.1 targeting iOS >= 7 and can't use NSStringDrawingUsesLineFragmentOrigin because it's unresolved. I've googled it but all I find are examples that use it, apparently without issue. Current docs on Apple's site show it as valid. Has anyone encountered / solved the same problem?
Edit:
I've got it working with NSStringDrawingOptions.UsesLineFragmentOrigin (thanks Matt) which I had tried yesterday, but it only works with the target context set to nil. Yesterday when I was passing a valid context, anything I passed in "options" showed as unresolved. Strangely, today if I pass a valid context, the compiler gives me a different error -- "NSString is not identical to NSObject" on my font attributes! I wonder if this is just some quirky bug in the Swift compiler? Anyway, here's the code that eventually compiled:
var textStyle = NSMutableParagraphStyle.defaultParagraphStyle().mutableCopy() as NSMutableParagraphStyle
textStyle.alignment = NSTextAlignment.Left
let fontAttributes = [
NSFontAttributeName: UIFont(name: "Georgia", size: tileSize * CLUES_FONT_SCALE)!,
NSForegroundColorAttributeName: UIColor.blackColor(),
NSParagraphStyleAttributeName: textStyle
]
size = text.boundingRectWithSize(
CGSize(width: width, height: 1000),
options: NSStringDrawingOptions.UsesLineFragmentOrigin,
attributes: fontAttributes,
context: nil
)
Note that if I replace:
NSStringDrawingOptions.UsesLineFragmentOrigin
with
NSStringDrawingUsesLineFragmentOrigin
as shown in the Apple docs, I get "use of unresolved identifier".
I just fired up Xcode 6.1, created a Swift iOS project with a deployment target of iOS 7.0, and pasted the following code into my application's didFinishLaunchingWithOptions:
let attrib_string = NSAttributedString(string: "Foo")
let rect = attrib_string.boundingRectWithSize(
CGSize(width: 100, height: 100),
options: .UsesLineFragmentOrigin,
context: nil)
println(rect)
It compiled, linked and ran fine, and printed the result to the console:
(0.0,0.0,20.6777,13.8)
You may need to edit your question to provide a complete example, and the exact error message you're getting. I couldn't see any oddities; using the fully qualified enum value of NSStringDrawingOptions.UsesLineFragmentOrigin worked fine, too.

NSFontAttributedString worked before XCode 6.1

let timeFont = [NSFontAttributeName:UIFont(name: "Voyage", size: 20.0)]
var attrString3 = NSAttributedString("(Time)", attributes : timeFont); // <--- compiler error "Extra argument in call"
This code worked in xcode 6.0, but now that I've upgraded to xcode 6.1 it doesn't work anymore and I can't figure out what I need to get it back working. It says that there is an extra argument, but that's not correct. I believe that it has something to do with the new failable initializers, but everything that I've tried doesn't' work.
There are two reasons your code is failing to compile:
The initializer for NSAttributedString that you want to use now requires the explicit labeling of the string parameter
The UIFont initializer that you are using now returns an optional (i.e., UIFont?), which needs to be unwrapped before you pass it in the attributes dictionary.
Try this instead:
let font = UIFont(name: "Voyage", size: 20.0) ?? UIFont.systemFontOfSize(20.0)
let attrs = [NSFontAttributeName : font]
var attrString3 = NSAttributedString(string: "(Time)", attributes: attrs)
Note the use of the new coalescing operator ??. This unwraps the optional Voyage font, but falls back to the System Font if Voyage is unavailable (which seems to be the case in the Playground). This way, you get your attributed string regardless, even if your preferred font can't be loaded.
Xcode 6.1 comes with Swift 1.1 that supports constructors that can fail. UIFont initialisation can fail and return nil. Also use string: when creating NSAttributedString:
if let font = UIFont(name: "Voyage", size: 20.0) {
let timeFont = [NSFontAttributeName:font]
var attrString3 = NSAttributedString(string: "(Time)", attributes : timeFont)
}