Skip to content

Commit

Permalink
Merge pull request #76 from inaka/swift3.0
Browse files Browse the repository at this point in the history
Swift 3.0 support
  • Loading branch information
Pablo Villar authored Sep 23, 2016
2 parents b1887b4 + 8e67e96 commit 91e8138
Show file tree
Hide file tree
Showing 54 changed files with 693 additions and 615 deletions.
1 change: 1 addition & 0 deletions .swift-version
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
3.0
1 change: 1 addition & 0 deletions .swiftlint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@ disabled_rules:
- todo
- trailing_whitespace
- statement_position
- type_name
- valid_docs
- variable_name_min_length
14 changes: 5 additions & 9 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
osx_image: xcode7.3
osx_image: xcode8
language: objective-c

before_install:
# - brew update || brew update
# - brew outdated xctool || brew upgrade xctool
- git clone https://github.com/facebook/xctool.git

script:
- xctool clean build -project Jayme.xcodeproj -scheme Jayme -sdk iphonesimulator
- xcodebuild -scheme Jayme -project Jayme.xcodeproj -sdk iphonesimulator9.3 -destination 'platform=iOS Simulator,name=iPhone 6s,OS=9.3' test
- "xcodebuild -sdk iphonesimulator clean"
- "xcodebuild -scheme Jayme -project Jayme.xcodeproj -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 7,OS=10.0' build-for-testing"
- "xcodebuild -scheme Jayme -project Jayme.xcodeproj -sdk iphonesimulator -destination 'platform=iOS Simulator,name=iPhone 7,OS=10.0' test-without-building"

