Alamofire deprecated code - swift

Scenario: Networking app based on Alamofire.
I'm encountering deprecated-code notices in my latest project build. I traced it to the following statement within Alamofire. I don't see any mention of the alternatives.
#available(*, deprecated=3.4.0)
public static func errorWithCode(code: Int, failureReason: String) -> NSError {
let userInfo = [NSLocalizedFailureReasonErrorKey: failureReason]
return NSError(domain: Domain, code: code, userInfo: userInfo)
}
What's the replacement?
And... how do I determine other replacements of deprecated codes?

You now need to build your own errors with your own custom domain. It was unwise of us to originally expose those convenience methods because it led users to create their own errors using the Alamofire error domain which is not correct.
All of this is going to be easier in Swift 3 with the new AFError type being introduced.

Related

Swift Error handling best practices

Im used to typical try catch blocks to handle exceptions of any function or block of code like objective C.
However, after making leap of faith to Swift and reading about Swift’s error handling; it’s not much what I expected. You must handle your exceptions by throwing errors and guard and checking if else everything.
I need general Swift error handling tips and best practices, and especially for the following cases:
Im using Alamofire for calling services, which has closure, and calling it through another function with closure too. AFAIK I can’t throw error inside async code, so what is best practice for such case? will try to update with code sample
Is it favourable to have every function in the app throw errors? Just in case ? Like checking every single value or result.
Can I have a Singleton Error handling module?
Thanks in advance
You must handle your exceptions by throwing errors and guard and checking if else everything.
This is an assumption that doesn't have to be true. If your code is structured correctly, you shouldn't have to check everything with if lets and throws.
I need general Swift error handling tips and best practices ...
Before you look at anything else, read the following pages in order. They should give you a good background on best practices.
Error Protocol Apple Developer Documentation
Error Handling - Apple's Swift Programming Language Guide
Magical Error Handling in Swift - Ray Wenderlich
Im using Alamofire for calling services, which has closure, and calling it through another function with closure too. AFAIK I can’t throw error inside async code, so what is best practice for such case?
You can. A good practice is to pass a closure as a parameter to your service-calling function, then call the closure when the asynchronous operation is complete, like so:
functionThatCallsAService(completion: #escaping (Data?, NetworkingErrors?) -> ()) {
session.dataTask(with: request) { data, response, error in
guard error == nil else {
completion(nil, NetworkingErrors.returnedError(error!))
return
}
completion(data, nil)
}.resume()
}
enum NetworkingErrors: Error {
case errorParsingJSON
case noInternetConnection
case dataReturnedNil
case returnedError(Error)
case invalidStatusCode(Int)
case customError(String)
}
Is it favourable to have every function in the app throw errors? Just in case? Like checking every single value or result.
If you know for sure that a function or value won't be nil/cause a runtime error/throw an error, then don't check for it! But generally, according to the web pages above, you should check for nil and/or errors from calling a web service, interacting with the file system, creating a complex object, etc.
Can I have a Singleton Error handling module?
You technically can, but I don't see any reason to do so besides logging.
enum CheckValidAge : Error{
case overrage
case underage
}
func checkValidAgeForGovernmentJob(age:Int)throws -> Bool{
if age < 18{
throw CheckValidAge.underage
}else if age > 25{
throw CheckValidAge.overrage
}else{
return true
}
}
do {
try checkValidAgeForGovernmentJob(age: 17)
print("You are valid for government job ")
}catch CheckValidAge.underage{
print("You are underage for government job ")
}catch CheckValidAge.overrage{
print("You are overrage for government job ")
}
try checkValidAgeForGovernmentJob(age: 17) OutPut : You are underage for government job
try checkValidAgeForGovernmentJob(age: 26) OutPut : You are overrage for government job
try checkValidAgeForGovernmentJob(age: 18) OutPut : You are valid for government job

Mocking a static class method in a swift unit test in a swifty way?

