How to Use Obsoleted Syntax of Swift 3 in Swift 4 - ios

To record video, while setting video codec as below:
sessionOutput.outputSettings = [AVVideoCodecKey: AVVideoCodecTypeJPEG]
XCode says 'AVVideoCodecTypeJPEG' has been renamed to 'AVVideoCodecType.jpeg' and 'AVVideoCodecTypeJPEG' was obsoleted in Swift 3 and it suggests Replace 'AVVideoCodecTypeJPEG' with 'AVVideoCodecType.jpeg'
After doing that, XCode says 'jpeg' is only available on iOS 11.0 or newer.
The problem is I have to use iOS 10 and want to use Swift 4.
Is there any solution to use features like this in Swift 4 with iOS 10?

I think the right way to solve such issue is to use the new AVVideoCodecType.jpeg and the deprecated one AVVideoCodecJPEG, doing so:
if #available(iOS 11.0, *) {
sessionOutput.outputSettings = [AVVideoCodecKey: AVVideoCodecType.jpeg]
} else {
sessionOutput.outputSettings = [AVVideoCodecKey : AVVideoCodecJPEG]
}

Related

iOS 11 Xcode 9: CoreML linker command failed with exit code 1 (use -v to see invocation)

I'm trying to capture photo using AVFoundation
Here is my code:
#objc func didTapCameraView() {
self.cameraView.isUserInteractionEnabled = false
let settings = AVCapturePhotoSettings()
let previewPixelType = settings.availablePreviewPhotoPixelFormatTypes.first!
let previewFormat = [kCVPixelBufferPixelFormatTypeKey as String: previewPixelType,
kCVPixelBufferWidthKey as String: 160,
kCVPixelBufferHeightKey as String: 160]
settings.previewPhotoFormat = previewFormat
if flashControlState == .off {
settings.flashMode = .off
} else {
settings.flashMode = .on
}
cameraOutput.capturePhoto(with: settings, delegate: self)
}
but I'm getting same error every time.
If I comment the code inside methods then it builds fine.
Let me know what I missed.
Update:
using iPhone 6 iOS11
Build architectures
Snapshot while using physical device
I found the explanation from Apple develop forum, Check this link
This bug will be fixed later(unfortunately it still exists in ode 9 GM Version).
Quote from Apple forum, we can use this workaround:
As a workaround you can use the SwiftPrivate versions of these API by prepending each API with double underscore (__). For example, change AVCaptureDevice.Format.supportedColorSpaces to AVCaptureDevice.Format.__supportedColorSpaces.
I tested it and it works, and they said such workaround is considered legitimate and is not considered SPI use.

How to check iOS device chip is A9 or A10?