after_success:
- bash <(curl -s https://codecov.io/bash)
- bash <(curl -s https://codecov.io/bash)
Binary file added Assets/V3/architecture-diagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Assets/V3/customization-diagram.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Assets/V3/testability-diagram-1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Assets/V3/testability-diagram-2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. `Jayme` a

---

### 3.x Releases

- `3.0.x` releases - [3.0.0](#300)

### 2.x Releases

- `2.0.x` Releases - [2.0.0](#200) | [2.0.1](#201)
Expand All @@ -14,6 +18,10 @@ All notable changes to this project will be documented in this file. `Jayme` a

---

## 3.0.0

- All of the changes involved in this release are due to [Swift 3 breaking changes](https://apple.github.io/swift-evolution/) and its [new APIs design](https://swift.org/documentation/api-design-guidelines/).

## 2.0.1

- `create(...)` function in `CRUDRepository` no longer attaches the `:id` parameter in its `POST` URL. (Issue [#63](https://github.com/inaka/Jayme/issues/63))
Expand Down
34 changes: 34 additions & 0 deletions Documentation/Jayme 3.0 Migration Guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Jayme 3.0 Migration Guide

**Jayme 3.0** is the latest major release of Jayme. As a major release, following Semantic Versioning conventions, 3.0 introduces several API-breaking changes that one should be aware of.

This guide is provided in order to ease the transition of existing applications using Jayme 2.x to the latest APIs, as well as explain the design and structure of new and changed functionality.

---

**All of these changes were applied in order to follow the [Swift API Design Guidelines](https://swift.org/documentation/api-design-guidelines/) that came up with [Swift 3](https://apple.github.io/swift-evolution/).**

---

### Automatically Suggested Changes

There are some compiler migration mechanisms that have been implemented in Jayme 2.0 by leveraging the `@unavailable` attribute in a `Compatibility.swift` file.

***For these changes you only have to follow the compiler suggestions and they should be applied automatically.***

For instance:

* `NSURLSessionBackend` has been renamed to `URLSessionBackend`.
* The compiler will automatically suggest the replacement of `NSURLSessionBackend` to `URLSessionBackend`.

---

### Manual Changes

However, there are some other changes that would have required overwhelming (if ever possible) mechanisms to be implemented in order to keep automatic suggestions from the compiler. In consequence, we decided not to implement them.

⚠️ ***Therefore, it's up to you to perform these changes manually.***

---

For further documentation regarding changes, check out the **[Change Log](../Changelog.md)**.
2 changes: 1 addition & 1 deletion Example/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {

var window: UIWindow?

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
return true
}

Expand Down
2 changes: 1 addition & 1 deletion Example/Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@

import Foundation

extension String: CustomStringConvertible {
extension String {
public var description: String {
return self
}
Expand Down
36 changes: 18 additions & 18 deletions Example/Post.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,34 +22,34 @@ import Foundation

struct Post: Identifiable {
let id: PostIdentifier
let authorID: String
let authorId: String
let title: String
let abstract: String
let date: NSDate
let date: Date
}

extension Post: DictionaryInitializable, DictionaryRepresentable {

init(dictionary: [String: AnyObject]) throws {
guard let
id = dictionary["id"] as? String,
authorID = dictionary["author_id"] as? String,
title = dictionary["title"] as? String,
abstract = dictionary["abstract"] as? String,
dateString = dictionary["date"] as? String,
date = dateString.toDate()
else { throw JaymeError.ParsingError }
self.id = .Server(id)
self.authorID = authorID
init(dictionary: [String: Any]) throws {
guard
let id = dictionary["id"] as? String,
let authorId = dictionary["author_id"] as? String,
let title = dictionary["title"] as? String,
let abstract = dictionary["abstract"] as? String,
let dateString = dictionary["date"] as? String,
let date = dateString.toDate()
else { throw JaymeError.parsingError }
self.id = .server(id)
self.authorId = authorId
self.title = title
self.abstract = abstract
self.date = date
}

var dictionaryValue: [String: AnyObject] {
var dictionaryValue: [String: Any] {
return [
"id": "\(self.id)",
"author_id": self.authorID,
"author_id": self.authorId,
"title": self.title,
"abstract": self.abstract,
"date": self.date
Expand All @@ -60,10 +60,10 @@ extension Post: DictionaryInitializable, DictionaryRepresentable {

private extension String {

func toDate() -> NSDate? {
let formatter = NSDateFormatter()
func toDate() -> Date? {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
return formatter.dateFromString(self)
return formatter.date(from: self)
}

}
10 changes: 5 additions & 5 deletions Example/PostIdentifier.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,18 +20,18 @@

import Foundation

/// Enumeration for identifying a Post via either a local ID or a server-defined ID, and being able to distinguish which scenario it corresponds to.
/// Enumeration for identifying a Post via either a local identifier or a server-defined identifier, and being able to distinguish which scenario it corresponds to.
enum PostIdentifier {
case Local(String)
case Server(String)
case local(String)
case server(String)
}

extension PostIdentifier: CustomStringConvertible {
var description: String {
switch self {
case .Local(let id):
case .local(let id):
return "local_\(id)"
case .Server(let id):
case .server(let id):
return id
}
}
Expand Down
6 changes: 3 additions & 3 deletions Example/PostRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@ import Foundation
class PostRepository: CRUDRepository {

typealias EntityType = Post
let backend = NSURLSessionBackend()
let backend = URLSessionBackend()
let name = "posts"

func findPostsForUser(user: User) -> Future<[Post], JaymeError> {
func findPosts(for user: User) -> Future<[Post], JaymeError> {
return self.findAll().map {
$0.filter { $0.authorID == user.id }
$0.filter { $0.authorId == user.id }
}
}

Expand Down
8 changes: 4 additions & 4 deletions Example/PostTableViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,12 @@ class PostTableViewCell: UITableViewCell {

}

private extension NSDate {
private extension Date {

func formatted() -> String {
let formatter = NSDateFormatter()
formatter.dateStyle = .MediumStyle
return formatter.stringFromDate(self)
let formatter = DateFormatter()
formatter.dateStyle = .medium
return formatter.string(from: self)
}

}
10 changes: 5 additions & 5 deletions Example/User.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,18 @@ struct User: Identifiable {

extension User: DictionaryInitializable, DictionaryRepresentable {

init(dictionary: [String: AnyObject]) throws {
init(dictionary: [String: Any]) throws {
guard let
id = dictionary["id"] as? String,
name = dictionary["name"] as? String,
email = dictionary["email"] as? String
else { throw JaymeError.ParsingError }
let name = dictionary["name"] as? String,
let email = dictionary["email"] as? String
else { throw JaymeError.parsingError }
self.id = id
self.name = name
self.email = email
}

var dictionaryValue: [String: AnyObject] {
var dictionaryValue: [String: Any] {
return [
"id": self.id,
"name": self.name,
Expand Down
36 changes: 18 additions & 18 deletions Example/UserDetailViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,33 +33,33 @@ class UserDetailViewController: UIViewController {

// MARK: - Private

private var posts = [Post]()
fileprivate var posts = [Post]()

private func loadPosts() {
let future = PostRepository().findPostsForUser(self.user)
fileprivate func loadPosts() {
let future = PostRepository().findPosts(for: self.user)
future.start { result in
switch result {
case .Success(let posts):
case .success(let posts):
self.posts = posts
self.tableView.reloadData()
case .Failure(let error):
self.showAlertControllerForError(error)
case .failure(let error):
self.showAlertController(for: error)
}
}
}

private func showAlertControllerForError(error: JaymeError) {
let message = self.descriptionForError(error)
let alert = UIAlertController(title: "Error", message: message, preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
fileprivate func showAlertController(for error: JaymeError) {
let message = self.description(for: error)
let alert = UIAlertController(title: "Error", message: message, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
self.present(alert, animated: true, completion: nil)
}

private func descriptionForError(error: JaymeError) -> String {
fileprivate func description(for error: JaymeError) -> String {
switch error {
case .ServerError(let code):
case .serverError(let code):
return "Server Error (code: \(code))"
case .Other(let nsError):
case .other(let nsError):
return nsError.localizedDescription
default:
return "Unexpected error"
Expand All @@ -70,13 +70,13 @@ class UserDetailViewController: UIViewController {

extension UserDetailViewController: UITableViewDataSource, UITableViewDelegate {

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return self.posts.count
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier(PostTableViewCell.Identifier) as! PostTableViewCell
cell.post = self.posts[indexPath.row]
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: PostTableViewCell.Identifier) as! PostTableViewCell
cell.post = self.posts[(indexPath as NSIndexPath).row]
return cell
}

Expand Down
10 changes: 5 additions & 5 deletions Example/UserRepository.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,18 @@ import Foundation
class UserRepository: CRUDRepository {

typealias EntityType = User
let backend: NSURLSessionBackend
let backend: URLSessionBackend
let name = "users"

init(backend: NSURLSessionBackend = NSURLSessionBackend()) {
init(backend: URLSessionBackend = URLSessionBackend()) {
self.backend = backend
}

func findActiveUsers() -> Future<[User], JaymeError> {
let path = "\(self.name)/active"
return self.backend.futureForPath(path, method: .GET, parameters: nil)
.andThen { DataParser().dictionariesFromData($0.0) }
.andThen { EntityParser().entitiesFromDictionaries($0) }
return self.backend.future(path: path, method: .GET, parameters: nil)
.andThen { DataParser().dictionaries(from: $0.0) }
.andThen { EntityParser().entities(from: $0) }
}

}
Loading

0 comments on commit 91e8138

Please sign in to comment.