So I've recently had to convert my project to Swift 3, and while a bit of a pain, it has mostly gone ok. However I am now down to one final set of errors that I can't work out!
Im using
self.convert(point, to: v)
to convert a point between views, but Xcode keeps giving me build errors saying that
'convert(_:to:)' is only available on iOS 8.0 or newer
This seems to be due to the method definition
public protocol UICoordinateSpace : NSObjectProtocol {
#available(iOS 8.0, *)
public func convert(_ point: CGPoint, to coordinateSpace: UICoordinateSpace) -> CGPoint
...
}
clashing with the normal UIView one
extension UIView {
...
open func convert(_ point: CGPoint, to view: UIView?) -> CGPoint
...
}
I can't for the life of me work out how to resolve this! Has anyone come across this or have any idea how to fix it?!
You can manually set the iOS Deployment Target to 7.0, and Xcode builds the app as targeted to 7.0. (I don't know apps built with that manner can be approved for App Store.)
So, you can test that behaviour with your Xcode 8.
And you can silence Xcode with this:
self.convert(point, to: v as UIView?)
With new renaming rule of Swift 3, some imported methods may have the same signature in Swift, and I'm afraid some of them may not have this sort of workaround, and may not be solved by changing target version.
Ok, if anyone else has this issue, turns out it's because pre-iOS 8 is no longer supported. If you update your project to recommended settings, it will set your minimum iOS version to 8 and everything will be happy :)
Related
So, I recently updated my MacOS to Catalina and installed XCode 11.5. Before that I had High Sierra and the maximum version of XCode that High Sierra supports (don't remember the version number).
So, an app I had built on that combo worked fine in XCode, but now after the update when I open I cannot run the app, because I get a Strideable error. I have the following code in one of my controllers which worked fine before this:
extension Date : Strideable {
public func advanced(by n: Int) -> Date {
return Calendar.current.date(byAdding: .day, value: n, to: self) ?? self
}
public func distance(to other: Date) -> Int {
return Calendar.current.dateComponents([.day], from: other, to: self).day ?? 0
}
}
I basically use this for a calendar I am implementing inside the app.
So, now when I try to run the app I get these two errors:
Protocol 'Strideable' requires 'advanced(by:)' to be available in iOS 11.0.0 and newer
Protocol 'Strideable' requires 'distance(to:)' to be available in iOS 11.0.0 and newer
As you can see I have both these functions implemented.
Inside my app's Deployment Info I have iOS 11.0 as minimum requirement for the app.
Besides, the current version of the app is published on the App Store and working fine. What can be the issue here?
Ok, I am not sure why, but apparently at some point there was an update for Strideable, so the only thing I had to do was delete my Strideable extension.
Once I did that, the app worked without any issues.
I tried to build my project in Xcode 11 and it throws 26 identical errors
<unknown>:0: error: '==' is only available in iOS 13.0 or newer
The errors happen on Compile Swift source files stage upon calling CompileSwift normal arm64 /long/path/to/MyClass.swift .... There is no context help pointing to anything within the files. The files are quite different but look harmless and does not share anything in common.
After a lot of pain, I found the 4-month old app version compiles fine. So I did git bisect and found the offending commit, and then this code:
struct Config: Equatable {
let formatDescription: CMFormatDescription
let orientation: CGImagePropertyOrientation
}
Turns out CMFormatDescription did become Equatable only in iOS 13, while the app deployment target is iOS 11. It probably felt back to [NSObject isEqual:] in Xcode 10, but it became complicated in Xcode 11. Since Swift automatically generates Equatable conformance under the hood it had troubles in pointing the exact place of the error. The solution is to add your own Equatable implementation for CMFormatDescription:
extension CMFormatDescription: Equatable {
public static func == (lhs: CMFormatDescription, rhs: CMFormatDescription) -> Bool {
return CMFormatDescriptionEqual(lhs, otherFormatDescription: rhs)
}
}
I couldn't get hitTest (with no options) to detect geometries that are hidden behind some other geometry in iOS 11. My code worked fine on iOS 10. Anyone know how to fix?
Example:
let hitResults = scnView.hitTest(location, options: nil)
Should return several nodes - but does only return one node.
You should use the symbolic constant SCNHitTestSearchMode.all instead of 1, it's more descriptive.
if #available(iOS 11.0, *) {
hitResults = scnView.hitTest(location, options: [.searchMode: SCNHitTestSearchMode.all.rawValue]) }
}
The other options are .closest and .any.
Adding some additional details - in my experience, there has been a major change from iOS 10 to iOS 11 in the way SceneKit handles touches. Specifically, the DEFAULT operation in SceneKit, as Bernd notes above, is now that only the first node touched in the "ray" is returned in the [SCNHitTestResult].
The additional comment is that if you were hoping for backward compatibility to iOS 10 or before, I couldn't seem to get it to work, because the solution noted above requires iOS 11 Deployment Target. So Apple seems to have changed the default way touches are handled, and if you want it to work the original way, you must change the default of [SCNHitTestOption.searchMode : 1], which is only available if/when you change your Deployment Target to iOS 11 or higher. ( thanks, Apple)
Here are some futher oddities I found as I searched for a way to make an iOS 10 deployment work with Xcode 9 / iOS 11 updates. (note: I had upgraded my phone to iOS 11 when testing these scenarios with an iOS 10.3 Deployment Target build)
the [SCNHitTestOption.firstFoundOnly : 0], while available with iOS 10 deployment, seems to be ignored if .searchMode isn't also set to 1, which requires iOS 11
similarly [SCNHitTestOption.categoryBitMask : ], while avail with iOS 10 deployment, seems to be ignored if .searchMode isn't also set to 1...
Bottom line, from what I can tell, is that Apple does everything in its power to force devs to upgrade to the latest OS (either wittingly or unwittingly), which then "encourages" end users to have to upgrade to get the latest app updates.
I was able to find a fix - and will share it here, maybe its useful for somebody else:
Apple introduced this new searchMode - which is by default "closest" - you can get the old behavior by setting searchMode to ALL = 1
if #available(iOS 11.0, *) {
hitResults = scnView.hitTest(location, options: [SCNHitTestOption.searchMode: 1])
}
Or in Objective C...
options:#{SCNHitTestOptionSearchMode : [NSNumber numberWithInt:1]}
I have created an ARKit project using a beta version of Xcode 9, which I was able to run on my real device without issues.
Yesterday, I upgraded to Xcode 9 GM, and without touching anything, Xcode shows multiple errors, saying it does not know ARSessionConfiguration i.e.:
Use of undeclared type 'ARSessionConfiguration'
and:
Use of undeclared type 'ARWorldTrackingSessionConfiguration'
...for this code:
let session = ARSession()
var sessionConfig: ARSessionConfiguration = ARWorldTrackingSessionConfiguration()
I have imported ARKit and am using the ARSCNViewDelegate in my ViewController.
When opening the project from the beta version of Xcode, it does not show the errors and I can again run the app on my phone.
Any idea how I can fix this?
ARWorldTrackingSessionConfiguration has been deprecated and renamed to ARWorldTrackingConfiguration: See here
Also, ARSessionConfiguration has been deprecated and renamed to ARConfiguration, which is now an abstract base class.
Use AROrientationTrackingConfiguration when you don't want world tracking, instead of using a generic ARConfiguration. Thus:
let configuration = AROrientationTrackingConfiguration()
You can also check if world tracking is supported on a device:
if ARWorldTrackingConfiguration.isSupported {
configuration = ARWorldTrackingConfiguration()
}
else {
configuration = AROrientationTrackingConfiguration()
}
In Xcode 9 GM, looks like ARWorldTrackingSessionConfiguration has been renamed to ARWorldTrackingConfiguration:
https://developer.apple.com/documentation/arkit/arworldtrackingconfiguration
Reference to this change:
https://github.com/markdaws/arkit-by-example/issues/7
ARSessionConfiguration has been renamed to ARConfiguration:
https://developer.apple.com/documentation/arkit/arconfiguration
I'm having problems with NSAttributedStringKey.attachment versus NSAttachmentAttributeName. Here's the relevant code:
var key: Any?
if #available(iOS 11, *) {
key = NSAttributedStringKey.attachment
}
else {
key = NSAttachmentAttributeName
}
One of two things are happening. In the actual place where I'm trying to use this code (a Cococapod of my own design, with a deployment target of iOS 8 and now building with Xcode 9), I get an error:
Type 'NSAttributedStringKey' (aka 'NSString') has no member 'attachment'
Or, if I just make a new example project and set the deployment target at iOS 8, I get:
'NSAttachmentAttributeName' has been renamed to 'NSAttributedStringKey.attachment'
This is not the behavior I'd expect with #available. Thoughts?
This String vs struct difference is between Swift 3 (uses Strings such as NSAttachmentAttributeName) and Swift 4 (uses struct static attributes such as NSAttributedStringKey.attachment), not between iOS <11 and iOS >=11. For instance, you can use NSAttributedStringKey.attachment and similar in any supporting version of iOS (e.g. .attachment is available since iOS 7) within a Swift 4 project. #available doesn't apply because it's a Swift language version difference rather than an OS version difference.
Ensure your pod is set to the correct Swift version and it should then work as expected. You can tell CocoaPods that by adding a .swift-version file at the top of your project:
$ echo 4.0 >.swift-version
This magical version file is mentioned in passing in a CocoaPods blog post from last year: http://blog.cocoapods.org/CocoaPods-1.1.0/