Apple announced HEVC encode support for A10 devices running iOS 11, and HEVC decode support for A9 devices running iOS 11.
Before create those hardware codec, how to check if current device is support the feature?
What is the chip? A8, A9, or A10 without hard code the model.
Don't check for the specific SOC, check for the feature you actually want. You'll need the VideoToolbox call VTIsHardwareDecodeSupported, passing the kCMVideoCodeType_HEVC key:
VTIsHardwareDecodeSupported(kCMVideoCodeType_HEVC)
However, iOS has software decoder fallbacks for HEVC if you need them.
Edit: Ah, sorry - I misread and thought you were talking about decoding. For encoding, you may be able to get what you want with VTCopySupportedPropertyDictionaryForEncoder, using the kCMVideoCodeType_HEVC and specifying the parameters you want to encode. I don't know if iOS has a fallback software encoder for HEVC, so this may give false positives.
For encoder, I could not find an official way but this seems to work in my tests:
#import <AVFoundation/AVFoundation.h>
#import <VideoToolbox/VideoToolbox.h>
- (BOOL)videoCodecTypeHevcIsSuppored {
if (#available(iOS 11, *)) {
CFMutableDictionaryRef encoderSpecification = CFDictionaryCreateMutable( NULL,0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
CFDictionarySetValue(encoderSpecification, kVTCompressionPropertyKey_ProfileLevel, kVTProfileLevel_HEVC_Main_AutoLevel);
CFDictionarySetValue(encoderSpecification, kVTCompressionPropertyKey_RealTime, kCFBooleanTrue);
OSStatus status = VTCopySupportedPropertyDictionaryForEncoder(3840, 2160, kCMVideoCodecType_HEVC, encoderSpecification, nil, nil);
if (status == kVTCouldNotFindVideoEncoderErr) {
return NO;
}
return YES;
}
return NO;
}
kanso's great answer in Swift 4.
Assumes that we target only iOS11 or higher and adds an extra check:
import AVFoundation
import VideoToolbox
#available (iOS 11, *)
func isHEVCHardwareEncodingSupported() -> Bool {
let encoderSpecDict : [String : Any] =
[kVTCompressionPropertyKey_ProfileLevel as String : kVTProfileLevel_HEVC_Main_AutoLevel,
kVTCompressionPropertyKey_RealTime as String : true]
let status = VTCopySupportedPropertyDictionaryForEncoder(3840, 2160,
kCMVideoCodecType_HEVC,
encoderSpecDict as CFDictionary,
nil, nil)
if status == kVTCouldNotFindVideoEncoderErr {
return false
}
if status != noErr {
return false
}
return true
}

Swift 4 backwards compatibility

I have the following code in my project in Xcode 8.3.3 (Swift 3.1):
let font = CGFont(provider!)
CTFontManagerRegisterGraphicsFont(font, &error)
But in Xcode 9 Beta (Swift 4), I get the following error:
Value of optional type 'CGFont?' not unwrapped; did you mean to use
'!' or '?'?
The error is because the initializer for CGFont that takes a CGDataProvider now returns an optional.
But when I apply the fix of:
let font = CGFont(provider)
CTFontManagerRegisterGraphicsFont(font!, &error)
The code no longer compiles in Xcode 8.3.3 with Swift 3.1 since font is not an optional and thus doesn't play nicely with the !.
Is there a way to make this work in both versions of Xcode? Is Swift 4 supposed to be backwards compatible (compile with Swift 3 compiler)?
This is a breaking change in Core Graphics not in Swift itself. API has changed, the initializer is now failable.
Use conditional compilation to make your code compile with both 3.1 and 4.0 compiler:
#if swift(>=4.0)
let font = CGFont(provider!)
#else
let font = CGFont(provider)!
#endif
CTFontManagerRegisterGraphicsFont(font, &error)
I ended up using the following method which allowed for backwards compatibility without conditional compilation (idea taken from this blog post):
func optionalize<T>(_ x: T?) -> T? {
return x
}
This way in both Xcode 8 and Xcode 9 I could use:
guard let font = optionalize(CGFont(provider)) else {
return
}
CTFontManagerRegisterGraphicsFont(font, &error)

`save(to:for:completionHandler:)` of `UIDocument` crashes

I get crash on every 32 bit device / simulator running iOS 9 on save(to:for:completionHandler:).
Xcode 8.2. Base SDK is 10.2. Target is 9.0. Standard architectures. Swift 3. For both develop and release builds. Sample project.
Could not find if it's known, neither any related issues. Can you recommend any workaround? Should I require 64 bit architecture?
The work around is to return NS object, Apple engineer recommended NSMutableData specifically:
override func contents(forType typeName: String) throws -> Any {
guard let data = text.data(using: .utf8) else { ... }
if #available(iOS 10, *) {
return data
} else {
return NSMutableData(data: data)
}
}

How do I conditionally use a class in Swift that may not be present in the targeted version of the OS?

This answer addresses how to use a Swift class from a framework that may not be linked to an app, but is present in the target OS. Relatedly, but a bit different, I'd like to know how to conditionally use a Swift class that may not be included in the target OS. For example, say I have an app, written in Swift, that targets iOS 7. I want to use WKWebView if I'm on iOS 8, and UIWebView if I'm on iOS 7. This doesn't work:
if NSClassFromString("WKWebView") == nil {
var wv = WKWebView()
} else {
var wv = UIWebView()
}
Because my app targets iOS 7, I get a compile-time error:
Undefined symbols for architecture i386:
"_OBJC_CLASS_$_WKWebView", referenced from:
__TMaCSo9WKWebView in MyWebKitViewController.o
I tried just assigning the WKWebView to an AnyObject property, but then I can’t call methods on it. So how can I get Swift to just check for these things at runtime?
I'm new to Swift so I don't know if this is Swift or not, but I found this on a different question. https://stackoverflow.com/a/25874127/1012144
http://floatlearning.com/2014/12/uiwebview-wkwebview-and-tying-them-together-using-swift/
if (NSClassFromString("WKWebView") != nil) {
// Use WebKit
} else {
// Fallback on UIWebView
}
The code in the OP is nearly correct; it just needed to use != instead of ==:
if NSClassFromString("WKWebView") != nil {
var wv = WKWebView()
} else {
var wv = UIWebView()
}
To make it work, be sure to set iOS Deployment Target to 7.0. Otherwise you get the undefined symbol errors.

Resources