- 
                Notifications
    You must be signed in to change notification settings 
- Fork 1
Add swiftlint #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
| "${BUILT_PRODUCTS_DIR}/RxSwift/RxSwift.framework", | ||
| "${BUILT_PRODUCTS_DIR}/RxBlocking/RxBlocking.framework", | ||
| "${BUILT_PRODUCTS_DIR}/RxTest/RxTest.framework", | ||
| "${BUILT_PRODUCTS_DIR}/SwiftHamcrest/Hamcrest.framework", | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's conventional to commit the result of pod install even if you don't commit the Pods folder
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
| func applicationWillResignActive(_ application: UIApplication) { | ||
| // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. | ||
| // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. | ||
| } | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Line length and general boilercrap cleanup
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 - on the android side I knew the analysis too.ls to enforce this. Not the case on iOS swift...yet.
| public enum AppError : Error { | ||
| case RuntimeError(String) | ||
| public enum AppError: Error { | ||
| case runtimeError(String) | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Swift naming guidelines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
| func autoconnect() -> Observable<E> { | ||
| return Observable.create { observer in | ||
| return self.do(onSubscribe: { | ||
| self.do(onSubscribe: { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Prefer implicit return of explicit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I bet Aziz Ansar would have loved explicit LOL!
I had no idea swift did this. However as a learning tool I'm probably going to leave it. Less WTF moments.
| } | ||
|  | ||
| extension Observable where Element: OptionalType { | ||
| func ignoreNil() -> Observable<Element.Wrapped> { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added this for easier strong type mapping to subclasses during an observable flow. Optional map to class -> ignore nils.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice...not 100% sure what it does but the less manual casting the better
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI, RxSwiftExt (a collection of RxSwift extensions from the RxSwift contributors) has an option similar to this already called .unwrap()
|  | ||
| return Observable.just(NowPlayingInfoImpl.init(movieInfoList: movieInfoList, | ||
| pageNumber: serviceResonse.page!, | ||
| totalPageNumber: serviceResonse.total_pages!)) | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Swift naming guidelines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
| case FAILURE | ||
| case inFlight | ||
| case success | ||
| case failure | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Swift naming guidelines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm trying to find where they talk about ENUMS. From ADA To C to Java...always been caps. Easier for readability that the code speaks about enums vs other types.
Just trusting and verifying :-)
| var popularity: Double! | ||
| var voteCount: Int! | ||
| var video: Bool! | ||
| var voteAverage: Double! | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Force unwraps here rather than scattered throughout the code. The real solution to this is to convert to Codable but had no time
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might try that on another PR. For now this is good for educational tool
| vote_count <- map["vote_count"] | ||
| voteCount <- map["vote_count"] | ||
| video <- map["video"] | ||
| vote_average <- map["vote_average"] | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Swift naming guidelines
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😲 well look at that.
| Add passed in list to table view with animation for each entry to add | ||
| Parameters: listToAdd - list to add | ||
| */ | ||
| func addAll(listToAdd: Array<MovieViewInfo>!) -> Void { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-> Void is implicit. This (and a lot of spacing and implicit return stuff) was fixed with 1 pass of swiftlint autocorrect 💯
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In the beginning I didn't have the void on my functions, then started putting it in. No idea why..
👍
| if (movieViewInfo is MovieViewInfoImpl) { | ||
| if movieViewInfo is MovieViewInfoImpl { | ||
| // swiftlint:disable:next force_cast | ||
| let movieCell: MovieCell = tableView.dequeueReusableCell(withIdentifier: "MovieCellIdentifier", for: indexPath) as! MovieCell | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I personally don't mind force casting in this case. A crash here is basically the only sane thing to do as you won't know how the app will behave with a cell of the wrong type
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
| nowPlayingViewModel?.processUiEvent(uiEvent: scrollEvent) | ||
| } else { | ||
| if (uiModel.adapterCommandType == AdapterCommandType.ADD_DATA) { | ||
| if uiModel.adapterCommandType == .addData { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Didn't clean this up everywhere but I generally prefer removing the prefix where it's implicit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so if I start typing "." on Xcode it'll expand all the enum types? I guess I'll find out...
👍
| assertThat(movieInfo.getPictureUrl(), matchesPattern(IMAGE_PATH + "/tnmL0g604PDRJwGJ5fsUSYKFo9.jpg", options: .caseInsensitive)) | ||
| assertThat(movieInfo.getRating(), equalTo(7.2)) | ||
| // TODO: This fails outside of US timezones | ||
| assertThat(movieInfo.getReleaseDate().description, equalTo("2017-03-15 04:00:00 +0000")) | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe you can set an override timezone to NSCalendar or soemthing but didn't have a chance to do it
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍 leaving in TODO
|  | ||
| let fileLogger: DDFileLogger = DDFileLogger() // File Logger | ||
| fileLogger.rollingFrequency = TimeInterval(60*60*24) // 24 hours | ||
| fileLogger.rollingFrequency = TimeInterval(60 * 60 * 24) // 24 hours | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
| //App Singleton | ||
| // | ||
| container.register(.singleton) { ServiceApiImpl(baseUrl: "https://api.themoviedb.org/3/movie") as ServiceApi} | ||
| container.register(.singleton) { ServiceApiImpl(baseUrl: "https://api.themoviedb.org/3/movie") as ServiceApi } | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
| // VC Singleton | ||
| // | ||
| container.register {serviceController in NowPlayingViewModel(serviceController: serviceController) as NowPlayingViewModel} | ||
| container.register { serviceController in NowPlayingViewModel(serviceController: serviceController) as NowPlayingViewModel } | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|  | ||
| /// Init an error for a local client-side error. Usually this would be the NSError reported by NSURLSession, e.g. network connection not available. | ||
| /// Init an error for a local client-side error. Usually this would be the NSError reported by NSURLSession, | ||
| /// e.g. network connection not available. | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
|  | ||
| func indexOf(element: Element) -> Int { | ||
| guard let index = index(where: { $0 as AnyObject === element as AnyObject}) else { return -1 } | ||
| guard let index = index(where: { $0 as AnyObject === element as AnyObject }) else { return -1 } | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
| .flatMap{ (serviceResponse: ServiceResponse) -> Observable<NowPlayingInfo> in | ||
| return TranslateNowPlayingSubscriptionFunc.init(imageUrlPath: self.imageUrlPath).apply(serviceResonse: serviceResponse) | ||
| .flatMap { (serviceResponse: ServiceResponse) -> Observable<NowPlayingInfo> in | ||
| TranslateNowPlayingSubscriptionFunc.init(imageUrlPath: self.imageUrlPath).apply(serviceResonse: serviceResponse) | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll probably add the return back in for learning. put some kind of note in the readme...why they are there lol
| import RxSwift | ||
|  | ||
| protocol NowPlayingInteractor : class { | ||
| protocol NowPlayingInteractor: class { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
| .catchError{ (error: Error) -> Observable<ScrollResult> in | ||
| return Observable.just(ScrollResult.failure(pageNumber: scrollAction.getPageNumber(), error: error)) | ||
| .catchError { (error: Error) -> Observable<ScrollResult> in | ||
| Observable.just(ScrollResult.failure(pageNumber: scrollAction.getPageNumber(), error: error)) | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same here...
| .flatMap { action -> Observable<ScrollAction> in | ||
| DDLogInfo("Thread name: " + Thread.current.description + " Translate Actions into ScrollActions.") | ||
| return Observable.just(action as! ScrollAction); | ||
| return Observable.just(action) | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice to have the extension and just do this.
| */ | ||
| init(pictureUrl: String, title: String, releaseDate: Date, rating: Double) { | ||
| self.pictureUrl = pictureUrl; | ||
| self.pictureUrl = pictureUrl | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
😆
| excluded: # paths to ignore during linting. overridden by `included`. | ||
| - Pods | ||
| - .git | ||
| - ReactiveArchitectureTests | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
on the components side, we allow swiftlint to lint our test code, but with custom rule sets.
Test code is still code that needs to follow standards
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
you're strict lol. Good to know though. I 'll leave for now.
|  | ||
| return movieCell | ||
| } else { | ||
| // swiftlint:disable:next force_cast | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
| // | ||
| if (scrollDisposable != nil) { | ||
| return; | ||
| guard self.scrollDisposable == nil else { | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
loving this is a keyword
👍
| return (self.nowPlayingInteractor?.processAction(actions: actions))! | ||
| }) | ||
| .scan(initialUiModel) { (uiModel: UiModel!, result: Result!) in | ||
| .map { $0 as? ScrollResult } | 
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this I'll have to reject. Although it's interesting I'll explain why.
As far as the nil...I know RxJava 2 I can't push nulls. for RxSwift I'll leave this in with a comment.
There will be a case where we have more than one type of Result. You'll need to switch off the class type just like you do in drawing the cell view. I'll pull this and make the changes.
| Max - thanks for the PR. I took most of your suggestions and incorporated them in via another branch. I took 80% of the suggestions. The rest I just marked with notes so people using this example understand the underlying weaknesses. Please close this PR. | 
This PR adds swiftlint (install with brew) and fixes as much as I could without doing bigger refactoring.
Hopefully without being annoying, here's some issues I noticed along the way:
Codableprotocol. This is much nicer, you can use immutable non-optionals. Your init is throwable, so if something doesn't decode from json as you'd expect an error is thrown for you to handle. You can then just filter that model out etc.Observable. In ReactiveSwift you can for example return an emptySignalProducer(cold signal) which completes immediately without sending values.selfin a lot of places, and this will result in a retain cycles (memory leaks). I didn't have time to clean these up. See below though.And a few notes, from a swift guy to an android guy 😄 :
!(force unwrap) or anas!(force cast) that's a crash waiting to happen. Always favour non-optionals where possible, or?to safely unwrap. There's a bunch of operators to help you here:if let/guard let!are legit. Ie where you know there will always be a value but it's simpler to do it this way than fight the compiler. Or when using storyboards with@IBOutletetc. Also where you actually do want the app to crash if something is nil or wrong type.self. Everytime you referenceselfin an anonymous closure it captures. You need to weakifyselfto break this. See ARC (about 2/3 way down)