I'm a seasoned Objective-c programmer but I can't say the same for Swift, I'm having a hard time unit testing a class in swift without using frameworks like OCMock.
The Problem: I'm integrating Firebase into a mixed Objective-C/Swift project, and I need to configure it based on the build configuration of the app.
I've written a Swift class for that (that will be used by the obj-c app delegate), however since the firebase framework is configured trough a static class method, precisely FIRApp.configure(with: FIROptions), I need to mock this method somehow in order to unit test it.
My code, without any handle for Dependency Injection, looks like that:
#objc class FirebaseConfigurator: NSObject{
func configureFirebase(){
let config = configManager.buildConfiguration
var optionsPlistBaseName = getPlistName()
let optionsFile = Bundle.main.path(forResource: optionsPlistBaseName, ofType: "plist")
guard let opts = FIROptions(contentsOfFile: optionsFile) else{
assert(false, "fatal: unable to load \(optionsFile)")
return
}
FIRApp.configure(with: opts)
}
func getPlistName() -> String{
// retrieves correct plist name and returns it
}
}
I've done some research but so far I didn't find nothing that fits my solution, however I was thinking of one of the following:
I could pass a function that defaults to FIRApp.configure(with:) however I should do this from objective-c and the function also accepts a parameter, I was struggling with the syntax
I could use a wrapper around FIRApp, but I wanted to avoid it unless the only viable clean solution.
I could keep on playing with protocols and do dependency inversion, however being the method static I was struggling with the syntax again, I can't find an easy way to do DI with a mock class with a static method.
As a reference (both personal and for who might need it) these are some of the resources I found useful and upon which I will keep on digging:
Dealing with static cling in Swift
This Question
This article about generic unit testing
In the meanwhile, every help would be really appreciated.
As a sidenote, there are many ways I can solve this problem without struggling with mocking a static class method, but my aim here is to find out a way of mocking it in order to have a better understanding of the best practices when testing more complex situations.
You can indeed do any of those.
Closure Argument
You can have your configureFirebase function take an "applier" closure that defaults to what you originally used:
func configureFirebase(
using apply: (_ options: FIROptions) -> Void
= { opts in FIRApp.configure(opts) }
) {
// building |opts| as before
// Now replace this: FIRApp.configure(with: opts)
apply(opts)
}
Protocols
You need a Configurable protocol, and then to conform FIRApp to it for the default case:
protocol Configurable {
static func configure(with options: FIROptions)
}
extension FIRApp: Configurable {}
class FirebaseConfigurator {
var configurable: Configurable
init(configurable: Configurable = FIRApp) {
self.configurable = configurable
}
func configureFirebase() {
//load |opts|…
configurable.configure(with: opts)
}
}
If you're just going to use this in one method, though, it's merely transient state, and it should probably be a function argument rather than stored property.
(If it's unclear whether it's persistent or transient state because the whole point of the class is to call a single function, perhaps you don't even need a class, just a function.)

unable to access public enum from within a framework

I have been working on developing a framework and I have decided to create custom enums that extend the Error protocol to report to the host application when a domain specific error is encountered.
i.e.
public enum MyCustomError: Error {
case customCase(message: String)
}
from the host application I have a response call back that is another enum with associated value
i.e.
public enum MyCustomResponse {
case success
case error(Error)
}
form within the host application I try to access the error by doing the following
i.e.
let responseHandler: (MyCustomResponse) -> Void = { response in
switch response {
case .error(let error):
if case let MyCustomModule.MyCustomError.customCase(theErrorMessage) = error {
print(theErrorMessage)
}
}
}
what I am getting is a message from the compiler telling me that MyCustomModule has no member named MyCustomError. If a loose the MyCustomModule. then the compiler complains Use of unresolved identifier 'MyCustomError'. I am importing MyCustomModule, and the access level of the MyCustomError is public, any ideas on how to solve this would be really appreciated.
Thanks
Note: I am developing my framework via cocoapods version 1.1.1 and using Xcode 8.2.1, swift version 3.0.2, supporting iOS version 8.0 and above.
Generated interface
import Foundation
public enum MyCustomError : Error {
case customCase(message: String)
}
After a long while trying out every little thing I could think of, even sandboxing the problem in a new repo (check github.com/anuragajwani/framework_pod_enums_test) without the ability to reproduce it I ended re-cloning the repository with the issue in question and reapplied all the changes and it worked no problem. Pitty I could not find the underlying problem, but by comparing each configuration setting in comparison with the sandboxed project and everything matching exactly I gave up. I have hunch that it had to with the compiler which given how flaky it is it would be no surprise.
I had the exact same issue. In my case I just set the "Build Active Architecture Only" to "No" in the Build Settings and the issue was gone.

How to add values to existing enum

I use the Alamofire swift library to do some networking in my App.
I'm currently building my own ResponseSerializer.
According to Alamofire's docs you throw errors in the serialization process like this
let failureReason = "Data could not be serialized. Input data was nil."
let error = Error.errorWithCode(.DataSerializationFailed, failureReason: failureReason)
return .Failure(data, error)
So my thought was to use this method to throw some more errors not related to Alamofire that can appear in my serialization. For example if there is a problem on the server-side, the response includes an error description as a string.
I want to add some custom error codes like .ServerErrorInJson that I can use in the errorWithCode(Alamofire.Error.Code, String) -> NSError method.
Is there a way I can add those cases to the enum Alamofire.Error.Code?

Can/How Should I replace my KVO stuff with RC3?

I'm trying to port an objc app which uses Facebook's KVOController, to Swift. I've been encouraged to look at RC3 as an alternate and more Swiftish approach. I've read some blogs and I'm encouraged to give this a try. But much of the docs and blogs seem to concentrate on sockets and timers as examples. So I have two simple questions right now:
1) Given an objc fragment like:
[self.KVOController observe: self.site keyPath: #"programs" options: NSKeyValueObservingOptionInitial block:^(id observer, id object, NSDictionary *change) {
[self.tableView reloadData];
}];
What is the simple way to rewrite this with RC3 APIs? And what is the RC3 equivalent for self.KVOController unobserve: self.site that happens when that view unloads?
2) It's recommended that I use Carthage to grab the RC3 code. Can I intermix a Cartfile safely with a project that is using cocoa pods already for Alamofire and SwiftyJSON?
Disclaimer :)
I'm also new to the whole ReactiveCocoa concept and especially to RAC 3. I'm playing around with the new framework to learn, so my solution may not be the intended usage of the API. I'd be happy to receive feedback from others and learn the right way.
Here's what I could come up with for your first question:
You can define the property you'd want to observe as a MutableProperty. Below is the most basic example with a String property. Assume you have a view model, it has a String property and you want to observe this in your view controller object.
ViewModel.swift
class ViewModel {
var testProp = MutableProperty<String>("")
}
ViewController.swift
class ViewController: UIViewController {
private let viewModel = ViewModel()
override func viewDidLoad() {
super.viewDidLoad()
let testPropObserver = viewModel.testProp.producer
testPropObserver.start(next: {value in
println("new value \(value)")
})
viewModel.testProp.value = "you should see this in your log"
}
}
For the first question I can only guide you in the right direction. Take a look at the change log to 3.0 describing the shift away from RACObserve() to PropertyTypes. It's a little more explicit and it offers type safety. Here is the source, which I think is your best bet for figuring out how to implement it. You could also take a look at their test cases to see if they have built any tests for the PropertyType protocol and mimic how they've got it set up.
And yes, you'll have no trouble mixing Carthage and CocoaPods in one project, as Carthage is designed to be minimally intrusive. As long as you follow the instructions on their website you should be fine.