Merge remote-tracking branch 'origin/master' into bug4584

This commit is contained in:
Alessandro Stoltenberg
2018-06-21 14:31:47 +02:00
123 changed files with 3693 additions and 3934 deletions
@@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
64FDEBDC20D12DCF0086C2F4 /* AFAutoPurgingImageCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 64FDEBDA20D12DCE0086C2F4 /* AFAutoPurgingImageCache.m */; };
64FDEBDD20D12DCF0086C2F4 /* AFImageDownloader.m in Sources */ = {isa = PBXBuildFile; fileRef = 64FDEBDB20D12DCE0086C2F4 /* AFImageDownloader.m */; };
7F0658FD19F7D6700077FF95 /* ScanViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F0658FC19F7D6700077FF95 /* ScanViewController.swift */; };
7F0658FF19F7EE910077FF95 /* CheckInData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7F0658FE19F7EE910077FF95 /* CheckInData.swift */; };
7F14A10A1A13B9A6001C1ECB /* _abkhazia.png in Resources */ = {isa = PBXBuildFile; fileRef = 7F14A0041A13B9A6001C1ECB /* _abkhazia.png */; };
@@ -385,12 +387,9 @@
C8E0BD0D1F39ADAD002FCCA5 /* KeychainPasswordItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8E0BD0C1F39ADAD002FCCA5 /* KeychainPasswordItem.swift */; };
C8E0D3131F59475B001EEF5C /* CheckInTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8E0D3121F59475B001EEF5C /* CheckInTableViewController.swift */; };
C8F1B1E11D488B6D004C3379 /* Translation.swift in Sources */ = {isa = PBXBuildFile; fileRef = C8F1B1E01D488B6D004C3379 /* Translation.swift */; };
C8F71EDA1D8691F700826DE4 /* AFHTTPRequestOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71EA61D8691F700826DE4 /* AFHTTPRequestOperation.m */; };
C8F71EDB1D8691F700826DE4 /* AFHTTPRequestOperationManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71EA81D8691F700826DE4 /* AFHTTPRequestOperationManager.m */; };
C8F71EDC1D8691F700826DE4 /* AFHTTPSessionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71EAA1D8691F700826DE4 /* AFHTTPSessionManager.m */; };
C8F71EDD1D8691F700826DE4 /* AFNetworkReachabilityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71EAD1D8691F700826DE4 /* AFNetworkReachabilityManager.m */; };
C8F71EDE1D8691F700826DE4 /* AFSecurityPolicy.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71EAF1D8691F700826DE4 /* AFSecurityPolicy.m */; };
C8F71EDF1D8691F700826DE4 /* AFURLConnectionOperation.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71EB11D8691F700826DE4 /* AFURLConnectionOperation.m */; };
C8F71EE01D8691F700826DE4 /* AFURLRequestSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71EB31D8691F700826DE4 /* AFURLRequestSerialization.m */; };
C8F71EE11D8691F700826DE4 /* AFURLResponseSerialization.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71EB51D8691F700826DE4 /* AFURLResponseSerialization.m */; };
C8F71EE21D8691F700826DE4 /* AFURLSessionManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71EB71D8691F700826DE4 /* AFURLSessionManager.m */; };
@@ -402,7 +401,6 @@
C8F71EE81D8691F700826DE4 /* TSMarkdownParser.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71EC61D8691F700826DE4 /* TSMarkdownParser.m */; };
C8F71EE91D8691F700826DE4 /* AFNetworkActivityIndicatorManager.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71EC91D8691F700826DE4 /* AFNetworkActivityIndicatorManager.m */; };
C8F71EEA1D8691F700826DE4 /* UIActivityIndicatorView+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71ECB1D8691F700826DE4 /* UIActivityIndicatorView+AFNetworking.m */; };
C8F71EEB1D8691F700826DE4 /* UIAlertView+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71ECD1D8691F700826DE4 /* UIAlertView+AFNetworking.m */; };
C8F71EEC1D8691F700826DE4 /* UIButton+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71ECF1D8691F700826DE4 /* UIButton+AFNetworking.m */; };
C8F71EED1D8691F700826DE4 /* UIImageView+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71ED21D8691F700826DE4 /* UIImageView+AFNetworking.m */; };
C8F71EEE1D8691F700826DE4 /* UIProgressView+AFNetworking.m in Sources */ = {isa = PBXBuildFile; fileRef = C8F71ED51D8691F700826DE4 /* UIProgressView+AFNetworking.m */; };
@@ -423,6 +421,10 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
64FDEBD220D12C390086C2F4 /* AFImageDownloader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFImageDownloader.h; sourceTree = "<group>"; };
64FDEBD320D12C390086C2F4 /* AFAutoPurgingImageCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFAutoPurgingImageCache.h; sourceTree = "<group>"; };
64FDEBDA20D12DCE0086C2F4 /* AFAutoPurgingImageCache.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AFAutoPurgingImageCache.m; sourceTree = "<group>"; };
64FDEBDB20D12DCE0086C2F4 /* AFImageDownloader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AFImageDownloader.m; sourceTree = "<group>"; };
7F03FD3F19FA4D7400FA1327 /* bridge.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = bridge.h; sourceTree = "<group>"; };
7F0658FC19F7D6700077FF95 /* ScanViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = ScanViewController.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
7F0658FE19F7EE910077FF95 /* CheckInData.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; lineEnding = 0; path = CheckInData.swift; sourceTree = "<group>"; xcLanguageSpecificationIdentifier = xcode.lang.swift; };
@@ -809,10 +811,6 @@
C8E0BD0C1F39ADAD002FCCA5 /* KeychainPasswordItem.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeychainPasswordItem.swift; sourceTree = "<group>"; };
C8E0D3121F59475B001EEF5C /* CheckInTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheckInTableViewController.swift; sourceTree = "<group>"; };
C8F1B1E01D488B6D004C3379 /* Translation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Translation.swift; sourceTree = "<group>"; };
C8F71EA51D8691F700826DE4 /* AFHTTPRequestOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFHTTPRequestOperation.h; sourceTree = "<group>"; };
C8F71EA61D8691F700826DE4 /* AFHTTPRequestOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFHTTPRequestOperation.m; sourceTree = "<group>"; };
C8F71EA71D8691F700826DE4 /* AFHTTPRequestOperationManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFHTTPRequestOperationManager.h; sourceTree = "<group>"; };
C8F71EA81D8691F700826DE4 /* AFHTTPRequestOperationManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFHTTPRequestOperationManager.m; sourceTree = "<group>"; };
C8F71EA91D8691F700826DE4 /* AFHTTPSessionManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFHTTPSessionManager.h; sourceTree = "<group>"; };
C8F71EAA1D8691F700826DE4 /* AFHTTPSessionManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFHTTPSessionManager.m; sourceTree = "<group>"; };
C8F71EAB1D8691F700826DE4 /* AFNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFNetworking.h; sourceTree = "<group>"; };
@@ -820,8 +818,6 @@
C8F71EAD1D8691F700826DE4 /* AFNetworkReachabilityManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFNetworkReachabilityManager.m; sourceTree = "<group>"; };
C8F71EAE1D8691F700826DE4 /* AFSecurityPolicy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFSecurityPolicy.h; sourceTree = "<group>"; };
C8F71EAF1D8691F700826DE4 /* AFSecurityPolicy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFSecurityPolicy.m; sourceTree = "<group>"; };
C8F71EB01D8691F700826DE4 /* AFURLConnectionOperation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFURLConnectionOperation.h; sourceTree = "<group>"; };
C8F71EB11D8691F700826DE4 /* AFURLConnectionOperation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFURLConnectionOperation.m; sourceTree = "<group>"; };
C8F71EB21D8691F700826DE4 /* AFURLRequestSerialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFURLRequestSerialization.h; sourceTree = "<group>"; };
C8F71EB31D8691F700826DE4 /* AFURLRequestSerialization.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFURLRequestSerialization.m; sourceTree = "<group>"; };
C8F71EB41D8691F700826DE4 /* AFURLResponseSerialization.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AFURLResponseSerialization.h; sourceTree = "<group>"; };
@@ -845,8 +841,6 @@
C8F71EC91D8691F700826DE4 /* AFNetworkActivityIndicatorManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AFNetworkActivityIndicatorManager.m; sourceTree = "<group>"; };
C8F71ECA1D8691F700826DE4 /* UIActivityIndicatorView+AFNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIActivityIndicatorView+AFNetworking.h"; sourceTree = "<group>"; };
C8F71ECB1D8691F700826DE4 /* UIActivityIndicatorView+AFNetworking.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIActivityIndicatorView+AFNetworking.m"; sourceTree = "<group>"; };
C8F71ECC1D8691F700826DE4 /* UIAlertView+AFNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIAlertView+AFNetworking.h"; sourceTree = "<group>"; };
C8F71ECD1D8691F700826DE4 /* UIAlertView+AFNetworking.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIAlertView+AFNetworking.m"; sourceTree = "<group>"; };
C8F71ECE1D8691F700826DE4 /* UIButton+AFNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIButton+AFNetworking.h"; sourceTree = "<group>"; };
C8F71ECF1D8691F700826DE4 /* UIButton+AFNetworking.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIButton+AFNetworking.m"; sourceTree = "<group>"; };
C8F71ED01D8691F700826DE4 /* UIImage+AFNetworking.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+AFNetworking.h"; sourceTree = "<group>"; };
@@ -1565,10 +1559,6 @@
C8F71EA41D8691F700826DE4 /* AFNetworking */ = {
isa = PBXGroup;
children = (
C8F71EA51D8691F700826DE4 /* AFHTTPRequestOperation.h */,
C8F71EA61D8691F700826DE4 /* AFHTTPRequestOperation.m */,
C8F71EA71D8691F700826DE4 /* AFHTTPRequestOperationManager.h */,
C8F71EA81D8691F700826DE4 /* AFHTTPRequestOperationManager.m */,
C8F71EA91D8691F700826DE4 /* AFHTTPSessionManager.h */,
C8F71EAA1D8691F700826DE4 /* AFHTTPSessionManager.m */,
C8F71EAB1D8691F700826DE4 /* AFNetworking.h */,
@@ -1576,8 +1566,6 @@
C8F71EAD1D8691F700826DE4 /* AFNetworkReachabilityManager.m */,
C8F71EAE1D8691F700826DE4 /* AFSecurityPolicy.h */,
C8F71EAF1D8691F700826DE4 /* AFSecurityPolicy.m */,
C8F71EB01D8691F700826DE4 /* AFURLConnectionOperation.h */,
C8F71EB11D8691F700826DE4 /* AFURLConnectionOperation.m */,
C8F71EB21D8691F700826DE4 /* AFURLRequestSerialization.h */,
C8F71EB31D8691F700826DE4 /* AFURLRequestSerialization.m */,
C8F71EB41D8691F700826DE4 /* AFURLResponseSerialization.h */,
@@ -1618,12 +1606,14 @@
C8F71EC71D8691F700826DE4 /* UIKit+AFNetworking */ = {
isa = PBXGroup;
children = (
64FDEBDA20D12DCE0086C2F4 /* AFAutoPurgingImageCache.m */,
64FDEBD320D12C390086C2F4 /* AFAutoPurgingImageCache.h */,
64FDEBDB20D12DCE0086C2F4 /* AFImageDownloader.m */,
64FDEBD220D12C390086C2F4 /* AFImageDownloader.h */,
C8F71EC81D8691F700826DE4 /* AFNetworkActivityIndicatorManager.h */,
C8F71EC91D8691F700826DE4 /* AFNetworkActivityIndicatorManager.m */,
C8F71ECA1D8691F700826DE4 /* UIActivityIndicatorView+AFNetworking.h */,
C8F71ECB1D8691F700826DE4 /* UIActivityIndicatorView+AFNetworking.m */,
C8F71ECC1D8691F700826DE4 /* UIAlertView+AFNetworking.h */,
C8F71ECD1D8691F700826DE4 /* UIAlertView+AFNetworking.m */,
C8F71ECE1D8691F700826DE4 /* UIButton+AFNetworking.h */,
C8F71ECF1D8691F700826DE4 /* UIButton+AFNetworking.m */,
C8F71ED01D8691F700826DE4 /* UIImage+AFNetworking.h */,
@@ -2034,14 +2024,14 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
64FDEBDC20D12DCF0086C2F4 /* AFAutoPurgingImageCache.m in Sources */,
64FDEBDD20D12DCF0086C2F4 /* AFImageDownloader.m in Sources */,
C867BD091F4B0274007E78E0 /* TrainingCompetitorViewController.swift in Sources */,
C85DB82A1F31AAFD009559CE /* LoginViewController.swift in Sources */,
C8F71EDA1D8691F700826DE4 /* AFHTTPRequestOperation.m in Sources */,
7F1875B31A10F1B800C25BE0 /* TrackingViewController.swift in Sources */,
C8739E081D2AA2A500A89F3C /* Leaderboard+CoreDataProperties.swift in Sources */,
C8739E121D2BF14F00A89F3C /* EventData.swift in Sources */,
C843D4881EBCADDC00250F01 /* CompetitorSessionController.swift in Sources */,
C8F71EDF1D8691F700826DE4 /* AFURLConnectionOperation.m in Sources */,
C880646E2087DA1F005FBE57 /* BoatClassData.swift in Sources */,
C891887A2057F55100E37CC3 /* BoatSessionController.swift in Sources */,
C8F71EE31D8691F700826DE4 /* SVIndefiniteAnimatedView.m in Sources */,
@@ -2090,7 +2080,6 @@
C89C5FCA1D06CECD002AAAD2 /* TrackingViewStatusCell.swift in Sources */,
C843D4861EBC927800250F01 /* RegattaMarkViewController.swift in Sources */,
C8F71EDE1D8691F700826DE4 /* AFSecurityPolicy.m in Sources */,
C8F71EDB1D8691F700826DE4 /* AFHTTPRequestOperationManager.m in Sources */,
7F8B8D3F1A37356C00C34B88 /* TrackingPageViewController.swift in Sources */,
C89188712057E7D700E37CC3 /* BoatCheckIn.swift in Sources */,
C843D48F1EC099EB00250F01 /* CoreData2-3.xcmappingmodel in Sources */,
@@ -2143,7 +2132,6 @@
C8B3B9C21F3C6B3900B3B6BA /* SignUpTranslation.swift in Sources */,
7F950A911A35E967003C8C5C /* LeaderboardViewController.swift in Sources */,
C8F71EED1D8691F700826DE4 /* UIImageView+AFNetworking.m in Sources */,
C8F71EEB1D8691F700826DE4 /* UIAlertView+AFNetworking.m in Sources */,
C88F6D2D1FEACC5700A616BE /* LeaderboardGroupData.swift in Sources */,
C87A74EA1F5053AE003DE396 /* RegattaCompetitorCreateAndAddData.swift in Sources */,
C8E0D3131F59475B001EEF5C /* CheckInTableViewController.swift in Sources */,
@@ -85,12 +85,12 @@ class CheckInRequestManager: NSObject {
}
let baseURLString: String
let manager: AFHTTPRequestOperationManager
let manager: AFHTTPSessionManager
let sessionManager: AFURLSessionManager
init(baseURLString: String = "") {
self.baseURLString = baseURLString
manager = AFHTTPRequestOperationManager(baseURL: URL(string: baseURLString))
manager = AFHTTPSessionManager(baseURL: URL(string: baseURLString))
manager.requestSerializer = AFJSONRequestSerializer() as AFHTTPRequestSerializer
manager.requestSerializer.timeoutInterval = Application.RequestTimeout
manager.responseSerializer = AFJSONResponseSerializer() as AFHTTPResponseSerializer
@@ -111,6 +111,7 @@ class CheckInRequestManager: NSObject {
manager.get(
urlString,
parameters: nil,
progress: nil,
success: { (requestOperation, responseObject) in self.getEventSuccess(responseObject: responseObject, success: success) },
failure: { (requestOperation, error) in self.getEventFailure(error: error, failure: failure) }
)
@@ -138,6 +139,7 @@ class CheckInRequestManager: NSObject {
manager.get(
urlString,
parameters: nil,
progress: nil,
success: { (requestOperation, responseObject) in self.getLeaderboardSuccess(responseObject: responseObject, success: success) },
failure: { (requestOperation, error) in self.getLeaderboardFailure(error: error, failure: failure) }
)
@@ -165,6 +167,7 @@ class CheckInRequestManager: NSObject {
manager.get(
urlString,
parameters: nil,
progress: nil,
success: { (requestOperation, responseObject) in self.getBoatSuccess(responseObject: responseObject, success: success) },
failure: { (requestOperation, error) in self.getBoatFailure(error: error, failure: failure) }
)
@@ -192,6 +195,7 @@ class CheckInRequestManager: NSObject {
manager.get(
urlString,
parameters: nil,
progress: nil,
success: { (requestOperation, responseObject) in self.getCompetitorSuccess(responseObject: responseObject, success: success) },
failure: { (requestOperation, error) in self.getCompetitorFailure(error: error, failure: failure) }
)
@@ -221,6 +225,7 @@ class CheckInRequestManager: NSObject {
manager.get(
urlString,
parameters: nil,
progress: nil,
success: { (requestOperation, responseObject) in self.getMarkSuccess(responseObject: responseObject, success: success) },
failure: { (requestOperation, error) in self.getMarkFailure(error: error, failure: failure) }
)
@@ -248,6 +253,7 @@ class CheckInRequestManager: NSObject {
manager.get(
urlString,
parameters: nil,
progress: nil,
success: { (requestOperation, responseObject) in self.getTeamSuccess(responseObject: responseObject, success: success) },
failure: { (requestOperation, error) in self.getTeamFailure(error: error, failure: failure) }
)
@@ -301,6 +307,7 @@ class CheckInRequestManager: NSObject {
manager.post(
urlString,
parameters: body,
progress: nil,
success: { (requestOperation, responseObject) in self.postCheckInSuccess(responseObject: responseObject, success: success) },
failure: { (requestOperation, error) in self.postCheckInFailure(error: error, failure: failure) }
)
@@ -340,6 +347,7 @@ class CheckInRequestManager: NSObject {
manager.post(
urlString,
parameters: body,
progress: nil,
success: { (requestOperation, responseObject) in self.postCheckOutSuccess(responseObject: responseObject, success: success) },
failure: { (requestOperation, error) in self.postCheckOutFailure(error: error, failure: failure) }
)
@@ -381,6 +389,7 @@ class CheckInRequestManager: NSObject {
manager.post(
urlString,
parameters: body,
progress: nil,
success: { (requestOperation, responseObject) in self.postGPSFixesSuccess(responseObject: responseObject, success: success) },
failure: { (requestOperation, error) in self.postGPSFixesFailure(error: error, failure: failure) }
)
@@ -1,70 +0,0 @@
// AFHTTPRequestOperation.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
#import "AFURLConnectionOperation.h"
NS_ASSUME_NONNULL_BEGIN
/**
`AFHTTPRequestOperation` is a subclass of `AFURLConnectionOperation` for requests using the HTTP or HTTPS protocols. It encapsulates the concept of acceptable status codes and content types, which determine the success or failure of a request.
*/
@interface AFHTTPRequestOperation : AFURLConnectionOperation
///------------------------------------------------
/// @name Getting HTTP URL Connection Information
///------------------------------------------------
/**
The last HTTP response received by the operation's connection.
*/
@property (readonly, nonatomic, strong, nullable) NSHTTPURLResponse *response;
/**
Responses sent from the server in data tasks created with `dataTaskWithRequest:success:failure:` and run using the `GET` / `POST` / et al. convenience methods are automatically validated and serialized by the response serializer. By default, this property is set to an AFHTTPResponse serializer, which uses the raw data as its response object. The serializer validates the status code to be in the `2XX` range, denoting success. If the response serializer generates an error in `-responseObjectForResponse:data:error:`, the `failure` callback of the session task or request operation will be executed; otherwise, the `success` callback will be executed.
@warning `responseSerializer` must not be `nil`. Setting a response serializer will clear out any cached value
*/
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
/**
An object constructed by the `responseSerializer` from the response and response data. Returns `nil` unless the operation `isFinished`, has a `response`, and has `responseData` with non-zero content length. If an error occurs during serialization, `nil` will be returned, and the `error` property will be populated with the serialization error.
*/
@property (readonly, nonatomic, strong, nullable) id responseObject;
///-----------------------------------------------------------
/// @name Setting Completion Block Success / Failure Callbacks
///-----------------------------------------------------------
/**
Sets the `completionBlock` property with a block that executes either the specified success or failure block, depending on the state of the request on completion. If `error` returns a value, which can be caused by an unacceptable status code or content type, then `failure` is executed. Otherwise, `success` is executed.
This method should be overridden in subclasses in order to specify the response object passed into the success block.
@param success The block to be executed on the completion of a successful request. This block has no return value and takes two arguments: the receiver operation and the object constructed from the response data of the request.
@param failure The block to be executed on the completion of an unsuccessful request. This block has no return value and takes two arguments: the receiver operation and the error that occurred during the request.
*/
- (void)setCompletionBlockWithSuccess:(nullable void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(nullable void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;
@end
NS_ASSUME_NONNULL_END
@@ -1,206 +0,0 @@
// AFHTTPRequestOperation.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "AFHTTPRequestOperation.h"
static dispatch_queue_t http_request_operation_processing_queue() {
static dispatch_queue_t af_http_request_operation_processing_queue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
af_http_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.http-request.processing", DISPATCH_QUEUE_CONCURRENT);
});
return af_http_request_operation_processing_queue;
}
static dispatch_group_t http_request_operation_completion_group() {
static dispatch_group_t af_http_request_operation_completion_group;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
af_http_request_operation_completion_group = dispatch_group_create();
});
return af_http_request_operation_completion_group;
}
#pragma mark -
@interface AFURLConnectionOperation ()
@property (readwrite, nonatomic, strong) NSURLRequest *request;
@property (readwrite, nonatomic, strong) NSURLResponse *response;
@end
@interface AFHTTPRequestOperation ()
@property (readwrite, nonatomic, strong) NSHTTPURLResponse *response;
@property (readwrite, nonatomic, strong) id responseObject;
@property (readwrite, nonatomic, strong) NSError *responseSerializationError;
@property (readwrite, nonatomic, strong) NSRecursiveLock *lock;
@end
@implementation AFHTTPRequestOperation
@dynamic response;
@dynamic lock;
- (instancetype)initWithRequest:(NSURLRequest *)urlRequest {
self = [super initWithRequest:urlRequest];
if (!self) {
return nil;
}
self.responseSerializer = [AFHTTPResponseSerializer serializer];
return self;
}
- (void)setResponseSerializer:(AFHTTPResponseSerializer <AFURLResponseSerialization> *)responseSerializer {
NSParameterAssert(responseSerializer);
[self.lock lock];
_responseSerializer = responseSerializer;
self.responseObject = nil;
self.responseSerializationError = nil;
[self.lock unlock];
}
- (id)responseObject {
[self.lock lock];
if (!_responseObject && [self isFinished] && !self.error) {
NSError *error = nil;
self.responseObject = [self.responseSerializer responseObjectForResponse:self.response data:self.responseData error:&error];
if (error) {
self.responseSerializationError = error;
}
}
[self.lock unlock];
return _responseObject;
}
- (NSError *)error {
if (_responseSerializationError) {
return _responseSerializationError;
} else {
return [super error];
}
}
#pragma mark - AFHTTPRequestOperation
- (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
// completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle.
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-retain-cycles"
#pragma clang diagnostic ignored "-Wgnu"
self.completionBlock = ^{
if (self.completionGroup) {
dispatch_group_enter(self.completionGroup);
}
dispatch_async(http_request_operation_processing_queue(), ^{
if (self.error) {
if (failure) {
dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error);
});
}
} else {
id responseObject = self.responseObject;
if (self.error) {
if (failure) {
dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(self, self.error);
});
}
} else {
if (success) {
dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{
success(self, responseObject);
});
}
}
}
if (self.completionGroup) {
dispatch_group_leave(self.completionGroup);
}
});
};
#pragma clang diagnostic pop
}
#pragma mark - AFURLRequestOperation
- (void)pause {
[super pause];
u_int64_t offset = 0;
if ([self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey]) {
offset = [(NSNumber *)[self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey] unsignedLongLongValue];
} else {
offset = [(NSData *)[self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey] length];
}
NSMutableURLRequest *mutableURLRequest = [self.request mutableCopy];
if ([self.response respondsToSelector:@selector(allHeaderFields)] && [[self.response allHeaderFields] valueForKey:@"ETag"]) {
[mutableURLRequest setValue:[[self.response allHeaderFields] valueForKey:@"ETag"] forHTTPHeaderField:@"If-Range"];
}
[mutableURLRequest setValue:[NSString stringWithFormat:@"bytes=%llu-", offset] forHTTPHeaderField:@"Range"];
self.request = mutableURLRequest;
}
#pragma mark - NSSecureCoding
+ (BOOL)supportsSecureCoding {
return YES;
}
- (id)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:decoder];
if (!self) {
return nil;
}
self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))];
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[super encodeWithCoder:coder];
[coder encodeObject:self.responseSerializer forKey:NSStringFromSelector(@selector(responseSerializer))];
}
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
AFHTTPRequestOperation *operation = [super copyWithZone:zone];
operation.responseSerializer = [self.responseSerializer copyWithZone:zone];
operation.completionQueue = self.completionQueue;
operation.completionGroup = self.completionGroup;
return operation;
}
@end
@@ -1,326 +0,0 @@
// AFHTTPRequestOperationManager.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
#import <SystemConfiguration/SystemConfiguration.h>
#import <Availability.h>
#if __IPHONE_OS_VERSION_MIN_REQUIRED
#import <MobileCoreServices/MobileCoreServices.h>
#else
#import <CoreServices/CoreServices.h>
#endif
#import "AFHTTPRequestOperation.h"
#import "AFURLResponseSerialization.h"
#import "AFURLRequestSerialization.h"
#import "AFSecurityPolicy.h"
#import "AFNetworkReachabilityManager.h"
#ifndef NS_DESIGNATED_INITIALIZER
#if __has_attribute(objc_designated_initializer)
#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
#else
#define NS_DESIGNATED_INITIALIZER
#endif
#endif
NS_ASSUME_NONNULL_BEGIN
/**
`AFHTTPRequestOperationManager` encapsulates the common patterns of communicating with a web application over HTTP, including request creation, response serialization, network reachability monitoring, and security, as well as request operation management.
## Subclassing Notes
Developers targeting iOS 7 or Mac OS X 10.9 or later that deal extensively with a web service are encouraged to subclass `AFHTTPSessionManager`, providing a class method that returns a shared singleton object on which authentication and other configuration can be shared across the application.
For developers targeting iOS 6 or Mac OS X 10.8 or earlier, `AFHTTPRequestOperationManager` may be used to similar effect.
## Methods to Override
To change the behavior of all request operation construction for an `AFHTTPRequestOperationManager` subclass, override `HTTPRequestOperationWithRequest:success:failure`.
## Serialization
Requests created by an HTTP client will contain default headers and encode parameters according to the `requestSerializer` property, which is an object conforming to `<AFURLRequestSerialization>`.
Responses received from the server are automatically validated and serialized by the `responseSerializers` property, which is an object conforming to `<AFURLResponseSerialization>`
## URL Construction Using Relative Paths
For HTTP convenience methods, the request serializer constructs URLs from the path relative to the `-baseURL`, using `NSURL +URLWithString:relativeToURL:`, when provided. If `baseURL` is `nil`, `path` needs to resolve to a valid `NSURL` object using `NSURL +URLWithString:`.
Below are a few examples of how `baseURL` and relative paths interact:
NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"];
[NSURL URLWithString:@"foo" relativeToURL:baseURL]; // http://example.com/v1/foo
[NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // http://example.com/v1/foo?bar=baz
[NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // http://example.com/foo
[NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // http://example.com/v1/foo
[NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // http://example.com/foo/
[NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/
Also important to note is that a trailing slash will be added to any `baseURL` without one. This would otherwise cause unexpected behavior when constructing URLs using paths without a leading slash.
## Network Reachability Monitoring
Network reachability status and change monitoring is available through the `reachabilityManager` property. Applications may choose to monitor network reachability conditions in order to prevent or suspend any outbound requests. See `AFNetworkReachabilityManager` for more details.
## NSSecureCoding & NSCopying Caveats
`AFHTTPRequestOperationManager` conforms to the `NSSecureCoding` and `NSCopying` protocols, allowing operations to be archived to disk, and copied in memory, respectively. There are a few minor caveats to keep in mind, however:
- Archives and copies of HTTP clients will be initialized with an empty operation queue.
- NSSecureCoding cannot serialize / deserialize block properties, so an archive of an HTTP client will not include any reachability callback block that may be set.
*/
@interface AFHTTPRequestOperationManager : NSObject <NSSecureCoding, NSCopying>
/**
The URL used to monitor reachability, and construct requests from relative paths in methods like `requestWithMethod:URLString:parameters:`, and the `GET` / `POST` / et al. convenience methods.
*/
@property (readonly, nonatomic, strong, nullable) NSURL *baseURL;
/**
Requests created with `requestWithMethod:URLString:parameters:` & `multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:` are constructed with a set of default headers using a parameter serialization specified by this property. By default, this is set to an instance of `AFHTTPRequestSerializer`, which serializes query string parameters for `GET`, `HEAD`, and `DELETE` requests, or otherwise URL-form-encodes HTTP message bodies.
@warning `requestSerializer` must not be `nil`.
*/
@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer;
/**
Responses sent from the server in data tasks created with `dataTaskWithRequest:success:failure:` and run using the `GET` / `POST` / et al. convenience methods are automatically validated and serialized by the response serializer. By default, this property is set to a JSON serializer, which serializes data from responses with a `application/json` MIME type, and falls back to the raw data object. The serializer validates the status code to be in the `2XX` range, denoting success. If the response serializer generates an error in `-responseObjectForResponse:data:error:`, the `failure` callback of the session task or request operation will be executed; otherwise, the `success` callback will be executed.
@warning `responseSerializer` must not be `nil`.
*/
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
/**
The operation queue on which request operations are scheduled and run.
*/
@property (nonatomic, strong) NSOperationQueue *operationQueue;
///-------------------------------
/// @name Managing URL Credentials
///-------------------------------
/**
Whether request operations should consult the credential storage for authenticating the connection. `YES` by default.
@see AFURLConnectionOperation -shouldUseCredentialStorage
*/
@property (nonatomic, assign) BOOL shouldUseCredentialStorage;
/**
The credential used by request operations for authentication challenges.
@see AFURLConnectionOperation -credential
*/
@property (nonatomic, strong, nullable) NSURLCredential *credential;
///-------------------------------
/// @name Managing Security Policy
///-------------------------------
/**
The security policy used by created request operations to evaluate server trust for secure connections. `AFHTTPRequestOperationManager` uses the `defaultPolicy` unless otherwise specified.
*/
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
///------------------------------------
/// @name Managing Network Reachability
///------------------------------------
/**
The network reachability manager. `AFHTTPRequestOperationManager` uses the `sharedManager` by default.
*/
@property (readwrite, nonatomic, strong) AFNetworkReachabilityManager *reachabilityManager;
///-------------------------------
/// @name Managing Callback Queues
///-------------------------------
/**
The dispatch queue for the `completionBlock` of request operations. If `NULL` (default), the main queue is used.
*/
#if OS_OBJECT_USE_OBJC
@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;
#else
@property (nonatomic, assign, nullable) dispatch_queue_t completionQueue;
#endif
/**
The dispatch group for the `completionBlock` of request operations. If `NULL` (default), a private dispatch group is used.
*/
#if OS_OBJECT_USE_OBJC
@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;
#else
@property (nonatomic, assign, nullable) dispatch_group_t completionGroup;
#endif
///---------------------------------------------
/// @name Creating and Initializing HTTP Clients
///---------------------------------------------
/**
Creates and returns an `AFHTTPRequestOperationManager` object.
*/
+ (instancetype)manager;
/**
Initializes an `AFHTTPRequestOperationManager` object with the specified base URL.
This is the designated initializer.
@param url The base URL for the HTTP client.
@return The newly-initialized HTTP client
*/
- (instancetype)initWithBaseURL:(nullable NSURL *)url NS_DESIGNATED_INITIALIZER;
///---------------------------------------
/// @name Managing HTTP Request Operations
///---------------------------------------
/**
Creates an `AFHTTPRequestOperation`, and sets the response serializers to that of the HTTP client.
@param request The request object to be loaded asynchronously during execution of the operation.
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the created request operation and the object created from the response data of request.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes two arguments:, the created request operation and the `NSError` object describing the network or parsing error that occurred.
*/
- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)request
success:(nullable void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(nullable void (^)(AFHTTPRequestOperation *operation, NSError *error))failure;
///---------------------------
/// @name Making HTTP Requests
///---------------------------
/**
Creates and runs an `AFHTTPRequestOperation` with a `GET` request.
@param URLString The URL string used to create the request URL.
@param parameters The parameters to be encoded according to the client request serializer.
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the request operation, and the response object created by the client response serializer.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the request operation and the error describing the network or parsing error that occurred.
@see -HTTPRequestOperationWithRequest:success:failure:
*/
- (nullable AFHTTPRequestOperation *)GET:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(nullable void (^)(AFHTTPRequestOperation * __nullable operation, NSError *error))failure;
/**
Creates and runs an `AFHTTPRequestOperation` with a `HEAD` request.
@param URLString The URL string used to create the request URL.
@param parameters The parameters to be encoded according to the client request serializer.
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes a single arguments: the request operation.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the request operation and the error describing the network or parsing error that occurred.
@see -HTTPRequestOperationWithRequest:success:failure:
*/
- (nullable AFHTTPRequestOperation *)HEAD:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(AFHTTPRequestOperation *operation))success
failure:(nullable void (^)(AFHTTPRequestOperation * __nullable operation, NSError *error))failure;
/**
Creates and runs an `AFHTTPRequestOperation` with a `POST` request.
@param URLString The URL string used to create the request URL.
@param parameters The parameters to be encoded according to the client request serializer.
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the request operation, and the response object created by the client response serializer.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the request operation and the error describing the network or parsing error that occurred.
@see -HTTPRequestOperationWithRequest:success:failure:
*/
- (nullable AFHTTPRequestOperation *)POST:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(nullable void (^)(AFHTTPRequestOperation * __nullable operation, NSError *error))failure;
/**
Creates and runs an `AFHTTPRequestOperation` with a multipart `POST` request.
@param URLString The URL string used to create the request URL.
@param parameters The parameters to be encoded according to the client request serializer.
@param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol.
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the request operation, and the response object created by the client response serializer.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the request operation and the error describing the network or parsing error that occurred.
@see -HTTPRequestOperationWithRequest:success:failure:
*/
- (nullable AFHTTPRequestOperation *)POST:(NSString *)URLString
parameters:(nullable id)parameters
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
success:(nullable void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(nullable void (^)(AFHTTPRequestOperation * __nullable operation, NSError *error))failure;
/**
Creates and runs an `AFHTTPRequestOperation` with a `PUT` request.
@param URLString The URL string used to create the request URL.
@param parameters The parameters to be encoded according to the client request serializer.
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the request operation, and the response object created by the client response serializer.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the request operation and the error describing the network or parsing error that occurred.
@see -HTTPRequestOperationWithRequest:success:failure:
*/
- (nullable AFHTTPRequestOperation *)PUT:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(nullable void (^)(AFHTTPRequestOperation * __nullable operation, NSError *error))failure;
/**
Creates and runs an `AFHTTPRequestOperation` with a `PATCH` request.
@param URLString The URL string used to create the request URL.
@param parameters The parameters to be encoded according to the client request serializer.
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the request operation, and the response object created by the client response serializer.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the request operation and the error describing the network or parsing error that occurred.
@see -HTTPRequestOperationWithRequest:success:failure:
*/
- (nullable AFHTTPRequestOperation *)PATCH:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(nullable void (^)(AFHTTPRequestOperation * __nullable operation, NSError *error))failure;
/**
Creates and runs an `AFHTTPRequestOperation` with a `DELETE` request.
@param URLString The URL string used to create the request URL.
@param parameters The parameters to be encoded according to the client request serializer.
@param success A block object to be executed when the request operation finishes successfully. This block has no return value and takes two arguments: the request operation, and the response object created by the client response serializer.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the request operation and the error describing the network or parsing error that occurred.
@see -HTTPRequestOperationWithRequest:success:failure:
*/
- (nullable AFHTTPRequestOperation *)DELETE:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(nullable void (^)(AFHTTPRequestOperation * __nullable operation, NSError *error))failure;
@end
NS_ASSUME_NONNULL_END
@@ -1,290 +0,0 @@
// AFHTTPRequestOperationManager.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
#import "AFHTTPRequestOperationManager.h"
#import "AFHTTPRequestOperation.h"
#import <Availability.h>
#import <Security/Security.h>
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#import <UIKit/UIKit.h>
#endif
@interface AFHTTPRequestOperationManager ()
@property (readwrite, nonatomic, strong) NSURL *baseURL;
@end
@implementation AFHTTPRequestOperationManager
+ (instancetype)manager {
return [[self alloc] initWithBaseURL:nil];
}
- (instancetype)init {
return [self initWithBaseURL:nil];
}
- (instancetype)initWithBaseURL:(NSURL *)url {
self = [super init];
if (!self) {
return nil;
}
// Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected
if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) {
url = [url URLByAppendingPathComponent:@""];
}
self.baseURL = url;
self.requestSerializer = [AFHTTPRequestSerializer serializer];
self.responseSerializer = [AFJSONResponseSerializer serializer];
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
self.reachabilityManager = [AFNetworkReachabilityManager sharedManager];
self.operationQueue = [[NSOperationQueue alloc] init];
self.shouldUseCredentialStorage = YES;
return self;
}
#pragma mark -
#ifdef _SYSTEMCONFIGURATION_H
#endif
- (void)setRequestSerializer:(AFHTTPRequestSerializer <AFURLRequestSerialization> *)requestSerializer {
NSParameterAssert(requestSerializer);
_requestSerializer = requestSerializer;
}
- (void)setResponseSerializer:(AFHTTPResponseSerializer <AFURLResponseSerialization> *)responseSerializer {
NSParameterAssert(responseSerializer);
_responseSerializer = responseSerializer;
}
#pragma mark -
- (AFHTTPRequestOperation *)HTTPRequestOperationWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
NSError *serializationError = nil;
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
if (serializationError) {
if (failure) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
#pragma clang diagnostic pop
}
return nil;
}
return [self HTTPRequestOperationWithRequest:request success:success failure:failure];
}
- (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)request
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = self.responseSerializer;
operation.shouldUseCredentialStorage = self.shouldUseCredentialStorage;
operation.credential = self.credential;
operation.securityPolicy = self.securityPolicy;
[operation setCompletionBlockWithSuccess:success failure:failure];
operation.completionQueue = self.completionQueue;
operation.completionGroup = self.completionGroup;
return operation;
}
#pragma mark -
- (AFHTTPRequestOperation *)GET:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithHTTPMethod:@"GET" URLString:URLString parameters:parameters success:success failure:failure];
[self.operationQueue addOperation:operation];
return operation;
}
- (AFHTTPRequestOperation *)HEAD:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(AFHTTPRequestOperation *operation))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithHTTPMethod:@"HEAD" URLString:URLString parameters:parameters success:^(AFHTTPRequestOperation *requestOperation, __unused id responseObject) {
if (success) {
success(requestOperation);
}
} failure:failure];
[self.operationQueue addOperation:operation];
return operation;
}
- (AFHTTPRequestOperation *)POST:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithHTTPMethod:@"POST" URLString:URLString parameters:parameters success:success failure:failure];
[self.operationQueue addOperation:operation];
return operation;
}
- (AFHTTPRequestOperation *)POST:(NSString *)URLString
parameters:(id)parameters
constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
NSError *serializationError = nil;
NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError];
if (serializationError) {
if (failure) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
failure(nil, serializationError);
});
#pragma clang diagnostic pop
}
return nil;
}
AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure];
[self.operationQueue addOperation:operation];
return operation;
}
- (AFHTTPRequestOperation *)PUT:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithHTTPMethod:@"PUT" URLString:URLString parameters:parameters success:success failure:failure];
[self.operationQueue addOperation:operation];
return operation;
}
- (AFHTTPRequestOperation *)PATCH:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithHTTPMethod:@"PATCH" URLString:URLString parameters:parameters success:success failure:failure];
[self.operationQueue addOperation:operation];
return operation;
}
- (AFHTTPRequestOperation *)DELETE:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success
failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure
{
AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithHTTPMethod:@"DELETE" URLString:URLString parameters:parameters success:success failure:failure];
[self.operationQueue addOperation:operation];
return operation;
}
#pragma mark - NSObject
- (NSString *)description {
return [NSString stringWithFormat:@"<%@: %p, baseURL: %@, operationQueue: %@>", NSStringFromClass([self class]), self, [self.baseURL absoluteString], self.operationQueue];
}
#pragma mark - NSSecureCoding
+ (BOOL)supportsSecureCoding {
return YES;
}
- (id)initWithCoder:(NSCoder *)decoder {
NSURL *baseURL = [decoder decodeObjectForKey:NSStringFromSelector(@selector(baseURL))];
self = [self initWithBaseURL:baseURL];
if (!self) {
return nil;
}
self.requestSerializer = [decoder decodeObjectOfClass:[AFHTTPRequestSerializer class] forKey:NSStringFromSelector(@selector(requestSerializer))];
self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))];
AFSecurityPolicy *decodedPolicy = [decoder decodeObjectOfClass:[AFSecurityPolicy class] forKey:NSStringFromSelector(@selector(securityPolicy))];
if (decodedPolicy) {
self.securityPolicy = decodedPolicy;
}
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[coder encodeObject:self.baseURL forKey:NSStringFromSelector(@selector(baseURL))];
[coder encodeObject:self.requestSerializer forKey:NSStringFromSelector(@selector(requestSerializer))];
[coder encodeObject:self.responseSerializer forKey:NSStringFromSelector(@selector(responseSerializer))];
[coder encodeObject:self.securityPolicy forKey:NSStringFromSelector(@selector(securityPolicy))];
}
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
AFHTTPRequestOperationManager *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL];
HTTPClient.requestSerializer = [self.requestSerializer copyWithZone:zone];
HTTPClient.responseSerializer = [self.responseSerializer copyWithZone:zone];
HTTPClient.securityPolicy = [self.securityPolicy copyWithZone:zone];
return HTTPClient;
}
@end
+70 -28
View File
@@ -1,5 +1,5 @@
// AFHTTPSessionManager.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,9 +23,9 @@
#if !TARGET_OS_WATCH
#import <SystemConfiguration/SystemConfiguration.h>
#endif
#import <Availability.h>
#import <TargetConditionals.h>
#if __IPHONE_OS_VERSION_MIN_REQUIRED
#if TARGET_OS_IOS || TARGET_OS_WATCH || TARGET_OS_TV
#import <MobileCoreServices/MobileCoreServices.h>
#else
#import <CoreServices/CoreServices.h>
@@ -33,14 +33,6 @@
#import "AFURLSessionManager.h"
#ifndef NS_DESIGNATED_INITIALIZER
#if __has_attribute(objc_designated_initializer)
#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
#else
#define NS_DESIGNATED_INITIALIZER
#endif
#endif
/**
`AFHTTPSessionManager` is a subclass of `AFURLSessionManager` with convenience methods for making HTTP requests. When a `baseURL` is provided, requests made with the `GET` / `POST` / et al. convenience methods can be made with relative paths.
@@ -79,8 +71,6 @@
@warning Managers for background sessions must be owned for the duration of their use. This can be accomplished by creating an application-wide or shared singleton instance.
*/
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) || TARGET_OS_WATCH
NS_ASSUME_NONNULL_BEGIN
@interface AFHTTPSessionManager : AFURLSessionManager <NSSecureCoding, NSCopying>
@@ -151,8 +141,26 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * __nullable task, NSError *error))failure;
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;
/**
Creates and runs an `NSURLSessionDataTask` with a `GET` request.
@param URLString The URL string used to create the request URL.
@param parameters The parameters to be encoded according to the client request serializer.
@param downloadProgress A block object to be executed when the download progress is updated. Note this block is called on the session queue, not the main queue.
@param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer.
@param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
@see -dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
*/
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
/**
Creates and runs an `NSURLSessionDataTask` with a `HEAD` request.
@@ -167,7 +175,7 @@ NS_ASSUME_NONNULL_BEGIN
- (nullable NSURLSessionDataTask *)HEAD:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task))success
failure:(nullable void (^)(NSURLSessionDataTask * __nullable task, NSError *error))failure;
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
/**
Creates and runs an `NSURLSessionDataTask` with a `POST` request.
@@ -181,8 +189,25 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * __nullable task, NSError *error))failure;
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;
/**
Creates and runs an `NSURLSessionDataTask` with a `POST` request.
@param URLString The URL string used to create the request URL.
@param parameters The parameters to be encoded according to the client request serializer.
@param uploadProgress A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
@param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer.
@param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
@see -dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
*/
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
/**
Creates and runs an `NSURLSessionDataTask` with a multipart `POST` request.
@@ -198,8 +223,27 @@ NS_ASSUME_NONNULL_BEGIN
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
success:(nullable void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * __nullable task, NSError *error))failure;
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;
/**
Creates and runs an `NSURLSessionDataTask` with a multipart `POST` request.
@param URLString The URL string used to create the request URL.
@param parameters The parameters to be encoded according to the client request serializer.
@param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol.
@param uploadProgress A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
@param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer.
@param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred.
@see -dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
*/
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
/**
Creates and runs an `NSURLSessionDataTask` with a `PUT` request.
@@ -213,8 +257,8 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (nullable NSURLSessionDataTask *)PUT:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * __nullable task, NSError *error))failure;
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
/**
Creates and runs an `NSURLSessionDataTask` with a `PATCH` request.
@@ -228,8 +272,8 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (nullable NSURLSessionDataTask *)PATCH:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * __nullable task, NSError *error))failure;
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
/**
Creates and runs an `NSURLSessionDataTask` with a `DELETE` request.
@@ -243,11 +287,9 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (nullable NSURLSessionDataTask *)DELETE:(NSString *)URLString
parameters:(nullable id)parameters
success:(nullable void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * __nullable task, NSError *error))failure;
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
@end
NS_ASSUME_NONNULL_END
#endif
+54 -21
View File
@@ -1,5 +1,5 @@
// AFHTTPSessionManager.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -21,23 +21,20 @@
#import "AFHTTPSessionManager.h"
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) || TARGET_WATCH_OS
#import "AFURLRequestSerialization.h"
#import "AFURLResponseSerialization.h"
#import <Availability.h>
#import <TargetConditionals.h>
#import <Security/Security.h>
#ifdef _SYSTEMCONFIGURATION_H
#import <netinet/in.h>
#import <netinet6/in6.h>
#import <arpa/inet.h>
#import <ifaddrs.h>
#import <netdb.h>
#endif
#if TARGET_OS_IOS
#if TARGET_OS_IOS || TARGET_OS_TV
#import <UIKit/UIKit.h>
#elif TARGET_OS_WATCH
#import <WatchKit/WatchKit.h>
@@ -89,9 +86,6 @@
#pragma mark -
#ifdef _SYSTEMCONFIGURATION_H
#endif
- (void)setRequestSerializer:(AFHTTPRequestSerializer <AFURLRequestSerialization> *)requestSerializer {
NSParameterAssert(requestSerializer);
@@ -111,7 +105,24 @@
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET" URLString:URLString parameters:parameters success:success failure:failure];
return [self GET:URLString parameters:parameters progress:nil success:success failure:failure];
}
- (NSURLSessionDataTask *)GET:(NSString *)URLString
parameters:(id)parameters
progress:(void (^)(NSProgress * _Nonnull))downloadProgress
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
URLString:URLString
parameters:parameters
uploadProgress:nil
downloadProgress:downloadProgress
success:success
failure:failure];
[dataTask resume];
@@ -123,7 +134,7 @@
success:(void (^)(NSURLSessionDataTask *task))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"HEAD" URLString:URLString parameters:parameters success:^(NSURLSessionDataTask *task, __unused id responseObject) {
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"HEAD" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:^(NSURLSessionDataTask *task, __unused id responseObject) {
if (success) {
success(task);
}
@@ -139,16 +150,35 @@
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters success:success failure:failure];
return [self POST:URLString parameters:parameters progress:nil success:success failure:failure];
}
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
progress:(void (^)(NSProgress * _Nonnull))uploadProgress
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters uploadProgress:uploadProgress downloadProgress:nil success:success failure:failure];
[dataTask resume];
return dataTask;
}
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(nullable id)parameters
constructingBodyWithBlock:(nullable void (^)(id<AFMultipartFormData> _Nonnull))block
success:(nullable void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
{
return [self POST:URLString parameters:parameters constructingBodyWithBlock:block progress:nil success:success failure:failure];
}
- (NSURLSessionDataTask *)POST:(NSString *)URLString
parameters:(id)parameters
constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
@@ -167,7 +197,7 @@
return nil;
}
__block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:nil completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
__block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:uploadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(task, error);
@@ -189,7 +219,7 @@
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PUT" URLString:URLString parameters:parameters success:success failure:failure];
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PUT" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:success failure:failure];
[dataTask resume];
@@ -201,7 +231,7 @@
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PATCH" URLString:URLString parameters:parameters success:success failure:failure];
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PATCH" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:success failure:failure];
[dataTask resume];
@@ -213,7 +243,7 @@
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"DELETE" URLString:URLString parameters:parameters success:success failure:failure];
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"DELETE" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:success failure:failure];
[dataTask resume];
@@ -223,6 +253,8 @@
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
success:(void (^)(NSURLSessionDataTask *, id))success
failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
{
@@ -242,7 +274,10 @@
}
__block NSURLSessionDataTask *dataTask = nil;
dataTask = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
dataTask = [self dataTaskWithRequest:request
uploadProgress:uploadProgress
downloadProgress:downloadProgress
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
if (error) {
if (failure) {
failure(dataTask, error);
@@ -269,7 +304,7 @@
return YES;
}
- (id)initWithCoder:(NSCoder *)decoder {
- (instancetype)initWithCoder:(NSCoder *)decoder {
NSURL *baseURL = [decoder decodeObjectOfClass:[NSURL class] forKey:NSStringFromSelector(@selector(baseURL))];
NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"];
if (!configuration) {
@@ -314,7 +349,7 @@
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
- (instancetype)copyWithZone:(NSZone *)zone {
AFHTTPSessionManager *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL sessionConfiguration:self.session.configuration];
HTTPClient.requestSerializer = [self.requestSerializer copyWithZone:zone];
@@ -324,5 +359,3 @@
}
@end
#endif
@@ -1,5 +1,5 @@
// AFNetworkReachabilityManager.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -24,14 +24,6 @@
#if !TARGET_OS_WATCH
#import <SystemConfiguration/SystemConfiguration.h>
#ifndef NS_DESIGNATED_INITIALIZER
#if __has_attribute(objc_designated_initializer)
#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
#else
#define NS_DESIGNATED_INITIALIZER
#endif
#endif
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
AFNetworkReachabilityStatusUnknown = -1,
AFNetworkReachabilityStatusNotReachable = 0,
@@ -46,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN
Reachability can be used to determine background information about why a network operation failed, or to trigger a network operation retrying when a connection is established. It should not be used to prevent a user from initiating a network request, as it's possible that an initial request may be required to establish reachability.
See Apple's Reachability Sample Code (https://developer.apple.com/library/ios/samplecode/reachability/)
See Apple's Reachability Sample Code ( https://developer.apple.com/library/ios/samplecode/reachability/ )
@warning Instances of `AFNetworkReachabilityManager` must be started with `-startMonitoring` before reachability status can be determined.
*/
@@ -81,6 +73,13 @@ NS_ASSUME_NONNULL_BEGIN
*/
+ (instancetype)sharedManager;
/**
Creates and returns a network reachability manager with the default socket address.
@return An initialized network reachability manager, actively monitoring the default socket address.
*/
+ (instancetype)manager;
/**
Creates and returns a network reachability manager for the specified domain.
@@ -93,7 +92,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
Creates and returns a network reachability manager for the socket address.
@param address The socket address (`sockaddr_in`) used to evaluate network reachability.
@param address The socket address (`sockaddr_in6`) used to evaluate network reachability.
@return An initialized network reachability manager, actively monitoring the specified socket address.
*/
@@ -1,5 +1,5 @@
// AFNetworkReachabilityManager.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -94,6 +94,7 @@ static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused targ
AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);
}
static const void * AFNetworkReachabilityRetainCallback(const void *info) {
return Block_copy(info);
}
@@ -105,7 +106,7 @@ static void AFNetworkReachabilityReleaseCallback(const void *info) {
}
@interface AFNetworkReachabilityManager ()
@property (readwrite, nonatomic, strong) id networkReachability;
@property (readonly, nonatomic, assign) SCNetworkReachabilityRef networkReachability;
@property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
@property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock;
@end
@@ -116,35 +117,46 @@ static void AFNetworkReachabilityReleaseCallback(const void *info) {
static AFNetworkReachabilityManager *_sharedManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_len = sizeof(address);
address.sin_family = AF_INET;
_sharedManager = [self managerForAddress:&address];
_sharedManager = [self manager];
});
return _sharedManager;
}
#ifndef __clang_analyzer__
+ (instancetype)managerForDomain:(NSString *)domain {
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
CFRelease(reachability);
return manager;
}
#endif
#ifndef __clang_analyzer__
+ (instancetype)managerForAddress:(const void *)address {
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
CFRelease(reachability);
return manager;
}
+ (instancetype)manager
{
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
struct sockaddr_in6 address;
bzero(&address, sizeof(address));
address.sin6_len = sizeof(address);
address.sin6_family = AF_INET6;
#else
struct sockaddr_in address;
bzero(&address, sizeof(address));
address.sin_len = sizeof(address);
address.sin_family = AF_INET;
#endif
return [self managerForAddress:&address];
}
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability {
self = [super init];
@@ -152,7 +164,7 @@ static void AFNetworkReachabilityReleaseCallback(const void *info) {
return nil;
}
self.networkReachability = CFBridgingRelease(reachability);
_networkReachability = CFRetain(reachability);
self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown;
return self;
@@ -165,6 +177,10 @@ static void AFNetworkReachabilityReleaseCallback(const void *info) {
- (void)dealloc {
[self stopMonitoring];
if (_networkReachability != NULL) {
CFRelease(_networkReachability);
}
}
#pragma mark -
@@ -201,14 +217,13 @@ static void AFNetworkReachabilityReleaseCallback(const void *info) {
};
id networkReachability = self.networkReachability;
SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
SCNetworkReachabilitySetCallback((__bridge SCNetworkReachabilityRef)networkReachability, AFNetworkReachabilityCallback, &context);
SCNetworkReachabilityScheduleWithRunLoop((__bridge SCNetworkReachabilityRef)networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
SCNetworkReachabilityFlags flags;
if (SCNetworkReachabilityGetFlags((__bridge SCNetworkReachabilityRef)networkReachability, &flags)) {
if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
AFPostReachabilityStatusChange(flags, callback);
}
});
@@ -219,7 +234,7 @@ static void AFNetworkReachabilityReleaseCallback(const void *info) {
return;
}
SCNetworkReachabilityUnscheduleFromRunLoop((__bridge SCNetworkReachabilityRef)self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
}
#pragma mark -
+2 -7
View File
@@ -22,6 +22,7 @@
#import <Foundation/Foundation.h>
#import <Availability.h>
#import <TargetConditionals.h>
#ifndef _AFNETWORKING_
#define _AFNETWORKING_
@@ -29,18 +30,12 @@
#import "AFURLRequestSerialization.h"
#import "AFURLResponseSerialization.h"
#import "AFSecurityPolicy.h"
#if !TARGET_OS_WATCH
#import "AFNetworkReachabilityManager.h"
#import "AFURLConnectionOperation.h"
#import "AFHTTPRequestOperation.h"
#import "AFHTTPRequestOperationManager.h"
#endif
#if ( ( defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) || \
( defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 ) || \
TARGET_OS_WATCH )
#import "AFURLSessionManager.h"
#import "AFHTTPSessionManager.h"
#endif
#endif /* _AFNETWORKING_ */
+28 -16
View File
@@ -1,5 +1,5 @@
// AFSecurityPolicy.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -44,9 +44,13 @@ NS_ASSUME_NONNULL_BEGIN
@property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
/**
The certificates used to evaluate server trust according to the SSL pinning mode. By default, this property is set to any (`.cer`) certificates included in the app bundle. Note that if you create an array with duplicate certificates, the duplicate certificates will be removed. Note that if pinning is enabled, `evaluateServerTrust:forDomain:` will return true if any pinned certificate matches.
The certificates used to evaluate server trust according to the SSL pinning mode.
By default, this property is set to any (`.cer`) certificates included in the target compiling AFNetworking. Note that if you are using AFNetworking as embedded framework, no certificates will be pinned by default. Use `certificatesInBundle` to load certificates from your target, and then create a new policy by calling `policyWithPinningMode:withPinnedCertificates`.
Note that if pinning is enabled, `evaluateServerTrust:forDomain:` will return true if any pinned certificate matches.
*/
@property (nonatomic, strong, nullable) NSArray *pinnedCertificates;
@property (nonatomic, strong, nullable) NSSet <NSData *> *pinnedCertificates;
/**
Whether or not to trust servers with an invalid or expired SSL certificates. Defaults to `NO`.
@@ -58,6 +62,17 @@ NS_ASSUME_NONNULL_BEGIN
*/
@property (nonatomic, assign) BOOL validatesDomainName;
///-----------------------------------------
/// @name Getting Certificates from the Bundle
///-----------------------------------------
/**
Returns any certificates included in the bundle. If you are using AFNetworking as an embedded framework, you must use this method to find the certificates you have included in your app bundle, and use them when creating your security policy by calling `policyWithPinningMode:withPinnedCertificates`.
@return The certificates included in the given bundle.
*/
+ (NSSet <NSData *> *)certificatesInBundle:(NSBundle *)bundle;
///-----------------------------------------
/// @name Getting Specific Security Policies
///-----------------------------------------
@@ -82,23 +97,20 @@ NS_ASSUME_NONNULL_BEGIN
*/
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode;
/**
Creates and returns a security policy with the specified pinning mode.
@param pinningMode The SSL pinning mode.
@param pinnedCertificates The certificates to pin against.
@return A new security policy.
*/
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet <NSData *> *)pinnedCertificates;
///------------------------------
/// @name Evaluating Server Trust
///------------------------------
/**
Whether or not the specified server trust should be accepted, based on the security policy.
This method should be used when responding to an authentication challenge from a server.
@param serverTrust The X.509 certificate trust of the server.
@return Whether or not to trust the server.
@warning This method has been deprecated in favor of `-evaluateServerTrust:forDomain:`.
*/
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust DEPRECATED_ATTRIBUTE;
/**
Whether or not the specified server trust should be accepted, based on the security policy.
+36 -30
View File
@@ -1,5 +1,5 @@
// AFSecurityPolicy.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +23,7 @@
#import <AssertMacros.h>
#if !TARGET_OS_IOS && !TARGET_OS_WATCH
#if !TARGET_OS_IOS && !TARGET_OS_WATCH && !TARGET_OS_TV
static NSData * AFSecKeyGetData(SecKeyRef key) {
CFDataRef data = NULL;
@@ -41,7 +41,7 @@ _out:
#endif
static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) {
#if TARGET_OS_IOS || TARGET_OS_WATCH
#if TARGET_OS_IOS || TARGET_OS_WATCH || TARGET_OS_TV
return [(__bridge id)key1 isEqual:(__bridge id)key2];
#else
return [AFSecKeyGetData(key1) isEqual:AFSecKeyGetData(key2)];
@@ -150,25 +150,29 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
@interface AFSecurityPolicy()
@property (readwrite, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
@property (readwrite, nonatomic, strong) NSArray *pinnedPublicKeys;
@property (readwrite, nonatomic, strong) NSSet *pinnedPublicKeys;
@end
@implementation AFSecurityPolicy
+ (NSArray *)defaultPinnedCertificates {
static NSArray *_defaultPinnedCertificates = nil;
+ (NSSet *)certificatesInBundle:(NSBundle *)bundle {
NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."];
NSMutableSet *certificates = [NSMutableSet setWithCapacity:[paths count]];
for (NSString *path in paths) {
NSData *certificateData = [NSData dataWithContentsOfFile:path];
[certificates addObject:certificateData];
}
return [NSSet setWithSet:certificates];
}
+ (NSSet *)defaultPinnedCertificates {
static NSSet *_defaultPinnedCertificates = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."];
NSMutableArray *certificates = [NSMutableArray arrayWithCapacity:[paths count]];
for (NSString *path in paths) {
NSData *certificateData = [NSData dataWithContentsOfFile:path];
[certificates addObject:certificateData];
}
_defaultPinnedCertificates = [[NSArray alloc] initWithArray:certificates];
_defaultPinnedCertificates = [self certificatesInBundle:bundle];
});
return _defaultPinnedCertificates;
@@ -182,15 +186,19 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
}
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode {
return [self policyWithPinningMode:pinningMode withPinnedCertificates:[self defaultPinnedCertificates]];
}
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet *)pinnedCertificates {
AFSecurityPolicy *securityPolicy = [[self alloc] init];
securityPolicy.SSLPinningMode = pinningMode;
[securityPolicy setPinnedCertificates:[self defaultPinnedCertificates]];
[securityPolicy setPinnedCertificates:pinnedCertificates];
return securityPolicy;
}
- (id)init {
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
@@ -201,11 +209,11 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
return self;
}
- (void)setPinnedCertificates:(NSArray *)pinnedCertificates {
_pinnedCertificates = [[NSOrderedSet orderedSetWithArray:pinnedCertificates] array];
- (void)setPinnedCertificates:(NSSet *)pinnedCertificates {
_pinnedCertificates = pinnedCertificates;
if (self.pinnedCertificates) {
NSMutableArray *mutablePinnedPublicKeys = [NSMutableArray arrayWithCapacity:[self.pinnedCertificates count]];
NSMutableSet *mutablePinnedPublicKeys = [NSMutableSet setWithCapacity:[self.pinnedCertificates count]];
for (NSData *certificate in self.pinnedCertificates) {
id publicKey = AFPublicKeyForCertificate(certificate);
if (!publicKey) {
@@ -213,7 +221,7 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
}
[mutablePinnedPublicKeys addObject:publicKey];
}
self.pinnedPublicKeys = [NSArray arrayWithArray:mutablePinnedPublicKeys];
self.pinnedPublicKeys = [NSSet setWithSet:mutablePinnedPublicKeys];
} else {
self.pinnedPublicKeys = nil;
}
@@ -221,10 +229,6 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
#pragma mark -
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust {
return [self evaluateServerTrust:serverTrust forDomain:nil];
}
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
forDomain:(NSString *)domain
{
@@ -256,7 +260,6 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
return NO;
}
NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
switch (self.SSLPinningMode) {
case AFSSLPinningModeNone:
default:
@@ -272,13 +275,16 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
return NO;
}
NSUInteger trustedCertificateCount = 0;
for (NSData *trustChainCertificate in serverCertificates) {
// obtain the chain after being validated, which *should* contain the pinned certificate in the last position (if it's the Root CA)
NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
trustedCertificateCount++;
return YES;
}
}
return trustedCertificateCount > 0;
return NO;
}
case AFSSLPinningModePublicKey: {
NSUInteger trustedPublicKeyCount = 0;
@@ -1,344 +0,0 @@
// AFURLConnectionOperation.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
#import <Availability.h>
#import "AFURLRequestSerialization.h"
#import "AFURLResponseSerialization.h"
#import "AFSecurityPolicy.h"
#ifndef NS_DESIGNATED_INITIALIZER
#if __has_attribute(objc_designated_initializer)
#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
#else
#define NS_DESIGNATED_INITIALIZER
#endif
#endif
/**
`AFURLConnectionOperation` is a subclass of `NSOperation` that implements `NSURLConnection` delegate methods.
## Subclassing Notes
This is the base class of all network request operations. You may wish to create your own subclass in order to implement additional `NSURLConnection` delegate methods (see "`NSURLConnection` Delegate Methods" below), or to provide additional properties and/or class constructors.
If you are creating a subclass that communicates over the HTTP or HTTPS protocols, you may want to consider subclassing `AFHTTPRequestOperation` instead, as it supports specifying acceptable content types or status codes.
## NSURLConnection Delegate Methods
`AFURLConnectionOperation` implements the following `NSURLConnection` delegate methods:
- `connection:didReceiveResponse:`
- `connection:didReceiveData:`
- `connectionDidFinishLoading:`
- `connection:didFailWithError:`
- `connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:`
- `connection:willCacheResponse:`
- `connectionShouldUseCredentialStorage:`
- `connection:needNewBodyStream:`
- `connection:willSendRequestForAuthenticationChallenge:`
If any of these methods are overridden in a subclass, they _must_ call the `super` implementation first.
## Callbacks and Completion Blocks
The built-in `completionBlock` provided by `NSOperation` allows for custom behavior to be executed after the request finishes. It is a common pattern for class constructors in subclasses to take callback block parameters, and execute them conditionally in the body of its `completionBlock`. Make sure to handle cancelled operations appropriately when setting a `completionBlock` (i.e. returning early before parsing response data). See the implementation of any of the `AFHTTPRequestOperation` subclasses for an example of this.
Subclasses are strongly discouraged from overriding `setCompletionBlock:`, as `AFURLConnectionOperation`'s implementation includes a workaround to mitigate retain cycles, and what Apple rather ominously refers to as ["The Deallocation Problem"](http://developer.apple.com/library/ios/#technotes/tn2109/).
## SSL Pinning
Relying on the CA trust model to validate SSL certificates exposes your app to security vulnerabilities, such as man-in-the-middle attacks. For applications that connect to known servers, SSL certificate pinning provides an increased level of security, by checking server certificate validity against those specified in the app bundle.
SSL with certificate pinning is strongly recommended for any application that transmits sensitive information to an external webservice.
Connections will be validated on all matching certificates with a `.cer` extension in the bundle root.
## NSCoding & NSCopying Conformance
`AFURLConnectionOperation` conforms to the `NSCoding` and `NSCopying` protocols, allowing operations to be archived to disk, and copied in memory, respectively. However, because of the intrinsic limitations of capturing the exact state of an operation at a particular moment, there are some important caveats to keep in mind:
### NSCoding Caveats
- Encoded operations do not include any block or stream properties. Be sure to set `completionBlock`, `outputStream`, and any callback blocks as necessary when using `-initWithCoder:` or `NSKeyedUnarchiver`.
- Operations are paused on `encodeWithCoder:`. If the operation was encoded while paused or still executing, its archived state will return `YES` for `isReady`. Otherwise, the state of an operation when encoding will remain unchanged.
### NSCopying Caveats
- `-copy` and `-copyWithZone:` return a new operation with the `NSURLRequest` of the original. So rather than an exact copy of the operation at that particular instant, the copying mechanism returns a completely new instance, which can be useful for retrying operations.
- A copy of an operation will not include the `outputStream` of the original.
- Operation copies do not include `completionBlock`, as it often strongly captures a reference to `self`, which would otherwise have the unintuitive side-effect of pointing to the _original_ operation when copied.
*/
NS_ASSUME_NONNULL_BEGIN
@interface AFURLConnectionOperation : NSOperation <NSURLConnectionDelegate, NSURLConnectionDataDelegate, NSSecureCoding, NSCopying>
///-------------------------------
/// @name Accessing Run Loop Modes
///-------------------------------
/**
The run loop modes in which the operation will run on the network thread. By default, this is a single-member set containing `NSRunLoopCommonModes`.
*/
@property (nonatomic, strong) NSSet *runLoopModes;
///-----------------------------------------
/// @name Getting URL Connection Information
///-----------------------------------------
/**
The request used by the operation's connection.
*/
@property (readonly, nonatomic, strong) NSURLRequest *request;
/**
The last response received by the operation's connection.
*/
@property (readonly, nonatomic, strong, nullable) NSURLResponse *response;
/**
The error, if any, that occurred in the lifecycle of the request.
*/
@property (readonly, nonatomic, strong, nullable) NSError *error;
///----------------------------
/// @name Getting Response Data
///----------------------------
/**
The data received during the request.
*/
@property (readonly, nonatomic, strong, nullable) NSData *responseData;
/**
The string representation of the response data.
*/
@property (readonly, nonatomic, copy, nullable) NSString *responseString;
/**
The string encoding of the response.
If the response does not specify a valid string encoding, `responseStringEncoding` will return `NSUTF8StringEncoding`.
*/
@property (readonly, nonatomic, assign) NSStringEncoding responseStringEncoding;
///-------------------------------
/// @name Managing URL Credentials
///-------------------------------
/**
Whether the URL connection should consult the credential storage for authenticating the connection. `YES` by default.
This is the value that is returned in the `NSURLConnectionDelegate` method `-connectionShouldUseCredentialStorage:`.
*/
@property (nonatomic, assign) BOOL shouldUseCredentialStorage;
/**
The credential used for authentication challenges in `-connection:didReceiveAuthenticationChallenge:`.
This will be overridden by any shared credentials that exist for the username or password of the request URL, if present.
*/
@property (nonatomic, strong, nullable) NSURLCredential *credential;
///-------------------------------
/// @name Managing Security Policy
///-------------------------------
/**
The security policy used to evaluate server trust for secure connections.
*/
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
///------------------------
/// @name Accessing Streams
///------------------------
/**
The input stream used to read data to be sent during the request.
This property acts as a proxy to the `HTTPBodyStream` property of `request`.
*/
@property (nonatomic, strong) NSInputStream *inputStream;
/**
The output stream that is used to write data received until the request is finished.
By default, data is accumulated into a buffer that is stored into `responseData` upon completion of the request, with the intermediary `outputStream` property set to `nil`. When `outputStream` is set, the data will not be accumulated into an internal buffer, and as a result, the `responseData` property of the completed request will be `nil`. The output stream will be scheduled in the network thread runloop upon being set.
*/
@property (nonatomic, strong, nullable) NSOutputStream *outputStream;
///---------------------------------
/// @name Managing Callback Queues
///---------------------------------
/**
The dispatch queue for `completionBlock`. If `NULL` (default), the main queue is used.
*/
#if OS_OBJECT_USE_OBJC
@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;
#else
@property (nonatomic, assign, nullable) dispatch_queue_t completionQueue;
#endif
/**
The dispatch group for `completionBlock`. If `NULL` (default), a private dispatch group is used.
*/
#if OS_OBJECT_USE_OBJC
@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;
#else
@property (nonatomic, assign, nullable) dispatch_group_t completionGroup;
#endif
///---------------------------------------------
/// @name Managing Request Operation Information
///---------------------------------------------
/**
The user info dictionary for the receiver.
*/
@property (nonatomic, strong) NSDictionary *userInfo;
// FIXME: It doesn't seem that this userInfo is used anywhere in the implementation.
///------------------------------------------------------
/// @name Initializing an AFURLConnectionOperation Object
///------------------------------------------------------
/**
Initializes and returns a newly allocated operation object with a url connection configured with the specified url request.
This is the designated initializer.
@param urlRequest The request object to be used by the operation connection.
*/
- (instancetype)initWithRequest:(NSURLRequest *)urlRequest NS_DESIGNATED_INITIALIZER;
///----------------------------------
/// @name Pausing / Resuming Requests
///----------------------------------
/**
Pauses the execution of the request operation.
A paused operation returns `NO` for `-isReady`, `-isExecuting`, and `-isFinished`. As such, it will remain in an `NSOperationQueue` until it is either cancelled or resumed. Pausing a finished, cancelled, or paused operation has no effect.
*/
- (void)pause;
/**
Whether the request operation is currently paused.
@return `YES` if the operation is currently paused, otherwise `NO`.
*/
- (BOOL)isPaused;
/**
Resumes the execution of the paused request operation.
Pause/Resume behavior varies depending on the underlying implementation for the operation class. In its base implementation, resuming a paused requests restarts the original request. However, since HTTP defines a specification for how to request a specific content range, `AFHTTPRequestOperation` will resume downloading the request from where it left off, instead of restarting the original request.
*/
- (void)resume;
///----------------------------------------------
/// @name Configuring Backgrounding Task Behavior
///----------------------------------------------
/**
Specifies that the operation should continue execution after the app has entered the background, and the expiration handler for that background task.
@param handler A handler to be called shortly before the application’s remaining background time reaches 0. The handler is wrapped in a block that cancels the operation, and cleans up and marks the end of execution, unlike the `handler` parameter in `UIApplication -beginBackgroundTaskWithExpirationHandler:`, which expects this to be done in the handler itself. The handler is called synchronously on the main thread, thus blocking the application’s suspension momentarily while the application is notified.
*/
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
- (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(nullable void (^)(void))handler NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extensions.");
#endif
///---------------------------------
/// @name Setting Progress Callbacks
///---------------------------------
/**
Sets a callback to be called when an undetermined number of bytes have been uploaded to the server.
@param block A block object to be called when an undetermined number of bytes have been uploaded to the server. This block has no return value and takes three arguments: the number of bytes written since the last time the upload progress block was called, the total bytes written, and the total bytes expected to be written during the request, as initially determined by the length of the HTTP body. This block may be called multiple times, and will execute on the main thread.
*/
- (void)setUploadProgressBlock:(nullable void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block;
/**
Sets a callback to be called when an undetermined number of bytes have been downloaded from the server.
@param block A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes three arguments: the number of bytes read since the last time the download progress block was called, the total bytes read, and the total bytes expected to be read during the request, as initially determined by the expected content size of the `NSHTTPURLResponse` object. This block may be called multiple times, and will execute on the main thread.
*/
- (void)setDownloadProgressBlock:(nullable void (^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block;
///-------------------------------------------------
/// @name Setting NSURLConnection Delegate Callbacks
///-------------------------------------------------
/**
Sets a block to be executed when the connection will authenticate a challenge in order to download its request, as handled by the `NSURLConnectionDelegate` method `connection:willSendRequestForAuthenticationChallenge:`.
@param block A block object to be executed when the connection will authenticate a challenge in order to download its request. The block has no return type and takes two arguments: the URL connection object, and the challenge that must be authenticated. This block must invoke one of the challenge-responder methods (NSURLAuthenticationChallengeSender protocol).
If `allowsInvalidSSLCertificate` is set to YES, `connection:willSendRequestForAuthenticationChallenge:` will attempt to have the challenge sender use credentials with invalid SSL certificates.
*/
- (void)setWillSendRequestForAuthenticationChallengeBlock:(nullable void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block;
/**
Sets a block to be executed when the server redirects the request from one URL to another URL, or when the request URL changed by the `NSURLProtocol` subclass handling the request in order to standardize its format, as handled by the `NSURLConnectionDataDelegate` method `connection:willSendRequest:redirectResponse:`.
@param block A block object to be executed when the request URL was changed. The block returns an `NSURLRequest` object, the URL request to redirect, and takes three arguments: the URL connection object, the the proposed redirected request, and the URL response that caused the redirect.
*/
- (void)setRedirectResponseBlock:(nullable NSURLRequest * (^)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse))block;
/**
Sets a block to be executed to modify the response a connection will cache, if any, as handled by the `NSURLConnectionDelegate` method `connection:willCacheResponse:`.
@param block A block object to be executed to determine what response a connection will cache, if any. The block returns an `NSCachedURLResponse` object, the cached response to store in memory or `nil` to prevent the response from being cached, and takes two arguments: the URL connection object, and the cached response provided for the request.
*/
- (void)setCacheResponseBlock:(nullable NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block;
///
/**
*/
+ (NSArray *)batchOfRequestOperations:(nullable NSArray *)operations
progressBlock:(nullable void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock
completionBlock:(nullable void (^)(NSArray *operations))completionBlock;
@end
///--------------------
/// @name Notifications
///--------------------
/**
Posted when an operation begins executing.
*/
FOUNDATION_EXPORT NSString * const AFNetworkingOperationDidStartNotification;
/**
Posted when an operation finishes.
*/
FOUNDATION_EXPORT NSString * const AFNetworkingOperationDidFinishNotification;
NS_ASSUME_NONNULL_END
@@ -1,792 +0,0 @@
// AFURLConnectionOperation.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "AFURLConnectionOperation.h"
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#import <UIKit/UIKit.h>
#endif
#if !__has_feature(objc_arc)
#error AFNetworking must be built with ARC.
// You can turn on ARC for only AFNetworking files by adding -fobjc-arc to the build phase for each of its files.
#endif
typedef NS_ENUM(NSInteger, AFOperationState) {
AFOperationPausedState = -1,
AFOperationReadyState = 1,
AFOperationExecutingState = 2,
AFOperationFinishedState = 3,
};
static dispatch_group_t url_request_operation_completion_group() {
static dispatch_group_t af_url_request_operation_completion_group;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
af_url_request_operation_completion_group = dispatch_group_create();
});
return af_url_request_operation_completion_group;
}
static dispatch_queue_t url_request_operation_completion_queue() {
static dispatch_queue_t af_url_request_operation_completion_queue;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
af_url_request_operation_completion_queue = dispatch_queue_create("com.alamofire.networking.operation.queue", DISPATCH_QUEUE_CONCURRENT );
});
return af_url_request_operation_completion_queue;
}
static NSString * const kAFNetworkingLockName = @"com.alamofire.networking.operation.lock";
NSString * const AFNetworkingOperationDidStartNotification = @"com.alamofire.networking.operation.start";
NSString * const AFNetworkingOperationDidFinishNotification = @"com.alamofire.networking.operation.finish";
typedef void (^AFURLConnectionOperationProgressBlock)(NSUInteger bytes, long long totalBytes, long long totalBytesExpected);
typedef void (^AFURLConnectionOperationAuthenticationChallengeBlock)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge);
typedef NSCachedURLResponse * (^AFURLConnectionOperationCacheResponseBlock)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse);
typedef NSURLRequest * (^AFURLConnectionOperationRedirectResponseBlock)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse);
typedef void (^AFURLConnectionOperationBackgroundTaskCleanupBlock)();
static inline NSString * AFKeyPathFromOperationState(AFOperationState state) {
switch (state) {
case AFOperationReadyState:
return @"isReady";
case AFOperationExecutingState:
return @"isExecuting";
case AFOperationFinishedState:
return @"isFinished";
case AFOperationPausedState:
return @"isPaused";
default: {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
return @"state";
#pragma clang diagnostic pop
}
}
}
static inline BOOL AFStateTransitionIsValid(AFOperationState fromState, AFOperationState toState, BOOL isCancelled) {
switch (fromState) {
case AFOperationReadyState:
switch (toState) {
case AFOperationPausedState:
case AFOperationExecutingState:
return YES;
case AFOperationFinishedState:
return isCancelled;
default:
return NO;
}
case AFOperationExecutingState:
switch (toState) {
case AFOperationPausedState:
case AFOperationFinishedState:
return YES;
default:
return NO;
}
case AFOperationFinishedState:
return NO;
case AFOperationPausedState:
return toState == AFOperationReadyState;
default: {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunreachable-code"
switch (toState) {
case AFOperationPausedState:
case AFOperationReadyState:
case AFOperationExecutingState:
case AFOperationFinishedState:
return YES;
default:
return NO;
}
}
#pragma clang diagnostic pop
}
}
@interface AFURLConnectionOperation ()
@property (readwrite, nonatomic, assign) AFOperationState state;
@property (readwrite, nonatomic, strong) NSRecursiveLock *lock;
@property (readwrite, nonatomic, strong) NSURLConnection *connection;
@property (readwrite, nonatomic, strong) NSURLRequest *request;
@property (readwrite, nonatomic, strong) NSURLResponse *response;
@property (readwrite, nonatomic, strong) NSError *error;
@property (readwrite, nonatomic, strong) NSData *responseData;
@property (readwrite, nonatomic, copy) NSString *responseString;
@property (readwrite, nonatomic, assign) NSStringEncoding responseStringEncoding;
@property (readwrite, nonatomic, assign) long long totalBytesRead;
@property (readwrite, nonatomic, copy) AFURLConnectionOperationBackgroundTaskCleanupBlock backgroundTaskCleanup;
@property (readwrite, nonatomic, copy) AFURLConnectionOperationProgressBlock uploadProgress;
@property (readwrite, nonatomic, copy) AFURLConnectionOperationProgressBlock downloadProgress;
@property (readwrite, nonatomic, copy) AFURLConnectionOperationAuthenticationChallengeBlock authenticationChallenge;
@property (readwrite, nonatomic, copy) AFURLConnectionOperationCacheResponseBlock cacheResponse;
@property (readwrite, nonatomic, copy) AFURLConnectionOperationRedirectResponseBlock redirectResponse;
- (void)operationDidStart;
- (void)finish;
- (void)cancelConnection;
@end
@implementation AFURLConnectionOperation
@synthesize outputStream = _outputStream;
+ (void)networkRequestThreadEntryPoint:(id)__unused object {
@autoreleasepool {
[[NSThread currentThread] setName:@"AFNetworking"];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[runLoop run];
}
}
+ (NSThread *)networkRequestThread {
static NSThread *_networkRequestThread = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_networkRequestThread = [[NSThread alloc] initWithTarget:self selector:@selector(networkRequestThreadEntryPoint:) object:nil];
[_networkRequestThread start];
});
return _networkRequestThread;
}
- (instancetype)initWithRequest:(NSURLRequest *)urlRequest {
NSParameterAssert(urlRequest);
self = [super init];
if (!self) {
return nil;
}
_state = AFOperationReadyState;
self.lock = [[NSRecursiveLock alloc] init];
self.lock.name = kAFNetworkingLockName;
self.runLoopModes = [NSSet setWithObject:NSRunLoopCommonModes];
self.request = urlRequest;
self.shouldUseCredentialStorage = YES;
self.securityPolicy = [AFSecurityPolicy defaultPolicy];
return self;
}
- (instancetype)init NS_UNAVAILABLE
{
return nil;
}
- (void)dealloc {
if (_outputStream) {
[_outputStream close];
_outputStream = nil;
}
if (_backgroundTaskCleanup) {
_backgroundTaskCleanup();
}
}
#pragma mark -
- (void)setResponseData:(NSData *)responseData {
[self.lock lock];
if (!responseData) {
_responseData = nil;
} else {
_responseData = [NSData dataWithBytes:responseData.bytes length:responseData.length];
}
[self.lock unlock];
}
- (NSString *)responseString {
[self.lock lock];
if (!_responseString && self.response && self.responseData) {
self.responseString = [[NSString alloc] initWithData:self.responseData encoding:self.responseStringEncoding];
}
[self.lock unlock];
return _responseString;
}
- (NSStringEncoding)responseStringEncoding {
[self.lock lock];
if (!_responseStringEncoding && self.response) {
NSStringEncoding stringEncoding = NSUTF8StringEncoding;
if (self.response.textEncodingName) {
CFStringEncoding IANAEncoding = CFStringConvertIANACharSetNameToEncoding((__bridge CFStringRef)self.response.textEncodingName);
if (IANAEncoding != kCFStringEncodingInvalidId) {
stringEncoding = CFStringConvertEncodingToNSStringEncoding(IANAEncoding);
}
}
self.responseStringEncoding = stringEncoding;
}
[self.lock unlock];
return _responseStringEncoding;
}
- (NSInputStream *)inputStream {
return self.request.HTTPBodyStream;
}
- (void)setInputStream:(NSInputStream *)inputStream {
NSMutableURLRequest *mutableRequest = [self.request mutableCopy];
mutableRequest.HTTPBodyStream = inputStream;
self.request = mutableRequest;
}
- (NSOutputStream *)outputStream {
if (!_outputStream) {
self.outputStream = [NSOutputStream outputStreamToMemory];
}
return _outputStream;
}
- (void)setOutputStream:(NSOutputStream *)outputStream {
[self.lock lock];
if (outputStream != _outputStream) {
if (_outputStream) {
[_outputStream close];
}
_outputStream = outputStream;
}
[self.lock unlock];
}
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
- (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler {
[self.lock lock];
if (!self.backgroundTaskCleanup) {
UIApplication *application = [UIApplication sharedApplication];
UIBackgroundTaskIdentifier __block backgroundTaskIdentifier = UIBackgroundTaskInvalid;
__weak __typeof(self)weakSelf = self;
self.backgroundTaskCleanup = ^(){
if (backgroundTaskIdentifier != UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:backgroundTaskIdentifier];
backgroundTaskIdentifier = UIBackgroundTaskInvalid;
}
};
backgroundTaskIdentifier = [application beginBackgroundTaskWithExpirationHandler:^{
__strong __typeof(weakSelf)strongSelf = weakSelf;
if (handler) {
handler();
}
if (strongSelf) {
[strongSelf cancel];
strongSelf.backgroundTaskCleanup();
}
}];
}
[self.lock unlock];
}
#endif
#pragma mark -
- (void)setState:(AFOperationState)state {
if (!AFStateTransitionIsValid(self.state, state, [self isCancelled])) {
return;
}
[self.lock lock];
NSString *oldStateKey = AFKeyPathFromOperationState(self.state);
NSString *newStateKey = AFKeyPathFromOperationState(state);
[self willChangeValueForKey:newStateKey];
[self willChangeValueForKey:oldStateKey];
_state = state;
[self didChangeValueForKey:oldStateKey];
[self didChangeValueForKey:newStateKey];
[self.lock unlock];
}
- (void)pause {
if ([self isPaused] || [self isFinished] || [self isCancelled]) {
return;
}
[self.lock lock];
if ([self isExecuting]) {
[self performSelector:@selector(operationDidPause) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
dispatch_async(dispatch_get_main_queue(), ^{
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter postNotificationName:AFNetworkingOperationDidFinishNotification object:self];
});
}
self.state = AFOperationPausedState;
[self.lock unlock];
}
- (void)operationDidPause {
[self.lock lock];
[self.connection cancel];
[self.lock unlock];
}
- (BOOL)isPaused {
return self.state == AFOperationPausedState;
}
- (void)resume {
if (![self isPaused]) {
return;
}
[self.lock lock];
self.state = AFOperationReadyState;
[self start];
[self.lock unlock];
}
#pragma mark -
- (void)setUploadProgressBlock:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block {
self.uploadProgress = block;
}
- (void)setDownloadProgressBlock:(void (^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block {
self.downloadProgress = block;
}
- (void)setWillSendRequestForAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block {
self.authenticationChallenge = block;
}
- (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block {
self.cacheResponse = block;
}
- (void)setRedirectResponseBlock:(NSURLRequest * (^)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse))block {
self.redirectResponse = block;
}
#pragma mark - NSOperation
- (void)setCompletionBlock:(void (^)(void))block {
[self.lock lock];
if (!block) {
[super setCompletionBlock:nil];
} else {
__weak __typeof(self)weakSelf = self;
[super setCompletionBlock:^ {
__strong __typeof(weakSelf)strongSelf = weakSelf;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
dispatch_group_t group = strongSelf.completionGroup ?: url_request_operation_completion_group();
dispatch_queue_t queue = strongSelf.completionQueue ?: dispatch_get_main_queue();
#pragma clang diagnostic pop
dispatch_group_async(group, queue, ^{
block();
});
dispatch_group_notify(group, url_request_operation_completion_queue(), ^{
[strongSelf setCompletionBlock:nil];
});
}];
}
[self.lock unlock];
}
- (BOOL)isReady {
return self.state == AFOperationReadyState && [super isReady];
}
- (BOOL)isExecuting {
return self.state == AFOperationExecutingState;
}
- (BOOL)isFinished {
return self.state == AFOperationFinishedState;
}
- (BOOL)isConcurrent {
return YES;
}
- (void)start {
[self.lock lock];
if ([self isCancelled]) {
[self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
} else if ([self isReady]) {
self.state = AFOperationExecutingState;
[self performSelector:@selector(operationDidStart) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
}
[self.lock unlock];
}
- (void)operationDidStart {
[self.lock lock];
if (![self isCancelled]) {
self.connection = [[NSURLConnection alloc] initWithRequest:self.request delegate:self startImmediately:NO];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
for (NSString *runLoopMode in self.runLoopModes) {
[self.connection scheduleInRunLoop:runLoop forMode:runLoopMode];
[self.outputStream scheduleInRunLoop:runLoop forMode:runLoopMode];
}
[self.outputStream open];
[self.connection start];
}
[self.lock unlock];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidStartNotification object:self];
});
}
- (void)finish {
[self.lock lock];
self.state = AFOperationFinishedState;
[self.lock unlock];
dispatch_async(dispatch_get_main_queue(), ^{
[[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingOperationDidFinishNotification object:self];
});
}
- (void)cancel {
[self.lock lock];
if (![self isFinished] && ![self isCancelled]) {
[super cancel];
if ([self isExecuting]) {
[self performSelector:@selector(cancelConnection) onThread:[[self class] networkRequestThread] withObject:nil waitUntilDone:NO modes:[self.runLoopModes allObjects]];
}
}
[self.lock unlock];
}
- (void)cancelConnection {
NSDictionary *userInfo = nil;
if ([self.request URL]) {
userInfo = @{NSURLErrorFailingURLErrorKey : [self.request URL]};
}
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:userInfo];
if (![self isFinished]) {
if (self.connection) {
[self.connection cancel];
[self performSelector:@selector(connection:didFailWithError:) withObject:self.connection withObject:error];
} else {
// Accommodate race condition where `self.connection` has not yet been set before cancellation
self.error = error;
[self finish];
}
}
}
#pragma mark -
+ (NSArray *)batchOfRequestOperations:(NSArray *)operations
progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock
completionBlock:(void (^)(NSArray *operations))completionBlock
{
if (!operations || [operations count] == 0) {
return @[[NSBlockOperation blockOperationWithBlock:^{
dispatch_async(dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(@[]);
}
});
}]];
}
__block dispatch_group_t group = dispatch_group_create();
NSBlockOperation *batchedOperation = [NSBlockOperation blockOperationWithBlock:^{
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(operations);
}
});
}];
for (AFURLConnectionOperation *operation in operations) {
operation.completionGroup = group;
void (^originalCompletionBlock)(void) = [operation.completionBlock copy];
__weak __typeof(operation)weakOperation = operation;
operation.completionBlock = ^{
__strong __typeof(weakOperation)strongOperation = weakOperation;
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
dispatch_queue_t queue = strongOperation.completionQueue ?: dispatch_get_main_queue();
#pragma clang diagnostic pop
dispatch_group_async(group, queue, ^{
if (originalCompletionBlock) {
originalCompletionBlock();
}
NSUInteger numberOfFinishedOperations = [[operations indexesOfObjectsPassingTest:^BOOL(id op, NSUInteger __unused idx, BOOL __unused *stop) {
return [op isFinished];
}] count];
if (progressBlock) {
progressBlock(numberOfFinishedOperations, [operations count]);
}
dispatch_group_leave(group);
});
};
dispatch_group_enter(group);
[batchedOperation addDependency:operation];
}
return [operations arrayByAddingObject:batchedOperation];
}
#pragma mark - NSObject
- (NSString *)description {
[self.lock lock];
NSString *description = [NSString stringWithFormat:@"<%@: %p, state: %@, cancelled: %@ request: %@, response: %@>", NSStringFromClass([self class]), self, AFKeyPathFromOperationState(self.state), ([self isCancelled] ? @"YES" : @"NO"), self.request, self.response];
[self.lock unlock];
return description;
}
#pragma mark - NSURLConnectionDelegate
- (void)connection:(NSURLConnection *)connection
willSendRequestForAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge
{
if (self.authenticationChallenge) {
self.authenticationChallenge(connection, challenge);
return;
}
if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) {
if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) {
NSURLCredential *credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust];
[[challenge sender] useCredential:credential forAuthenticationChallenge:challenge];
} else {
[[challenge sender] cancelAuthenticationChallenge:challenge];
}
} else {
if ([challenge previousFailureCount] == 0) {
if (self.credential) {
[[challenge sender] useCredential:self.credential forAuthenticationChallenge:challenge];
} else {
[[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
}
} else {
[[challenge sender] continueWithoutCredentialForAuthenticationChallenge:challenge];
}
}
}
- (BOOL)connectionShouldUseCredentialStorage:(NSURLConnection __unused *)connection {
return self.shouldUseCredentialStorage;
}
- (NSURLRequest *)connection:(NSURLConnection *)connection
willSendRequest:(NSURLRequest *)request
redirectResponse:(NSURLResponse *)redirectResponse
{
if (self.redirectResponse) {
return self.redirectResponse(connection, request, redirectResponse);
} else {
return request;
}
}
- (void)connection:(NSURLConnection __unused *)connection
didSendBodyData:(NSInteger)bytesWritten
totalBytesWritten:(NSInteger)totalBytesWritten
totalBytesExpectedToWrite:(NSInteger)totalBytesExpectedToWrite
{
dispatch_async(dispatch_get_main_queue(), ^{
if (self.uploadProgress) {
self.uploadProgress((NSUInteger)bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
}
});
}
- (void)connection:(NSURLConnection __unused *)connection
didReceiveResponse:(NSURLResponse *)response
{
self.response = response;
}
- (void)connection:(NSURLConnection __unused *)connection
didReceiveData:(NSData *)data
{
NSUInteger length = [data length];
while (YES) {
NSInteger totalNumberOfBytesWritten = 0;
if ([self.outputStream hasSpaceAvailable]) {
const uint8_t *dataBuffer = (uint8_t *)[data bytes];
NSInteger numberOfBytesWritten = 0;
while (totalNumberOfBytesWritten < (NSInteger)length) {
numberOfBytesWritten = [self.outputStream write:&dataBuffer[(NSUInteger)totalNumberOfBytesWritten] maxLength:(length - (NSUInteger)totalNumberOfBytesWritten)];
if (numberOfBytesWritten == -1) {
break;
}
totalNumberOfBytesWritten += numberOfBytesWritten;
}
break;
} else {
[self.connection cancel];
if (self.outputStream.streamError) {
[self performSelector:@selector(connection:didFailWithError:) withObject:self.connection withObject:self.outputStream.streamError];
}
return;
}
}
dispatch_async(dispatch_get_main_queue(), ^{
self.totalBytesRead += (long long)length;
if (self.downloadProgress) {
self.downloadProgress(length, self.totalBytesRead, self.response.expectedContentLength);
}
});
}
- (void)connectionDidFinishLoading:(NSURLConnection __unused *)connection {
self.responseData = [self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey];
[self.outputStream close];
if (self.responseData) {
self.outputStream = nil;
}
self.connection = nil;
[self finish];
}
- (void)connection:(NSURLConnection __unused *)connection
didFailWithError:(NSError *)error
{
self.error = error;
[self.outputStream close];
if (self.responseData) {
self.outputStream = nil;
}
self.connection = nil;
[self finish];
}
- (NSCachedURLResponse *)connection:(NSURLConnection *)connection
willCacheResponse:(NSCachedURLResponse *)cachedResponse
{
if (self.cacheResponse) {
return self.cacheResponse(connection, cachedResponse);
} else {
if ([self isCancelled]) {
return nil;
}
return cachedResponse;
}
}
#pragma mark - NSSecureCoding
+ (BOOL)supportsSecureCoding {
return YES;
}
- (id)initWithCoder:(NSCoder *)decoder {
NSURLRequest *request = [decoder decodeObjectOfClass:[NSURLRequest class] forKey:NSStringFromSelector(@selector(request))];
self = [self initWithRequest:request];
if (!self) {
return nil;
}
self.state = (AFOperationState)[[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(state))] integerValue];
self.response = [decoder decodeObjectOfClass:[NSHTTPURLResponse class] forKey:NSStringFromSelector(@selector(response))];
self.error = [decoder decodeObjectOfClass:[NSError class] forKey:NSStringFromSelector(@selector(error))];
self.responseData = [decoder decodeObjectOfClass:[NSData class] forKey:NSStringFromSelector(@selector(responseData))];
self.totalBytesRead = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(totalBytesRead))] longLongValue];
return self;
}
- (void)encodeWithCoder:(NSCoder *)coder {
[self pause];
[coder encodeObject:self.request forKey:NSStringFromSelector(@selector(request))];
switch (self.state) {
case AFOperationExecutingState:
case AFOperationPausedState:
[coder encodeInteger:AFOperationReadyState forKey:NSStringFromSelector(@selector(state))];
break;
default:
[coder encodeInteger:self.state forKey:NSStringFromSelector(@selector(state))];
break;
}
[coder encodeObject:self.response forKey:NSStringFromSelector(@selector(response))];
[coder encodeObject:self.error forKey:NSStringFromSelector(@selector(error))];
[coder encodeObject:self.responseData forKey:NSStringFromSelector(@selector(responseData))];
[coder encodeInt64:self.totalBytesRead forKey:NSStringFromSelector(@selector(totalBytesRead))];
}
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
AFURLConnectionOperation *operation = [(AFURLConnectionOperation *)[[self class] allocWithZone:zone] initWithRequest:self.request];
operation.uploadProgress = self.uploadProgress;
operation.downloadProgress = self.downloadProgress;
operation.authenticationChallenge = self.authenticationChallenge;
operation.cacheResponse = self.cacheResponse;
operation.redirectResponse = self.redirectResponse;
operation.completionQueue = self.completionQueue;
operation.completionGroup = self.completionGroup;
return operation;
}
@end
@@ -1,5 +1,5 @@
// AFURLRequestSerialization.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -20,7 +20,9 @@
// THE SOFTWARE.
#import <Foundation/Foundation.h>
#if TARGET_OS_IOS
#import <TargetConditionals.h>
#if TARGET_OS_IOS || TARGET_OS_TV
#import <UIKit/UIKit.h>
#elif TARGET_OS_WATCH
#import <WatchKit/WatchKit.h>
@@ -28,6 +30,31 @@
NS_ASSUME_NONNULL_BEGIN
/**
Returns a percent-escaped string following RFC 3986 for a query string key or value.
RFC 3986 states that the following characters are "reserved" characters.
- General Delimiters: ":", "#", "[", "]", "@", "?", "/"
- Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
should be percent-escaped in the query string.
@param string The string to be percent-escaped.
@return The percent-escaped string.
*/
FOUNDATION_EXPORT NSString * AFPercentEscapedStringFromString(NSString *string);
/**
A helper method to generate encoded url query parameters for appending to the end of a URL.
@param parameters A dictionary of key/values to be encoded.
@return A url encoded query string
*/
FOUNDATION_EXPORT NSString * AFQueryStringFromParameters(NSDictionary *parameters);
/**
The `AFURLRequestSerialization` protocol is adopted by an object that encodes parameters for a specified HTTP requests. Request serializers may encode parameters as query strings, HTTP bodies, setting the appropriate HTTP header fields as necessary.
@@ -46,11 +73,8 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (nullable NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(nullable id)parameters
error:(NSError * __nullable __autoreleasing *)error
#ifdef NS_SWIFT_NOTHROW
NS_SWIFT_NOTHROW
#endif
;
error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;
@end
#pragma mark -
@@ -130,7 +154,7 @@ typedef NS_ENUM(NSUInteger, AFHTTPRequestQueryStringSerializationStyle) {
@discussion To add or remove default request headers, use `setValue:forHTTPHeaderField:`.
*/
@property (readonly, nonatomic, strong) NSDictionary *HTTPRequestHeaders;
@property (readonly, nonatomic, strong) NSDictionary <NSString *, NSString *> *HTTPRequestHeaders;
/**
Creates and returns a serializer with default configuration.
@@ -164,12 +188,6 @@ forHTTPHeaderField:(NSString *)field;
- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username
password:(NSString *)password;
/**
@deprecated This method has been deprecated. Use -setValue:forHTTPHeaderField: instead.
*/
- (void)setAuthorizationHeaderFieldWithToken:(NSString *)token DEPRECATED_ATTRIBUTE;
/**
Clears any existing value for the "Authorization" HTTP header.
*/
@@ -182,7 +200,7 @@ forHTTPHeaderField:(NSString *)field;
/**
HTTP methods for which serialized requests will encode parameters as a query string. `GET`, `HEAD`, and `DELETE` by default.
*/
@property (nonatomic, strong) NSSet *HTTPMethodsEncodingParametersInURI;
@property (nonatomic, strong) NSSet <NSString *> *HTTPMethodsEncodingParametersInURI;
/**
Set the method of query string serialization according to one of the pre-defined styles.
@@ -204,13 +222,6 @@ forHTTPHeaderField:(NSString *)field;
/// @name Creating Request Objects
///-------------------------------
/**
@deprecated This method has been deprecated. Use -requestWithMethod:URLString:parameters:error: instead.
*/
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters DEPRECATED_ATTRIBUTE;
/**
Creates an `NSMutableURLRequest` object with the specified HTTP method and URL string.
@@ -226,15 +237,7 @@ forHTTPHeaderField:(NSString *)field;
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(nullable id)parameters
error:(NSError * __nullable __autoreleasing *)error;
/**
@deprecated This method has been deprecated. Use -multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:error: instead.
*/
- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(NSDictionary *)parameters
constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block DEPRECATED_ATTRIBUTE;
error:(NSError * _Nullable __autoreleasing *)error;
/**
Creates an `NSMutableURLRequest` object with the specified HTTP method and URLString, and constructs a `multipart/form-data` HTTP body, using the specified parameters and multipart form data block. See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2
@@ -251,9 +254,9 @@ forHTTPHeaderField:(NSString *)field;
*/
- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(nullable NSDictionary *)parameters
parameters:(nullable NSDictionary <NSString *, id> *)parameters
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
error:(NSError * __nullable __autoreleasing *)error;
error:(NSError * _Nullable __autoreleasing *)error;
/**
Creates an `NSMutableURLRequest` by removing the `HTTPBodyStream` from a request, and asynchronously writing its contents into the specified file, invoking the completion handler when finished.
@@ -268,7 +271,7 @@ forHTTPHeaderField:(NSString *)field;
*/
- (NSMutableURLRequest *)requestWithMultipartFormRequest:(NSURLRequest *)request
writingStreamContentsToFile:(NSURL *)fileURL
completionHandler:(nullable void (^)(NSError * __nullable error))handler;
completionHandler:(nullable void (^)(NSError * _Nullable error))handler;
@end
@@ -292,7 +295,7 @@ forHTTPHeaderField:(NSString *)field;
*/
- (BOOL)appendPartWithFileURL:(NSURL *)fileURL
name:(NSString *)name
error:(NSError * __nullable __autoreleasing *)error;
error:(NSError * _Nullable __autoreleasing *)error;
/**
Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary.
@@ -309,7 +312,7 @@ forHTTPHeaderField:(NSString *)field;
name:(NSString *)name
fileName:(NSString *)fileName
mimeType:(NSString *)mimeType
error:(NSError * __nullable __autoreleasing *)error;
error:(NSError * _Nullable __autoreleasing *)error;
/**
Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the data from the input stream and the multipart form boundary.
@@ -356,7 +359,7 @@ forHTTPHeaderField:(NSString *)field;
@param headers The HTTP headers to be appended to the form data.
@param body The data to be encoded and appended to the form data. This parameter must not be `nil`.
*/
- (void)appendPartWithHeaders:(nullable NSDictionary *)headers
- (void)appendPartWithHeaders:(nullable NSDictionary <NSString *, NSString *> *)headers
body:(NSData *)body;
/**
@@ -1,5 +1,5 @@
// AFURLRequestSerialization.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -21,7 +21,7 @@
#import "AFURLRequestSerialization.h"
#if __IPHONE_OS_VERSION_MIN_REQUIRED
#if TARGET_OS_IOS || TARGET_OS_WATCH || TARGET_OS_TV
#import <MobileCoreServices/MobileCoreServices.h>
#else
#import <CoreServices/CoreServices.h>
@@ -32,35 +32,6 @@ NSString * const AFNetworkingOperationFailingURLRequestErrorKey = @"com.alamofir
typedef NSString * (^AFQueryStringSerializationBlock)(NSURLRequest *request, id parameters, NSError *__autoreleasing *error);
static NSString * AFBase64EncodedStringFromString(NSString *string) {
NSData *data = [NSData dataWithBytes:[string UTF8String] length:[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
NSUInteger length = [data length];
NSMutableData *mutableData = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
uint8_t *input = (uint8_t *)[data bytes];
uint8_t *output = (uint8_t *)[mutableData mutableBytes];
for (NSUInteger i = 0; i < length; i += 3) {
NSUInteger value = 0;
for (NSUInteger j = i; j < (i + 3); j++) {
value <<= 8;
if (j < length) {
value |= (0xFF & input[j]);
}
}
static uint8_t const kAFBase64EncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
NSUInteger idx = (i / 3) * 4;
output[idx + 0] = kAFBase64EncodingTable[(value >> 18) & 0x3F];
output[idx + 1] = kAFBase64EncodingTable[(value >> 12) & 0x3F];
output[idx + 2] = (i + 1) < length ? kAFBase64EncodingTable[(value >> 6) & 0x3F] : '=';
output[idx + 3] = (i + 2) < length ? kAFBase64EncodingTable[(value >> 0) & 0x3F] : '=';
}
return [[NSString alloc] initWithData:mutableData encoding:NSASCIIStringEncoding];
}
/**
Returns a percent-escaped string following RFC 3986 for a query string key or value.
RFC 3986 states that the following characters are "reserved" characters.
@@ -73,7 +44,7 @@ static NSString * AFBase64EncodedStringFromString(NSString *string) {
- parameter string: The string to be percent-escaped.
- returns: The percent-escaped string.
*/
static NSString * AFPercentEscapedStringFromString(NSString *string) {
NSString * AFPercentEscapedStringFromString(NSString *string) {
static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;=";
@@ -114,14 +85,14 @@ static NSString * AFPercentEscapedStringFromString(NSString *string) {
@property (readwrite, nonatomic, strong) id field;
@property (readwrite, nonatomic, strong) id value;
- (id)initWithField:(id)field value:(id)value;
- (instancetype)initWithField:(id)field value:(id)value;
- (NSString *)URLEncodedStringValue;
@end
@implementation AFQueryStringPair
- (id)initWithField:(id)field value:(id)value {
- (instancetype)initWithField:(id)field value:(id)value {
self = [super init];
if (!self) {
return nil;
@@ -148,7 +119,7 @@ static NSString * AFPercentEscapedStringFromString(NSString *string) {
FOUNDATION_EXPORT NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary);
FOUNDATION_EXPORT NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value);
static NSString * AFQueryStringFromParameters(NSDictionary *parameters) {
NSString * AFQueryStringFromParameters(NSDictionary *parameters) {
NSMutableArray *mutablePairs = [NSMutableArray array];
for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
[mutablePairs addObject:[pair URLEncodedStringValue]];
@@ -351,12 +322,9 @@ forHTTPHeaderField:(NSString *)field
- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username
password:(NSString *)password
{
NSString *basicAuthCredentials = [NSString stringWithFormat:@"%@:%@", username, password];
[self setValue:[NSString stringWithFormat:@"Basic %@", AFBase64EncodedStringFromString(basicAuthCredentials)] forHTTPHeaderField:@"Authorization"];
}
- (void)setAuthorizationHeaderFieldWithToken:(NSString *)token {
[self setValue:[NSString stringWithFormat:@"Token token=\"%@\"", token] forHTTPHeaderField:@"Authorization"];
NSData *basicAuthCredentials = [[NSString stringWithFormat:@"%@:%@", username, password] dataUsingEncoding:NSUTF8StringEncoding];
NSString *base64AuthCredentials = [basicAuthCredentials base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0];
[self setValue:[NSString stringWithFormat:@"Basic %@", base64AuthCredentials] forHTTPHeaderField:@"Authorization"];
}
- (void)clearAuthorizationHeader {
@@ -376,13 +344,6 @@ forHTTPHeaderField:(NSString *)field
#pragma mark -
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
{
return [self requestWithMethod:method URLString:URLString parameters:parameters error:nil];
}
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
@@ -409,14 +370,6 @@ forHTTPHeaderField:(NSString *)field
return mutableRequest;
}
- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(NSDictionary *)parameters
constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
{
return [self multipartFormRequestWithMethod:method URLString:URLString parameters:parameters constructingBodyWithBlock:block error:nil];
}
- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(NSDictionary *)parameters
@@ -547,7 +500,7 @@ forHTTPHeaderField:(NSString *)field
}
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
if (query) {
if (query && query.length > 0) {
mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]];
}
} else {
@@ -594,7 +547,7 @@ forHTTPHeaderField:(NSString *)field
return YES;
}
- (id)initWithCoder:(NSCoder *)decoder {
- (instancetype)initWithCoder:(NSCoder *)decoder {
self = [self init];
if (!self) {
return nil;
@@ -613,7 +566,7 @@ forHTTPHeaderField:(NSString *)field
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
- (instancetype)copyWithZone:(NSZone *)zone {
AFHTTPRequestSerializer *serializer = [[[self class] allocWithZone:zone] init];
serializer.mutableHTTPRequestHeaders = [self.mutableHTTPRequestHeaders mutableCopyWithZone:zone];
serializer.queryStringSerializationStyle = self.queryStringSerializationStyle;
@@ -645,7 +598,6 @@ static inline NSString * AFMultipartFormFinalBoundary(NSString *boundary) {
}
static inline NSString * AFContentTypeForPathExtension(NSString *extension) {
#ifdef __UTTYPE__
NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL);
NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)UTI, kUTTagClassMIMEType);
if (!contentType) {
@@ -653,10 +605,6 @@ static inline NSString * AFContentTypeForPathExtension(NSString *extension) {
} else {
return contentType;
}
#else
#pragma unused (extension)
return @"application/octet-stream";
#endif
}
NSUInteger const kAFUploadStream3GSuggestedPacketSize = 1024 * 16;
@@ -687,7 +635,7 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
@property (readonly, nonatomic, assign) unsigned long long contentLength;
@property (readonly, nonatomic, assign, getter = isEmpty) BOOL empty;
- (id)initWithStringEncoding:(NSStringEncoding)encoding;
- (instancetype)initWithStringEncoding:(NSStringEncoding)encoding;
- (void)setInitialAndFinalBoundaries;
- (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart;
@end
@@ -703,8 +651,8 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
@implementation AFStreamingMultipartFormData
- (id)initWithURLRequest:(NSMutableURLRequest *)urlRequest
stringEncoding:(NSStringEncoding)encoding
- (instancetype)initWithURLRequest:(NSMutableURLRequest *)urlRequest
stringEncoding:(NSStringEncoding)encoding
{
self = [super init];
if (!self) {
@@ -896,7 +844,7 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
@synthesize streamError;
#pragma clang diagnostic pop
- (id)initWithStringEncoding:(NSStringEncoding)encoding {
- (instancetype)initWithStringEncoding:(NSStringEncoding)encoding {
self = [super init];
if (!self) {
return nil;
@@ -948,7 +896,7 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
break;
}
} else {
NSUInteger maxLength = length - (NSUInteger)totalNumberOfBytesRead;
NSUInteger maxLength = MIN(length, self.numberOfBytesInPacket) - (NSUInteger)totalNumberOfBytesRead;
NSInteger numberOfBytesRead = [self.currentHTTPBodyPart read:&buffer[totalNumberOfBytesRead] maxLength:maxLength];
if (numberOfBytesRead == -1) {
self.streamError = self.currentHTTPBodyPart.inputStream.streamError;
@@ -1039,7 +987,7 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
#pragma mark - NSCopying
-(id)copyWithZone:(NSZone *)zone {
- (instancetype)copyWithZone:(NSZone *)zone {
AFMultipartBodyStream *bodyStreamCopy = [[[self class] allocWithZone:zone] initWithStringEncoding:self.stringEncoding];
for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
@@ -1076,7 +1024,7 @@ typedef enum {
@implementation AFHTTPBodyPart
- (id)init {
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
@@ -1254,7 +1202,7 @@ typedef enum {
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
- (instancetype)copyWithZone:(NSZone *)zone {
AFHTTPBodyPart *bodyPart = [[[self class] allocWithZone:zone] init];
bodyPart.stringEncoding = self.stringEncoding;
@@ -1317,7 +1265,7 @@ typedef enum {
#pragma mark - NSSecureCoding
- (id)initWithCoder:(NSCoder *)decoder {
- (instancetype)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:decoder];
if (!self) {
return nil;
@@ -1336,7 +1284,7 @@ typedef enum {
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
- (instancetype)copyWithZone:(NSZone *)zone {
AFJSONRequestSerializer *serializer = [super copyWithZone:zone];
serializer.writingOptions = self.writingOptions;
@@ -1396,7 +1344,7 @@ typedef enum {
#pragma mark - NSSecureCoding
- (id)initWithCoder:(NSCoder *)decoder {
- (instancetype)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:decoder];
if (!self) {
return nil;
@@ -1417,7 +1365,7 @@ typedef enum {
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
- (instancetype)copyWithZone:(NSZone *)zone {
AFPropertyListRequestSerializer *serializer = [super copyWithZone:zone];
serializer.format = self.format;
serializer.writeOptions = self.writeOptions;
@@ -1,5 +1,5 @@
// AFURLResponseSerialization.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -42,11 +42,7 @@ NS_ASSUME_NONNULL_BEGIN
*/
- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response
data:(nullable NSData *)data
error:(NSError * __nullable __autoreleasing *)error
#ifdef NS_SWIFT_NOTHROW
NS_SWIFT_NOTHROW
#endif
;
error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;
@end
@@ -85,7 +81,7 @@ NS_SWIFT_NOTHROW
/**
The acceptable MIME types for responses. When non-`nil`, responses with a `Content-Type` with MIME types that do not intersect with the set will result in an error during validation.
*/
@property (nonatomic, copy, nullable) NSSet *acceptableContentTypes;
@property (nonatomic, copy, nullable) NSSet <NSString *> *acceptableContentTypes;
/**
Validates the specified response and data.
@@ -100,7 +96,7 @@ NS_SWIFT_NOTHROW
*/
- (BOOL)validateResponse:(nullable NSHTTPURLResponse *)response
data:(nullable NSData *)data
error:(NSError * __nullable __autoreleasing *)error;
error:(NSError * _Nullable __autoreleasing *)error;
@end
@@ -239,7 +235,7 @@ NS_SWIFT_NOTHROW
*/
@interface AFImageResponseSerializer : AFHTTPResponseSerializer
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
/**
The scale factor used when interpreting the image data to construct `responseImage`. Specifying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the size property. This is set to the value of scale of the main screen by default, which automatically scales images for retina displays, for instance.
*/
@@ -263,14 +259,14 @@ NS_SWIFT_NOTHROW
/**
The component response serializers.
*/
@property (readonly, nonatomic, copy) NSArray *responseSerializers;
@property (readonly, nonatomic, copy) NSArray <id<AFURLResponseSerialization>> *responseSerializers;
/**
Creates and returns a compound serializer comprised of the specified response serializers.
@warning Each response serializer specified must be a subclass of `AFHTTPResponseSerializer`, and response to `-validateResponse:data:error:`.
*/
+ (instancetype)compoundSerializerWithResponseSerializers:(NSArray *)responseSerializers;
+ (instancetype)compoundSerializerWithResponseSerializers:(NSArray <id<AFURLResponseSerialization>> *)responseSerializers;
@end
@@ -1,5 +1,5 @@
// AFURLResponseSerialization.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -21,6 +21,8 @@
#import "AFURLResponseSerialization.h"
#import <TargetConditionals.h>
#if TARGET_OS_IOS
#import <UIKit/UIKit.h>
#elif TARGET_OS_WATCH
@@ -113,7 +115,9 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
NSError *validationError = nil;
if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) {
if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]]) {
if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]] &&
!([response MIMEType] == nil && [data length] == 0)) {
if ([data length] > 0 && [response URL]) {
NSMutableDictionary *mutableUserInfo = [@{
NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]],
@@ -171,7 +175,7 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
return YES;
}
- (id)initWithCoder:(NSCoder *)decoder {
- (instancetype)initWithCoder:(NSCoder *)decoder {
self = [self init];
if (!self) {
return nil;
@@ -190,7 +194,7 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
- (instancetype)copyWithZone:(NSZone *)zone {
AFHTTPResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
serializer.acceptableStatusCodes = [self.acceptableStatusCodes copyWithZone:zone];
serializer.acceptableContentTypes = [self.acceptableContentTypes copyWithZone:zone];
@@ -238,40 +242,15 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
}
}
// Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization.
// See https://github.com/rails/rails/issues/1742
NSStringEncoding stringEncoding = self.stringEncoding;
if (response.textEncodingName) {
CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName);
if (encoding != kCFStringEncodingInvalidId) {
stringEncoding = CFStringConvertEncodingToNSStringEncoding(encoding);
}
}
id responseObject = nil;
NSError *serializationError = nil;
@autoreleasepool {
NSString *responseString = [[NSString alloc] initWithData:data encoding:stringEncoding];
if (responseString && ![responseString isEqualToString:@" "]) {
// Workaround for a bug in NSJSONSerialization when Unicode character escape codes are used instead of the actual character
// See http://stackoverflow.com/a/12843465/157142
data = [responseString dataUsingEncoding:NSUTF8StringEncoding];
if (data) {
if ([data length] > 0) {
responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
} else {
return nil;
}
} else {
NSDictionary *userInfo = @{
NSLocalizedDescriptionKey: NSLocalizedStringFromTable(@"Data failed decoding as a UTF-8 string", @"AFNetworking", nil),
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Could not decode string: %@", @"AFNetworking", nil), responseString]
};
serializationError = [NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo];
}
}
// Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization.
// See https://github.com/rails/rails/issues/1742
BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
if (data.length > 0 && !isSpace) {
responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
} else {
return nil;
}
if (self.removesKeysWithNullValues && responseObject) {
@@ -287,7 +266,7 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
#pragma mark - NSSecureCoding
- (id)initWithCoder:(NSCoder *)decoder {
- (instancetype)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:decoder];
if (!self) {
return nil;
@@ -308,7 +287,7 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
- (instancetype)copyWithZone:(NSZone *)zone {
AFJSONResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
serializer.readingOptions = self.readingOptions;
serializer.removesKeysWithNullValues = self.removesKeysWithNullValues;
@@ -408,7 +387,7 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
#pragma mark - NSSecureCoding
- (id)initWithCoder:(NSCoder *)decoder {
- (instancetype)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:decoder];
if (!self) {
return nil;
@@ -427,7 +406,7 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
- (instancetype)copyWithZone:(NSZone *)zone {
AFXMLDocumentResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
serializer.options = self.options;
@@ -495,7 +474,7 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
#pragma mark - NSSecureCoding
- (id)initWithCoder:(NSCoder *)decoder {
- (instancetype)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:decoder];
if (!self) {
return nil;
@@ -516,7 +495,7 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
- (instancetype)copyWithZone:(NSZone *)zone {
AFPropertyListResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
serializer.format = self.format;
serializer.readOptions = self.readOptions;
@@ -528,8 +507,9 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
#pragma mark -
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
#import <CoreGraphics/CoreGraphics.h>
#import <UIKit/UIKit.h>
@interface UIImage (AFNetworkingSafeImageLoading)
+ (UIImage *)af_safeImageWithData:(NSData *)data;
@@ -667,10 +647,10 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"image/tiff", @"image/jpeg", @"image/gif", @"image/png", @"image/ico", @"image/x-icon", @"image/bmp", @"image/x-bmp", @"image/x-xbitmap", @"image/x-win-bitmap", nil];
#if TARGET_OS_IOS
#if TARGET_OS_IOS || TARGET_OS_TV
self.imageScale = [[UIScreen mainScreen] scale];
self.automaticallyInflatesResponseImage = YES;
#elif TARGET_OS_WATCH
#elif TARGET_OS_WATCH
self.imageScale = [[WKInterfaceDevice currentDevice] screenScale];
self.automaticallyInflatesResponseImage = YES;
#endif
@@ -690,13 +670,13 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
}
}
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
if (self.automaticallyInflatesResponseImage) {
return AFInflatedImageFromResponseWithDataAtScale((NSHTTPURLResponse *)response, data, self.imageScale);
} else {
return AFImageWithDataAtScale(data, self.imageScale);
}
#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
#else
// Ensure that the image is set to it's correct pixel width and height
NSBitmapImageRep *bitimage = [[NSBitmapImageRep alloc] initWithData:data];
NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize([bitimage pixelsWide], [bitimage pixelsHigh])];
@@ -710,13 +690,13 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
#pragma mark - NSSecureCoding
- (id)initWithCoder:(NSCoder *)decoder {
- (instancetype)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:decoder];
if (!self) {
return nil;
}
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
NSNumber *imageScale = [decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(imageScale))];
#if CGFLOAT_IS_DOUBLE
self.imageScale = [imageScale doubleValue];
@@ -733,7 +713,7 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
- (void)encodeWithCoder:(NSCoder *)coder {
[super encodeWithCoder:coder];
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
[coder encodeObject:@(self.imageScale) forKey:NSStringFromSelector(@selector(imageScale))];
[coder encodeBool:self.automaticallyInflatesResponseImage forKey:NSStringFromSelector(@selector(automaticallyInflatesResponseImage))];
#endif
@@ -741,10 +721,10 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
- (instancetype)copyWithZone:(NSZone *)zone {
AFImageResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
serializer.imageScale = self.imageScale;
serializer.automaticallyInflatesResponseImage = self.automaticallyInflatesResponseImage;
#endif
@@ -796,7 +776,7 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
#pragma mark - NSSecureCoding
- (id)initWithCoder:(NSCoder *)decoder {
- (instancetype)initWithCoder:(NSCoder *)decoder {
self = [super initWithCoder:decoder];
if (!self) {
return nil;
@@ -815,7 +795,7 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
- (instancetype)copyWithZone:(NSZone *)zone {
AFCompoundResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
serializer.responseSerializers = self.responseSerializers;
+50 -104
View File
@@ -1,5 +1,5 @@
// AFURLSessionManager.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -19,6 +19,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
#import "AFURLResponseSerialization.h"
@@ -28,14 +29,6 @@
#import "AFNetworkReachabilityManager.h"
#endif
#ifndef NS_DESIGNATED_INITIALIZER
#if __has_attribute(objc_designated_initializer)
#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
#else
#define NS_DESIGNATED_INITIALIZER
#endif
#endif
/**
`AFURLSessionManager` creates and manages an `NSURLSession` object based on a specified `NSURLSessionConfiguration` object, which conforms to `<NSURLSessionTaskDelegate>`, `<NSURLSessionDataDelegate>`, `<NSURLSessionDownloadDelegate>`, and `<NSURLSessionDelegate>`.
@@ -58,6 +51,7 @@
- `URLSession:willPerformHTTPRedirection:newRequest:completionHandler:`
- `URLSession:task:didReceiveChallenge:completionHandler:`
- `URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:`
- `URLSession:task:needNewBodyStream:`
- `URLSession:task:didCompleteWithError:`
### `NSURLSessionDataDelegate`
@@ -93,8 +87,6 @@
NS_ASSUME_NONNULL_BEGIN
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) || TARGET_OS_WATCH
@interface AFURLSessionManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>
/**
@@ -119,7 +111,7 @@ NS_ASSUME_NONNULL_BEGIN
///-------------------------------
/**
The security policy used by created request operations to evaluate server trust for secure connections. `AFURLSessionManager` uses the `defaultPolicy` unless otherwise specified.
The security policy used by created session to evaluate server trust for secure connections. `AFURLSessionManager` uses the `defaultPolicy` unless otherwise specified.
*/
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
@@ -141,22 +133,22 @@ NS_ASSUME_NONNULL_BEGIN
/**
The data, upload, and download tasks currently run by the managed session.
*/
@property (readonly, nonatomic, strong) NSArray *tasks;
@property (readonly, nonatomic, strong) NSArray <NSURLSessionTask *> *tasks;
/**
The data tasks currently run by the managed session.
*/
@property (readonly, nonatomic, strong) NSArray *dataTasks;
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks;
/**
The upload tasks currently run by the managed session.
*/
@property (readonly, nonatomic, strong) NSArray *uploadTasks;
@property (readonly, nonatomic, strong) NSArray <NSURLSessionUploadTask *> *uploadTasks;
/**
The download tasks currently run by the managed session.
*/
@property (readonly, nonatomic, strong) NSArray *downloadTasks;
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDownloadTask *> *downloadTasks;
///-------------------------------
/// @name Managing Callback Queues
@@ -165,20 +157,12 @@ NS_ASSUME_NONNULL_BEGIN
/**
The dispatch queue for `completionBlock`. If `NULL` (default), the main queue is used.
*/
#if OS_OBJECT_USE_OBJC
@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;
#else
@property (nonatomic, assign, nullable) dispatch_queue_t completionQueue;
#endif
/**
The dispatch group for `completionBlock`. If `NULL` (default), a private dispatch group is used.
*/
#if OS_OBJECT_USE_OBJC
@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;
#else
@property (nonatomic, assign, nullable) dispatch_group_t completionGroup;
#endif
///---------------------------------
/// @name Working Around System Bugs
@@ -224,7 +208,20 @@ NS_ASSUME_NONNULL_BEGIN
@param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
*/
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
completionHandler:(nullable void (^)(NSURLResponse *response, id __nullable responseObject, NSError * __nullable error))completionHandler;
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
/**
Creates an `NSURLSessionDataTask` with the specified request.
@param request The HTTP request for the request.
@param uploadProgressBlock A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
@param downloadProgressBlock A block object to be executed when the download progress is updated. Note this block is called on the session queue, not the main queue.
@param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
*/
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
uploadProgress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
///---------------------------
/// @name Running Upload Tasks
@@ -235,39 +232,39 @@ NS_ASSUME_NONNULL_BEGIN
@param request The HTTP request for the request.
@param fileURL A URL to the local file to be uploaded.
@param progress A progress object monitoring the current upload progress.
@param uploadProgressBlock A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
@param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
@see `attemptsToRecreateUploadTasksForBackgroundSessions`
*/
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
fromFile:(NSURL *)fileURL
progress:(NSProgress * __nullable __autoreleasing * __nullable)progress
completionHandler:(nullable void (^)(NSURLResponse *response, id __nullable responseObject, NSError * __nullable error))completionHandler;
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
/**
Creates an `NSURLSessionUploadTask` with the specified request for an HTTP body.
@param request The HTTP request for the request.
@param bodyData A data object containing the HTTP body to be uploaded.
@param progress A progress object monitoring the current upload progress.
@param uploadProgressBlock A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
@param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
*/
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
fromData:(nullable NSData *)bodyData
progress:(NSProgress * __nullable __autoreleasing * __nullable)progress
completionHandler:(nullable void (^)(NSURLResponse *response, id __nullable responseObject, NSError * __nullable error))completionHandler;
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
/**
Creates an `NSURLSessionUploadTask` with the specified streaming request.
@param request The HTTP request for the request.
@param progress A progress object monitoring the current upload progress.
@param uploadProgressBlock A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
@param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
*/
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
progress:(NSProgress * __nullable __autoreleasing * __nullable)progress
completionHandler:(nullable void (^)(NSURLResponse *response, id __nullable responseObject, NSError * __nullable error))completionHandler;
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
///-----------------------------
/// @name Running Download Tasks
@@ -277,29 +274,29 @@ NS_ASSUME_NONNULL_BEGIN
Creates an `NSURLSessionDownloadTask` with the specified request.
@param request The HTTP request for the request.
@param progress A progress object monitoring the current download progress.
@param downloadProgressBlock A block object to be executed when the download progress is updated. Note this block is called on the session queue, not the main queue.
@param destination A block object to be executed in order to determine the destination of the downloaded file. This block takes two arguments, the target path & the server response, and returns the desired file URL of the resulting download. The temporary file used during the download will be automatically deleted after being moved to the returned URL.
@param completionHandler A block to be executed when a task finishes. This block has no return value and takes three arguments: the server response, the path of the downloaded file, and the error describing the network or parsing error that occurred, if any.
@warning If using a background `NSURLSessionConfiguration` on iOS, these blocks will be lost when the app is terminated. Background sessions may prefer to use `-setDownloadTaskDidFinishDownloadingBlock:` to specify the URL for saving the downloaded file, rather than the destination block of this method.
*/
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
progress:(NSProgress * __nullable __autoreleasing * __nullable)progress
progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * __nullable filePath, NSError * __nullable error))completionHandler;
completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;
/**
Creates an `NSURLSessionDownloadTask` with the specified resume data.
@param resumeData The data used to resume downloading.
@param progress A progress object monitoring the current download progress.
@param downloadProgressBlock A block object to be executed when the download progress is updated. Note this block is called on the session queue, not the main queue.
@param destination A block object to be executed in order to determine the destination of the downloaded file. This block takes two arguments, the target path & the server response, and returns the desired file URL of the resulting download. The temporary file used during the download will be automatically deleted after being moved to the returned URL.
@param completionHandler A block to be executed when a task finishes. This block has no return value and takes three arguments: the server response, the path of the downloaded file, and the error describing the network or parsing error that occurred, if any.
*/
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
progress:(NSProgress * __nullable __autoreleasing * __nullable)progress
progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * __nullable filePath, NSError * __nullable error))completionHandler;
completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;
///---------------------------------
/// @name Getting Progress for Tasks
@@ -308,20 +305,20 @@ NS_ASSUME_NONNULL_BEGIN
/**
Returns the upload progress of the specified task.
@param uploadTask The session upload task. Must not be `nil`.
@param task The session task. Must not be `nil`.
@return An `NSProgress` object reporting the upload progress of a task, or `nil` if the progress is unavailable.
*/
- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionUploadTask *)uploadTask;
- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task;
/**
Returns the download progress of the specified task.
@param downloadTask The session download task. Must not be `nil`.
@param task The session task. Must not be `nil`.
@return An `NSProgress` object reporting the download progress of a task, or `nil` if the progress is unavailable.
*/
- (nullable NSProgress *)downloadProgressForTask:(NSURLSessionDownloadTask *)downloadTask;
- (nullable NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task;
///-----------------------------------------
/// @name Setting Session Delegate Callbacks
@@ -339,7 +336,7 @@ NS_ASSUME_NONNULL_BEGIN
@param block A block object to be executed when a connection level authentication challenge has occurred. The block returns the disposition of the authentication challenge, and takes three arguments: the session, the authentication challenge, and a pointer to the credential that should be used to resolve the challenge.
*/
- (void)setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __nullable __autoreleasing * __nullable credential))block;
- (void)setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;
///--------------------------------------
/// @name Setting Task Delegate Callbacks
@@ -364,7 +361,7 @@ NS_ASSUME_NONNULL_BEGIN
@param block A block object to be executed when a session task has received a request specific authentication challenge. The block returns the disposition of the authentication challenge, and takes four arguments: the session, the task, the authentication challenge, and a pointer to the credential that should be used to resolve the challenge.
*/
- (void)setTaskDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __nullable __autoreleasing * __nullable credential))block;
- (void)setTaskDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;
/**
Sets a block to be executed periodically to track upload progress, as handled by the `NSURLSessionTaskDelegate` method `URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:`.
@@ -378,7 +375,7 @@ NS_ASSUME_NONNULL_BEGIN
@param block A block object to be executed when a session task is completed. The block has no return value, and takes three arguments: the session, the task, and any error that occurred in the process of executing the task.
*/
- (void)setTaskDidCompleteBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, NSError * __nullable error))block;
- (void)setTaskDidCompleteBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, NSError * _Nullable error))block;
///-------------------------------------------
/// @name Setting Data Task Delegate Callbacks
@@ -428,7 +425,7 @@ NS_ASSUME_NONNULL_BEGIN
@param block A block object to be executed when a download task has completed. The block returns the URL the download should be moved to, and takes three arguments: the session, the download task, and the temporary location of the downloaded file. If the file manager encounters an error while attempting to move the temporary file to the destination, an `AFURLSessionDownloadTaskDidFailToMoveFileNotification` will be posted, with the download task as its object, and the user info of the error.
*/
- (void)setDownloadTaskDidFinishDownloadingBlock:(nullable NSURL * __nullable (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block;
- (void)setDownloadTaskDidFinishDownloadingBlock:(nullable NSURL * _Nullable (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block;
/**
Sets a block to be executed periodically to track download progress, as handled by the `NSURLSessionDownloadDelegate` method `URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesWritten:totalBytesExpectedToWrite:`.
@@ -446,31 +443,15 @@ NS_ASSUME_NONNULL_BEGIN
@end
#endif
///--------------------
/// @name Notifications
///--------------------
/**
Posted when a task begins executing.
@deprecated Use `AFNetworkingTaskDidResumeNotification` instead.
*/
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidStartNotification DEPRECATED_ATTRIBUTE;
/**
Posted when a task resumes.
*/
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidResumeNotification;
/**
Posted when a task finishes executing. Includes a userInfo dictionary with additional information about the task.
@deprecated Use `AFNetworkingTaskDidCompleteNotification` instead.
*/
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidFinishNotification DEPRECATED_ATTRIBUTE;
/**
Posted when a task finishes executing. Includes a userInfo dictionary with additional information about the task.
*/
@@ -492,62 +473,27 @@ FOUNDATION_EXPORT NSString * const AFURLSessionDidInvalidateNotification;
FOUNDATION_EXPORT NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification;
/**
The raw response data of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if response data exists for the task.
@deprecated Use `AFNetworkingTaskDidCompleteResponseDataKey` instead.
*/
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidFinishResponseDataKey DEPRECATED_ATTRIBUTE;
/**
The raw response data of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if response data exists for the task.
The raw response data of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidCompleteNotification` if response data exists for the task.
*/
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteResponseDataKey;
/**
The serialized response object of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if the response was serialized.
@deprecated Use `AFNetworkingTaskDidCompleteSerializedResponseKey` instead.
*/
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidFinishSerializedResponseKey DEPRECATED_ATTRIBUTE;
/**
The serialized response object of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if the response was serialized.
The serialized response object of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidCompleteNotification` if the response was serialized.
*/
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey;
/**
The response serializer used to serialize the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if the task has an associated response serializer.
@deprecated Use `AFNetworkingTaskDidCompleteResponseSerializerKey` instead.
*/
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidFinishResponseSerializerKey DEPRECATED_ATTRIBUTE;
/**
The response serializer used to serialize the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if the task has an associated response serializer.
The response serializer used to serialize the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidCompleteNotification` if the task has an associated response serializer.
*/
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey;
/**
The file path associated with the download task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if an the response data has been stored directly to disk.
@deprecated Use `AFNetworkingTaskDidCompleteAssetPathKey` instead.
*/
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidFinishAssetPathKey DEPRECATED_ATTRIBUTE;
/**
The file path associated with the download task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if an the response data has been stored directly to disk.
The file path associated with the download task. Included in the userInfo dictionary of the `AFNetworkingTaskDidCompleteNotification` if an the response data has been stored directly to disk.
*/
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteAssetPathKey;
/**
Any error associated with the task, or the serialization of the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if an error exists.
@deprecated Use `AFNetworkingTaskDidCompleteErrorKey` instead.
*/
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidFinishErrorKey DEPRECATED_ATTRIBUTE;
/**
Any error associated with the task, or the serialization of the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if an error exists.
Any error associated with the task, or the serialization of the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidCompleteNotification` if an error exists.
*/
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteErrorKey;
+189 -119
View File
@@ -1,5 +1,5 @@
// AFURLSessionManager.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -22,7 +22,11 @@
#import "AFURLSessionManager.h"
#import <objc/runtime.h>
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090)
#ifndef NSFoundationVersionNumber_iOS_8_0
#define NSFoundationVersionNumber_With_Fixed_5871104061079552_bug 1140.11
#else
#define NSFoundationVersionNumber_With_Fixed_5871104061079552_bug NSFoundationVersionNumber_iOS_8_0
#endif
static dispatch_queue_t url_session_manager_creation_queue() {
static dispatch_queue_t af_url_session_manager_creation_queue;
@@ -34,6 +38,17 @@ static dispatch_queue_t url_session_manager_creation_queue() {
return af_url_session_manager_creation_queue;
}
static void url_session_manager_create_task_safely(dispatch_block_t block) {
if (NSFoundationVersionNumber < NSFoundationVersionNumber_With_Fixed_5871104061079552_bug) {
// Fix of bug
// Open Radar:http://openradar.appspot.com/radar?id=5871104061079552 (status: Fixed in iOS8)
// Issue about:https://github.com/AFNetworking/AFNetworking/issues/2093
dispatch_sync(url_session_manager_creation_queue(), block);
} else {
block();
}
}
static dispatch_queue_t url_session_manager_processing_queue() {
static dispatch_queue_t af_url_session_manager_processing_queue;
static dispatch_once_t onceToken;
@@ -60,21 +75,12 @@ NSString * const AFNetworkingTaskDidSuspendNotification = @"com.alamofire.networ
NSString * const AFURLSessionDidInvalidateNotification = @"com.alamofire.networking.session.invalidate";
NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification = @"com.alamofire.networking.session.download.file-manager-error";
NSString * const AFNetworkingTaskDidStartNotification = @"com.alamofire.networking.task.resume"; // Deprecated
NSString * const AFNetworkingTaskDidFinishNotification = @"com.alamofire.networking.task.complete"; // Deprecated
NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey = @"com.alamofire.networking.task.complete.serializedresponse";
NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey = @"com.alamofire.networking.task.complete.responseserializer";
NSString * const AFNetworkingTaskDidCompleteResponseDataKey = @"com.alamofire.networking.complete.finish.responsedata";
NSString * const AFNetworkingTaskDidCompleteErrorKey = @"com.alamofire.networking.task.complete.error";
NSString * const AFNetworkingTaskDidCompleteAssetPathKey = @"com.alamofire.networking.task.complete.assetpath";
NSString * const AFNetworkingTaskDidFinishSerializedResponseKey = @"com.alamofire.networking.task.complete.serializedresponse"; // Deprecated
NSString * const AFNetworkingTaskDidFinishResponseSerializerKey = @"com.alamofire.networking.task.complete.responseserializer"; // Deprecated
NSString * const AFNetworkingTaskDidFinishResponseDataKey = @"com.alamofire.networking.complete.finish.responsedata"; // Deprecated
NSString * const AFNetworkingTaskDidFinishErrorKey = @"com.alamofire.networking.task.complete.error"; // Deprecated
NSString * const AFNetworkingTaskDidFinishAssetPathKey = @"com.alamofire.networking.task.complete.assetpath"; // Deprecated
static NSString * const AFURLSessionManagerLockName = @"com.alamofire.networking.session.manager.lock";
static NSUInteger const AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask = 3;
@@ -100,17 +106,22 @@ typedef NSCachedURLResponse * (^AFURLSessionDataTaskWillCacheResponseBlock)(NSUR
typedef NSURL * (^AFURLSessionDownloadTaskDidFinishDownloadingBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location);
typedef void (^AFURLSessionDownloadTaskDidWriteDataBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite);
typedef void (^AFURLSessionDownloadTaskDidResumeBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes);
typedef void (^AFURLSessionTaskProgressBlock)(NSProgress *);
typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id responseObject, NSError *error);
#pragma mark -
@interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
@property (nonatomic, weak) AFURLSessionManager *manager;
@property (nonatomic, strong) NSMutableData *mutableData;
@property (nonatomic, strong) NSProgress *progress;
@property (nonatomic, strong) NSProgress *uploadProgress;
@property (nonatomic, strong) NSProgress *downloadProgress;
@property (nonatomic, copy) NSURL *downloadFileURL;
@property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
@property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock;
@property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock;
@property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler;
@end
@@ -123,24 +134,119 @@ typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id re
}
self.mutableData = [NSMutableData data];
self.uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
self.uploadProgress.totalUnitCount = NSURLSessionTransferSizeUnknown;
self.progress = [NSProgress progressWithTotalUnitCount:0];
self.downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
self.downloadProgress.totalUnitCount = NSURLSessionTransferSizeUnknown;
return self;
}
#pragma mark - NSURLSessionTaskDelegate
#pragma mark - NSProgress Tracking
- (void)URLSession:(__unused NSURLSession *)session
task:(__unused NSURLSessionTask *)task
didSendBodyData:(__unused int64_t)bytesSent
totalBytesSent:(int64_t)totalBytesSent
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
{
self.progress.totalUnitCount = totalBytesExpectedToSend;
self.progress.completedUnitCount = totalBytesSent;
- (void)setupProgressForTask:(NSURLSessionTask *)task {
__weak __typeof__(task) weakTask = task;
self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
self.downloadProgress.totalUnitCount = task.countOfBytesExpectedToReceive;
[self.uploadProgress setCancellable:YES];
[self.uploadProgress setCancellationHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask cancel];
}];
[self.uploadProgress setPausable:YES];
[self.uploadProgress setPausingHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask suspend];
}];
if ([self.uploadProgress respondsToSelector:@selector(setResumingHandler:)]) {
[self.uploadProgress setResumingHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask resume];
}];
}
[self.downloadProgress setCancellable:YES];
[self.downloadProgress setCancellationHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask cancel];
}];
[self.downloadProgress setPausable:YES];
[self.downloadProgress setPausingHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask suspend];
}];
if ([self.downloadProgress respondsToSelector:@selector(setResumingHandler:)]) {
[self.downloadProgress setResumingHandler:^{
__typeof__(weakTask) strongTask = weakTask;
[strongTask resume];
}];
}
[task addObserver:self
forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))
options:NSKeyValueObservingOptionNew
context:NULL];
[task addObserver:self
forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))
options:NSKeyValueObservingOptionNew
context:NULL];
[task addObserver:self
forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))
options:NSKeyValueObservingOptionNew
context:NULL];
[task addObserver:self
forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend))
options:NSKeyValueObservingOptionNew
context:NULL];
[self.downloadProgress addObserver:self
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
[self.uploadProgress addObserver:self
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:NULL];
}
- (void)cleanUpProgressForTask:(NSURLSessionTask *)task {
[task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))];
[task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))];
[task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))];
[task removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesExpectedToSend))];
[self.downloadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
[self.uploadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
if ([object isKindOfClass:[NSURLSessionTask class]] || [object isKindOfClass:[NSURLSessionDownloadTask class]]) {
if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))]) {
self.downloadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToReceive))]) {
self.downloadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) {
self.uploadProgress.completedUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
} else if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesExpectedToSend))]) {
self.uploadProgress.totalUnitCount = [change[NSKeyValueChangeNewKey] longLongValue];
}
}
else if ([object isEqual:self.downloadProgress]) {
if (self.downloadProgressBlock) {
self.downloadProgressBlock(object);
}
}
else if ([object isEqual:self.uploadProgress]) {
if (self.uploadProgressBlock) {
self.uploadProgressBlock(object);
}
}
}
#pragma mark - NSURLSessionTaskDelegate
- (void)URLSession:(__unused NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error
@@ -241,24 +347,6 @@ didFinishDownloadingToURL:(NSURL *)location
}
}
- (void)URLSession:(__unused NSURLSession *)session
downloadTask:(__unused NSURLSessionDownloadTask *)downloadTask
didWriteData:(__unused int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
self.progress.totalUnitCount = totalBytesExpectedToWrite;
self.progress.completedUnitCount = totalBytesWritten;
}
- (void)URLSession:(__unused NSURLSession *)session
downloadTask:(__unused NSURLSessionDownloadTask *)downloadTask
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes {
self.progress.totalUnitCount = expectedTotalBytes;
self.progress.completedUnitCount = fileOffset;
}
@end
#pragma mark -
@@ -452,7 +540,7 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
for (NSURLSessionDataTask *task in dataTasks) {
[self addDelegateForDataTask:task completionHandler:nil];
[self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
}
for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
@@ -464,9 +552,6 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
}
}];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:nil];
return self;
}
@@ -523,10 +608,14 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
[self.lock lock];
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
[delegate setupProgressForTask:task];
[self addNotificationObserverForTask:task];
[self.lock unlock];
}
- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
@@ -535,48 +624,28 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
[self setDelegate:delegate forTask:dataTask];
delegate.uploadProgressBlock = uploadProgressBlock;
delegate.downloadProgressBlock = downloadProgressBlock;
}
- (void)addDelegateForUploadTask:(NSURLSessionUploadTask *)uploadTask
progress:(NSProgress * __autoreleasing *)progress
progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
delegate.manager = self;
delegate.completionHandler = completionHandler;
int64_t totalUnitCount = uploadTask.countOfBytesExpectedToSend;
if(totalUnitCount == NSURLSessionTransferSizeUnknown) {
NSString *contentLength = [uploadTask.originalRequest valueForHTTPHeaderField:@"Content-Length"];
if(contentLength) {
totalUnitCount = (int64_t)[contentLength longLongValue];
}
}
if (delegate.progress) {
delegate.progress.totalUnitCount = totalUnitCount;
} else {
delegate.progress = [NSProgress progressWithTotalUnitCount:totalUnitCount];
}
delegate.progress.pausingHandler = ^{
[uploadTask suspend];
};
delegate.progress.cancellationHandler = ^{
[uploadTask cancel];
};
if (progress) {
*progress = delegate.progress;
}
uploadTask.taskDescription = self.taskDescriptionForSessionTasks;
[self setDelegate:delegate forTask:uploadTask];
delegate.uploadProgressBlock = uploadProgressBlock;
}
- (void)addDelegateForDownloadTask:(NSURLSessionDownloadTask *)downloadTask
progress:(NSProgress * __autoreleasing *)progress
progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{
@@ -590,29 +659,24 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
};
}
if (progress) {
*progress = delegate.progress;
}
downloadTask.taskDescription = self.taskDescriptionForSessionTasks;
[self setDelegate:delegate forTask:downloadTask];
delegate.downloadProgressBlock = downloadProgressBlock;
}
- (void)removeDelegateForTask:(NSURLSessionTask *)task {
NSParameterAssert(task);
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
[self.lock lock];
[delegate cleanUpProgressForTask:task];
[self removeNotificationObserverForTask:task];
[self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];
[self.lock unlock];
}
- (void)removeAllDelegates {
[self.lock lock];
[self.mutableTaskDelegatesKeyedByTaskIdentifier removeAllObjects];
[self.lock unlock];
}
#pragma mark -
- (NSArray *)tasksForKeyPath:(NSString *)keyPath {
@@ -673,17 +737,36 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
_responseSerializer = responseSerializer;
}
#pragma mark -
- (void)addNotificationObserverForTask:(NSURLSessionTask *)task {
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:task];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:task];
}
- (void)removeNotificationObserverForTask:(NSURLSessionTask *)task {
[[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidSuspendNotification object:task];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidResumeNotification object:task];
}
#pragma mark -
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
return [self dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:completionHandler];
}
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler {
__block NSURLSessionDataTask *dataTask = nil;
dispatch_sync(url_session_manager_creation_queue(), ^{
url_session_manager_create_task_safely(^{
dataTask = [self.session dataTaskWithRequest:request];
});
[self addDelegateForDataTask:dataTask completionHandler:completionHandler];
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
return dataTask;
}
@@ -692,11 +775,11 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
fromFile:(NSURL *)fileURL
progress:(NSProgress * __autoreleasing *)progress
progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
__block NSURLSessionUploadTask *uploadTask = nil;
dispatch_sync(url_session_manager_creation_queue(), ^{
url_session_manager_create_task_safely(^{
uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
});
@@ -706,36 +789,36 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
}
}
[self addDelegateForUploadTask:uploadTask progress:progress completionHandler:completionHandler];
[self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
return uploadTask;
}
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
fromData:(NSData *)bodyData
progress:(NSProgress * __autoreleasing *)progress
progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
__block NSURLSessionUploadTask *uploadTask = nil;
dispatch_sync(url_session_manager_creation_queue(), ^{
url_session_manager_create_task_safely(^{
uploadTask = [self.session uploadTaskWithRequest:request fromData:bodyData];
});
[self addDelegateForUploadTask:uploadTask progress:progress completionHandler:completionHandler];
[self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
return uploadTask;
}
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
progress:(NSProgress * __autoreleasing *)progress
progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
{
__block NSURLSessionUploadTask *uploadTask = nil;
dispatch_sync(url_session_manager_creation_queue(), ^{
url_session_manager_create_task_safely(^{
uploadTask = [self.session uploadTaskWithStreamedRequest:request];
});
[self addDelegateForUploadTask:uploadTask progress:progress completionHandler:completionHandler];
[self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
return uploadTask;
}
@@ -743,43 +826,42 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
#pragma mark -
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
progress:(NSProgress * __autoreleasing *)progress
progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{
__block NSURLSessionDownloadTask *downloadTask = nil;
dispatch_sync(url_session_manager_creation_queue(), ^{
url_session_manager_create_task_safely(^{
downloadTask = [self.session downloadTaskWithRequest:request];
});
[self addDelegateForDownloadTask:downloadTask progress:progress destination:destination completionHandler:completionHandler];
[self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];
return downloadTask;
}
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
progress:(NSProgress * __autoreleasing *)progress
progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
{
__block NSURLSessionDownloadTask *downloadTask = nil;
dispatch_sync(url_session_manager_creation_queue(), ^{
url_session_manager_create_task_safely(^{
downloadTask = [self.session downloadTaskWithResumeData:resumeData];
});
[self addDelegateForDownloadTask:downloadTask progress:progress destination:destination completionHandler:completionHandler];
[self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];
return downloadTask;
}
#pragma mark -
- (NSProgress *)uploadProgressForTask:(NSURLSessionUploadTask *)uploadTask {
return [[self delegateForTask:uploadTask] progress];
- (NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task {
return [[self delegateForTask:task] uploadProgress];
}
- (NSProgress *)downloadProgressForTask:(NSURLSessionDownloadTask *)downloadTask {
return [[self delegateForTask:downloadTask] progress];
- (NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task {
return [[self delegateForTask:task] downloadProgress];
}
#pragma mark -
@@ -879,7 +961,6 @@ didBecomeInvalidWithError:(NSError *)error
self.sessionDidBecomeInvalid(session, error);
}
[self removeAllDelegates];
[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDidInvalidateNotification object:session];
}
@@ -993,9 +1074,6 @@ totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
}
}
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
[delegate URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalUnitCount];
if (self.taskDidSendBodyData) {
self.taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalUnitCount);
}
@@ -1017,7 +1095,6 @@ didCompleteWithError:(NSError *)error
if (self.taskDidComplete) {
self.taskDidComplete(session, task, error);
}
}
#pragma mark - NSURLSessionDataDelegate
@@ -1057,6 +1134,7 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data
{
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
[delegate URLSession:session dataTask:dataTask didReceiveData:data];
@@ -1121,9 +1199,6 @@ didFinishDownloadingToURL:(NSURL *)location
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
[delegate URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
if (self.downloadTaskDidWriteData) {
self.downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
}
@@ -1134,9 +1209,6 @@ totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
didResumeAtOffset:(int64_t)fileOffset
expectedTotalBytes:(int64_t)expectedTotalBytes
{
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
[delegate URLSession:session downloadTask:downloadTask didResumeAtOffset:fileOffset expectedTotalBytes:expectedTotalBytes];
if (self.downloadTaskDidResume) {
self.downloadTaskDidResume(session, downloadTask, fileOffset, expectedTotalBytes);
}
@@ -1148,7 +1220,7 @@ expectedTotalBytes:(int64_t)expectedTotalBytes
return YES;
}
- (id)initWithCoder:(NSCoder *)decoder {
- (instancetype)initWithCoder:(NSCoder *)decoder {
NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"];
self = [self initWithSessionConfiguration:configuration];
@@ -1165,10 +1237,8 @@ expectedTotalBytes:(int64_t)expectedTotalBytes
#pragma mark - NSCopying
- (id)copyWithZone:(NSZone *)zone {
- (instancetype)copyWithZone:(NSZone *)zone {
return [[[self class] allocWithZone:zone] initWithSessionConfiguration:self.session.configuration];
}
@end
#endif
@@ -0,0 +1,149 @@
// AFAutoPurgingImageCache.h
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <TargetConditionals.h>
#import <Foundation/Foundation.h>
#if TARGET_OS_IOS || TARGET_OS_TV
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
/**
The `AFImageCache` protocol defines a set of APIs for adding, removing and fetching images from a cache synchronously.
*/
@protocol AFImageCache <NSObject>
/**
Adds the image to the cache with the given identifier.
@param image The image to cache.
@param identifier The unique identifier for the image in the cache.
*/
- (void)addImage:(UIImage *)image withIdentifier:(NSString *)identifier;
/**
Removes the image from the cache matching the given identifier.
@param identifier The unique identifier for the image in the cache.
@return A BOOL indicating whether or not the image was removed from the cache.
*/
- (BOOL)removeImageWithIdentifier:(NSString *)identifier;
/**
Removes all images from the cache.
@return A BOOL indicating whether or not all images were removed from the cache.
*/
- (BOOL)removeAllImages;
/**
Returns the image in the cache associated with the given identifier.
@param identifier The unique identifier for the image in the cache.
@return An image for the matching identifier, or nil.
*/
- (nullable UIImage *)imageWithIdentifier:(NSString *)identifier;
@end
/**
The `ImageRequestCache` protocol extends the `ImageCache` protocol by adding methods for adding, removing and fetching images from a cache given an `NSURLRequest` and additional identifier.
*/
@protocol AFImageRequestCache <AFImageCache>
/**
Adds the image to the cache using an identifier created from the request and additional identifier.
@param image The image to cache.
@param request The unique URL request identifing the image asset.
@param identifier The additional identifier to apply to the URL request to identify the image.
*/
- (void)addImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;
/**
Removes the image from the cache using an identifier created from the request and additional identifier.
@param request The unique URL request identifing the image asset.
@param identifier The additional identifier to apply to the URL request to identify the image.
@return A BOOL indicating whether or not all images were removed from the cache.
*/
- (BOOL)removeImageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;
/**
Returns the image from the cache associated with an identifier created from the request and additional identifier.
@param request The unique URL request identifing the image asset.
@param identifier The additional identifier to apply to the URL request to identify the image.
@return An image for the matching request and identifier, or nil.
*/
- (nullable UIImage *)imageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier;
@end
/**
The `AutoPurgingImageCache` in an in-memory image cache used to store images up to a given memory capacity. When the memory capacity is reached, the image cache is sorted by last access date, then the oldest image is continuously purged until the preferred memory usage after purge is met. Each time an image is accessed through the cache, the internal access date of the image is updated.
*/
@interface AFAutoPurgingImageCache : NSObject <AFImageRequestCache>
/**
The total memory capacity of the cache in bytes.
*/
@property (nonatomic, assign) UInt64 memoryCapacity;
/**
The preferred memory usage after purge in bytes. During a purge, images will be purged until the memory capacity drops below this limit.
*/
@property (nonatomic, assign) UInt64 preferredMemoryUsageAfterPurge;
/**
The current total memory usage in bytes of all images stored within the cache.
*/
@property (nonatomic, assign, readonly) UInt64 memoryUsage;
/**
Initialies the `AutoPurgingImageCache` instance with default values for memory capacity and preferred memory usage after purge limit. `memoryCapcity` defaults to `100 MB`. `preferredMemoryUsageAfterPurge` defaults to `60 MB`.
@return The new `AutoPurgingImageCache` instance.
*/
- (instancetype)init;
/**
Initialies the `AutoPurgingImageCache` instance with the given memory capacity and preferred memory usage
after purge limit.
@param memoryCapacity The total memory capacity of the cache in bytes.
@param preferredMemoryCapacity The preferred memory usage after purge in bytes.
@return The new `AutoPurgingImageCache` instance.
*/
- (instancetype)initWithMemoryCapacity:(UInt64)memoryCapacity preferredMemoryCapacity:(UInt64)preferredMemoryCapacity;
@end
NS_ASSUME_NONNULL_END
#endif
@@ -0,0 +1,201 @@
// AFAutoPurgingImageCache.m
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <TargetConditionals.h>
#if TARGET_OS_IOS || TARGET_OS_TV
#import "AFAutoPurgingImageCache.h"
@interface AFCachedImage : NSObject
@property (nonatomic, strong) UIImage *image;
@property (nonatomic, strong) NSString *identifier;
@property (nonatomic, assign) UInt64 totalBytes;
@property (nonatomic, strong) NSDate *lastAccessDate;
@property (nonatomic, assign) UInt64 currentMemoryUsage;
@end
@implementation AFCachedImage
-(instancetype)initWithImage:(UIImage *)image identifier:(NSString *)identifier {
if (self = [self init]) {
self.image = image;
self.identifier = identifier;
CGSize imageSize = CGSizeMake(image.size.width * image.scale, image.size.height * image.scale);
CGFloat bytesPerPixel = 4.0;
CGFloat bytesPerSize = imageSize.width * imageSize.height;
self.totalBytes = (UInt64)bytesPerPixel * (UInt64)bytesPerSize;
self.lastAccessDate = [NSDate date];
}
return self;
}
- (UIImage*)accessImage {
self.lastAccessDate = [NSDate date];
return self.image;
}
- (NSString *)description {
NSString *descriptionString = [NSString stringWithFormat:@"Idenfitier: %@ lastAccessDate: %@ ", self.identifier, self.lastAccessDate];
return descriptionString;
}
@end
@interface AFAutoPurgingImageCache ()
@property (nonatomic, strong) NSMutableDictionary <NSString* , AFCachedImage*> *cachedImages;
@property (nonatomic, assign) UInt64 currentMemoryUsage;
@property (nonatomic, strong) dispatch_queue_t synchronizationQueue;
@end
@implementation AFAutoPurgingImageCache
- (instancetype)init {
return [self initWithMemoryCapacity:100 * 1024 * 1024 preferredMemoryCapacity:60 * 1024 * 1024];
}
- (instancetype)initWithMemoryCapacity:(UInt64)memoryCapacity preferredMemoryCapacity:(UInt64)preferredMemoryCapacity {
if (self = [super init]) {
self.memoryCapacity = memoryCapacity;
self.preferredMemoryUsageAfterPurge = preferredMemoryCapacity;
self.cachedImages = [[NSMutableDictionary alloc] init];
NSString *queueName = [NSString stringWithFormat:@"com.alamofire.autopurgingimagecache-%@", [[NSUUID UUID] UUIDString]];
self.synchronizationQueue = dispatch_queue_create([queueName cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_CONCURRENT);
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(removeAllImages)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
}
return self;
}
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
}
- (UInt64)memoryUsage {
__block UInt64 result = 0;
dispatch_sync(self.synchronizationQueue, ^{
result = self.currentMemoryUsage;
});
return result;
}
- (void)addImage:(UIImage *)image withIdentifier:(NSString *)identifier {
dispatch_barrier_async(self.synchronizationQueue, ^{
AFCachedImage *cacheImage = [[AFCachedImage alloc] initWithImage:image identifier:identifier];
AFCachedImage *previousCachedImage = self.cachedImages[identifier];
if (previousCachedImage != nil) {
self.currentMemoryUsage -= previousCachedImage.totalBytes;
}
self.cachedImages[identifier] = cacheImage;
self.currentMemoryUsage += cacheImage.totalBytes;
});
dispatch_barrier_async(self.synchronizationQueue, ^{
if (self.currentMemoryUsage > self.memoryCapacity) {
UInt64 bytesToPurge = self.currentMemoryUsage - self.preferredMemoryUsageAfterPurge;
NSMutableArray <AFCachedImage*> *sortedImages = [NSMutableArray arrayWithArray:self.cachedImages.allValues];
NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastAccessDate"
ascending:YES];
[sortedImages sortUsingDescriptors:@[sortDescriptor]];
UInt64 bytesPurged = 0;
for (AFCachedImage *cachedImage in sortedImages) {
[self.cachedImages removeObjectForKey:cachedImage.identifier];
bytesPurged += cachedImage.totalBytes;
if (bytesPurged >= bytesToPurge) {
break ;
}
}
self.currentMemoryUsage -= bytesPurged;
}
});
}
- (BOOL)removeImageWithIdentifier:(NSString *)identifier {
__block BOOL removed = NO;
dispatch_barrier_sync(self.synchronizationQueue, ^{
AFCachedImage *cachedImage = self.cachedImages[identifier];
if (cachedImage != nil) {
[self.cachedImages removeObjectForKey:identifier];
self.currentMemoryUsage -= cachedImage.totalBytes;
removed = YES;
}
});
return removed;
}
- (BOOL)removeAllImages {
__block BOOL removed = NO;
dispatch_barrier_sync(self.synchronizationQueue, ^{
if (self.cachedImages.count > 0) {
[self.cachedImages removeAllObjects];
self.currentMemoryUsage = 0;
removed = YES;
}
});
return removed;
}
- (nullable UIImage *)imageWithIdentifier:(NSString *)identifier {
__block UIImage *image = nil;
dispatch_sync(self.synchronizationQueue, ^{
AFCachedImage *cachedImage = self.cachedImages[identifier];
image = [cachedImage accessImage];
});
return image;
}
- (void)addImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(NSString *)identifier {
[self addImage:image withIdentifier:[self imageCacheKeyFromURLRequest:request withAdditionalIdentifier:identifier]];
}
- (BOOL)removeImageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(NSString *)identifier {
return [self removeImageWithIdentifier:[self imageCacheKeyFromURLRequest:request withAdditionalIdentifier:identifier]];
}
- (nullable UIImage *)imageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(NSString *)identifier {
return [self imageWithIdentifier:[self imageCacheKeyFromURLRequest:request withAdditionalIdentifier:identifier]];
}
- (NSString *)imageCacheKeyFromURLRequest:(NSURLRequest *)request withAdditionalIdentifier:(NSString *)additionalIdentifier {
NSString *key = request.URL.absoluteString;
if (additionalIdentifier != nil) {
key = [key stringByAppendingString:additionalIdentifier];
}
return key;
}
@end
#endif
@@ -0,0 +1,157 @@
// AFImageDownloader.h
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <TargetConditionals.h>
#if TARGET_OS_IOS || TARGET_OS_TV
#import <Foundation/Foundation.h>
#import "AFAutoPurgingImageCache.h"
#import "AFHTTPSessionManager.h"
NS_ASSUME_NONNULL_BEGIN
typedef NS_ENUM(NSInteger, AFImageDownloadPrioritization) {
AFImageDownloadPrioritizationFIFO,
AFImageDownloadPrioritizationLIFO
};
/**
The `AFImageDownloadReceipt` is an object vended by the `AFImageDownloader` when starting a data task. It can be used to cancel active tasks running on the `AFImageDownloader` session. As a general rule, image data tasks should be cancelled using the `AFImageDownloadReceipt` instead of calling `cancel` directly on the `task` itself. The `AFImageDownloader` is optimized to handle duplicate task scenarios as well as pending versus active downloads.
*/
@interface AFImageDownloadReceipt : NSObject
/**
The data task created by the `AFImageDownloader`.
*/
@property (nonatomic, strong) NSURLSessionDataTask *task;
/**
The unique identifier for the success and failure blocks when duplicate requests are made.
*/
@property (nonatomic, strong) NSUUID *receiptID;
@end
/** The `AFImageDownloader` class is responsible for downloading images in parallel on a prioritized queue. Incoming downloads are added to the front or back of the queue depending on the download prioritization. Each downloaded image is cached in the underlying `NSURLCache` as well as the in-memory image cache. By default, any download request with a cached image equivalent in the image cache will automatically be served the cached image representation.
*/
@interface AFImageDownloader : NSObject
/**
The image cache used to store all downloaded images in. `AFAutoPurgingImageCache` by default.
*/
@property (nonatomic, strong, nullable) id <AFImageRequestCache> imageCache;
/**
The `AFHTTPSessionManager` used to download images. By default, this is configured with an `AFImageResponseSerializer`, and a shared `NSURLCache` for all image downloads.
*/
@property (nonatomic, strong) AFHTTPSessionManager *sessionManager;
/**
Defines the order prioritization of incoming download requests being inserted into the queue. `AFImageDownloadPrioritizationFIFO` by default.
*/
@property (nonatomic, assign) AFImageDownloadPrioritization downloadPrioritizaton;
/**
The shared default instance of `AFImageDownloader` initialized with default values.
*/
+ (instancetype)defaultInstance;
/**
Creates a default `NSURLCache` with common usage parameter values.
@returns The default `NSURLCache` instance.
*/
+ (NSURLCache *)defaultURLCache;
/**
Default initializer
@return An instance of `AFImageDownloader` initialized with default values.
*/
- (instancetype)init;
/**
Initializes the `AFImageDownloader` instance with the given session manager, download prioritization, maximum active download count and image cache.
@param sessionManager The session manager to use to download images.
@param downloadPrioritization The download prioritization of the download queue.
@param maximumActiveDownloads The maximum number of active downloads allowed at any given time. Recommend `4`.
@param imageCache The image cache used to store all downloaded images in.
@return The new `AFImageDownloader` instance.
*/
- (instancetype)initWithSessionManager:(AFHTTPSessionManager *)sessionManager
downloadPrioritization:(AFImageDownloadPrioritization)downloadPrioritization
maximumActiveDownloads:(NSInteger)maximumActiveDownloads
imageCache:(nullable id <AFImageRequestCache>)imageCache;
/**
Creates a data task using the `sessionManager` instance for the specified URL request.
If the same data task is already in the queue or currently being downloaded, the success and failure blocks are
appended to the already existing task. Once the task completes, all success or failure blocks attached to the
task are executed in the order they were added.
@param request The URL request.
@param success A block to be executed when the image data task finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the image created from the response data of request. If the image was returned from cache, the response parameter will be `nil`.
@param failure A block object to be executed when the image data task finishes unsuccessfully, or that finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error object describing the network or parsing error that occurred.
@return The image download receipt for the data task if available. `nil` if the image is stored in the cache.
cache and the URL request cache policy allows the cache to be used.
*/
- (nullable AFImageDownloadReceipt *)downloadImageForURLRequest:(NSURLRequest *)request
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *responseObject))success
failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure;
/**
Creates a data task using the `sessionManager` instance for the specified URL request.
If the same data task is already in the queue or currently being downloaded, the success and failure blocks are
appended to the already existing task. Once the task completes, all success or failure blocks attached to the
task are executed in the order they were added.
@param request The URL request.
@param receiptID The identifier to use for the download receipt that will be created for this request. This must be a unique identifier that does not represent any other request.
@param success A block to be executed when the image data task finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the image created from the response data of request. If the image was returned from cache, the response parameter will be `nil`.
@param failure A block object to be executed when the image data task finishes unsuccessfully, or that finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error object describing the network or parsing error that occurred.
@return The image download receipt for the data task if available. `nil` if the image is stored in the cache.
cache and the URL request cache policy allows the cache to be used.
*/
- (nullable AFImageDownloadReceipt *)downloadImageForURLRequest:(NSURLRequest *)request
withReceiptID:(NSUUID *)receiptID
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *responseObject))success
failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure;
/**
Cancels the data task in the receipt by removing the corresponding success and failure blocks and cancelling the data task if necessary.
If the data task is pending in the queue, it will be cancelled if no other success and failure blocks are registered with the data task. If the data task is currently executing or is already completed, the success and failure blocks are removed and will not be called when the task finishes.
@param imageDownloadReceipt The image download receipt to cancel.
*/
- (void)cancelTaskForImageDownloadReceipt:(AFImageDownloadReceipt *)imageDownloadReceipt;
@end
#endif
NS_ASSUME_NONNULL_END
@@ -0,0 +1,391 @@
// AFImageDownloader.m
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <TargetConditionals.h>
#if TARGET_OS_IOS || TARGET_OS_TV
#import "AFImageDownloader.h"
#import "AFHTTPSessionManager.h"
@interface AFImageDownloaderResponseHandler : NSObject
@property (nonatomic, strong) NSUUID *uuid;
@property (nonatomic, copy) void (^successBlock)(NSURLRequest*, NSHTTPURLResponse*, UIImage*);
@property (nonatomic, copy) void (^failureBlock)(NSURLRequest*, NSHTTPURLResponse*, NSError*);
@end
@implementation AFImageDownloaderResponseHandler
- (instancetype)initWithUUID:(NSUUID *)uuid
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *responseObject))success
failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure {
if (self = [self init]) {
self.uuid = uuid;
self.successBlock = success;
self.failureBlock = failure;
}
return self;
}
- (NSString *)description {
return [NSString stringWithFormat: @"<AFImageDownloaderResponseHandler>UUID: %@", [self.uuid UUIDString]];
}
@end
@interface AFImageDownloaderMergedTask : NSObject
@property (nonatomic, strong) NSString *URLIdentifier;
@property (nonatomic, strong) NSUUID *identifier;
@property (nonatomic, strong) NSURLSessionDataTask *task;
@property (nonatomic, strong) NSMutableArray <AFImageDownloaderResponseHandler*> *responseHandlers;
@end
@implementation AFImageDownloaderMergedTask
- (instancetype)initWithURLIdentifier:(NSString *)URLIdentifier identifier:(NSUUID *)identifier task:(NSURLSessionDataTask *)task {
if (self = [self init]) {
self.URLIdentifier = URLIdentifier;
self.task = task;
self.identifier = identifier;
self.responseHandlers = [[NSMutableArray alloc] init];
}
return self;
}
- (void)addResponseHandler:(AFImageDownloaderResponseHandler*)handler {
[self.responseHandlers addObject:handler];
}
- (void)removeResponseHandler:(AFImageDownloaderResponseHandler*)handler {
[self.responseHandlers removeObject:handler];
}
@end
@implementation AFImageDownloadReceipt
- (instancetype)initWithReceiptID:(NSUUID *)receiptID task:(NSURLSessionDataTask *)task {
if (self = [self init]) {
self.receiptID = receiptID;
self.task = task;
}
return self;
}
@end
@interface AFImageDownloader ()
@property (nonatomic, strong) dispatch_queue_t synchronizationQueue;
@property (nonatomic, strong) dispatch_queue_t responseQueue;
@property (nonatomic, assign) NSInteger maximumActiveDownloads;
@property (nonatomic, assign) NSInteger activeRequestCount;
@property (nonatomic, strong) NSMutableArray *queuedMergedTasks;
@property (nonatomic, strong) NSMutableDictionary *mergedTasks;
@end
@implementation AFImageDownloader
+ (NSURLCache *)defaultURLCache {
return [[NSURLCache alloc] initWithMemoryCapacity:20 * 1024 * 1024
diskCapacity:150 * 1024 * 1024
diskPath:@"com.alamofire.imagedownloader"];
}
+ (NSURLSessionConfiguration *)defaultURLSessionConfiguration {
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
//TODO set the default HTTP headers
configuration.HTTPShouldSetCookies = YES;
configuration.HTTPShouldUsePipelining = NO;
configuration.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
configuration.allowsCellularAccess = YES;
configuration.timeoutIntervalForRequest = 60.0;
configuration.URLCache = [AFImageDownloader defaultURLCache];
return configuration;
}
- (instancetype)init {
NSURLSessionConfiguration *defaultConfiguration = [self.class defaultURLSessionConfiguration];
AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:defaultConfiguration];
sessionManager.responseSerializer = [AFImageResponseSerializer serializer];
return [self initWithSessionManager:sessionManager
downloadPrioritization:AFImageDownloadPrioritizationFIFO
maximumActiveDownloads:4
imageCache:[[AFAutoPurgingImageCache alloc] init]];
}
- (instancetype)initWithSessionManager:(AFHTTPSessionManager *)sessionManager
downloadPrioritization:(AFImageDownloadPrioritization)downloadPrioritization
maximumActiveDownloads:(NSInteger)maximumActiveDownloads
imageCache:(id <AFImageRequestCache>)imageCache {
if (self = [super init]) {
self.sessionManager = sessionManager;
self.downloadPrioritizaton = downloadPrioritization;
self.maximumActiveDownloads = maximumActiveDownloads;
self.imageCache = imageCache;
self.queuedMergedTasks = [[NSMutableArray alloc] init];
self.mergedTasks = [[NSMutableDictionary alloc] init];
self.activeRequestCount = 0;
NSString *name = [NSString stringWithFormat:@"com.alamofire.imagedownloader.synchronizationqueue-%@", [[NSUUID UUID] UUIDString]];
self.synchronizationQueue = dispatch_queue_create([name cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_SERIAL);
name = [NSString stringWithFormat:@"com.alamofire.imagedownloader.responsequeue-%@", [[NSUUID UUID] UUIDString]];
self.responseQueue = dispatch_queue_create([name cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_CONCURRENT);
}
return self;
}
+ (instancetype)defaultInstance {
static AFImageDownloader *sharedInstance = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[self alloc] init];
});
return sharedInstance;
}
- (nullable AFImageDownloadReceipt *)downloadImageForURLRequest:(NSURLRequest *)request
success:(void (^)(NSURLRequest * _Nonnull, NSHTTPURLResponse * _Nullable, UIImage * _Nonnull))success
failure:(void (^)(NSURLRequest * _Nonnull, NSHTTPURLResponse * _Nullable, NSError * _Nonnull))failure {
return [self downloadImageForURLRequest:request withReceiptID:[NSUUID UUID] success:success failure:failure];
}
- (nullable AFImageDownloadReceipt *)downloadImageForURLRequest:(NSURLRequest *)request
withReceiptID:(nonnull NSUUID *)receiptID
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *responseObject))success
failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure {
__block NSURLSessionDataTask *task = nil;
dispatch_sync(self.synchronizationQueue, ^{
NSString *URLIdentifier = request.URL.absoluteString;
if (URLIdentifier == nil) {
if (failure) {
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadURL userInfo:nil];
dispatch_async(dispatch_get_main_queue(), ^{
failure(request, nil, error);
});
}
return;
}
// 1) Append the success and failure blocks to a pre-existing request if it already exists
AFImageDownloaderMergedTask *existingMergedTask = self.mergedTasks[URLIdentifier];
if (existingMergedTask != nil) {
AFImageDownloaderResponseHandler *handler = [[AFImageDownloaderResponseHandler alloc] initWithUUID:receiptID success:success failure:failure];
[existingMergedTask addResponseHandler:handler];
task = existingMergedTask.task;
return;
}
// 2) Attempt to load the image from the image cache if the cache policy allows it
switch (request.cachePolicy) {
case NSURLRequestUseProtocolCachePolicy:
case NSURLRequestReturnCacheDataElseLoad:
case NSURLRequestReturnCacheDataDontLoad: {
UIImage *cachedImage = [self.imageCache imageforRequest:request withAdditionalIdentifier:nil];
if (cachedImage != nil) {
if (success) {
dispatch_async(dispatch_get_main_queue(), ^{
success(request, nil, cachedImage);
});
}
return;
}
break;
}
default:
break;
}
// 3) Create the request and set up authentication, validation and response serialization
NSUUID *mergedTaskIdentifier = [NSUUID UUID];
NSURLSessionDataTask *createdTask;
__weak __typeof__(self) weakSelf = self;
createdTask = [self.sessionManager
dataTaskWithRequest:request
completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) {
dispatch_async(self.responseQueue, ^{
__strong __typeof__(weakSelf) strongSelf = weakSelf;
AFImageDownloaderMergedTask *mergedTask = self.mergedTasks[URLIdentifier];
if ([mergedTask.identifier isEqual:mergedTaskIdentifier]) {
mergedTask = [strongSelf safelyRemoveMergedTaskWithURLIdentifier:URLIdentifier];
if (error) {
for (AFImageDownloaderResponseHandler *handler in mergedTask.responseHandlers) {
if (handler.failureBlock) {
dispatch_async(dispatch_get_main_queue(), ^{
handler.failureBlock(request, (NSHTTPURLResponse*)response, error);
});
}
}
} else {
[strongSelf.imageCache addImage:responseObject forRequest:request withAdditionalIdentifier:nil];
for (AFImageDownloaderResponseHandler *handler in mergedTask.responseHandlers) {
if (handler.successBlock) {
dispatch_async(dispatch_get_main_queue(), ^{
handler.successBlock(request, (NSHTTPURLResponse*)response, responseObject);
});
}
}
}
}
[strongSelf safelyDecrementActiveTaskCount];
[strongSelf safelyStartNextTaskIfNecessary];
});
}];
// 4) Store the response handler for use when the request completes
AFImageDownloaderResponseHandler *handler = [[AFImageDownloaderResponseHandler alloc] initWithUUID:receiptID
success:success
failure:failure];
AFImageDownloaderMergedTask *mergedTask = [[AFImageDownloaderMergedTask alloc]
initWithURLIdentifier:URLIdentifier
identifier:mergedTaskIdentifier
task:createdTask];
[mergedTask addResponseHandler:handler];
self.mergedTasks[URLIdentifier] = mergedTask;
// 5) Either start the request or enqueue it depending on the current active request count
if ([self isActiveRequestCountBelowMaximumLimit]) {
[self startMergedTask:mergedTask];
} else {
[self enqueueMergedTask:mergedTask];
}
task = mergedTask.task;
});
if (task) {
return [[AFImageDownloadReceipt alloc] initWithReceiptID:receiptID task:task];
} else {
return nil;
}
}
- (void)cancelTaskForImageDownloadReceipt:(AFImageDownloadReceipt *)imageDownloadReceipt {
dispatch_sync(self.synchronizationQueue, ^{
NSString *URLIdentifier = imageDownloadReceipt.task.originalRequest.URL.absoluteString;
AFImageDownloaderMergedTask *mergedTask = self.mergedTasks[URLIdentifier];
NSUInteger index = [mergedTask.responseHandlers indexOfObjectPassingTest:^BOOL(AFImageDownloaderResponseHandler * _Nonnull handler, __unused NSUInteger idx, __unused BOOL * _Nonnull stop) {
return handler.uuid == imageDownloadReceipt.receiptID;
}];
if (index != NSNotFound) {
AFImageDownloaderResponseHandler *handler = mergedTask.responseHandlers[index];
[mergedTask removeResponseHandler:handler];
NSString *failureReason = [NSString stringWithFormat:@"ImageDownloader cancelled URL request: %@",imageDownloadReceipt.task.originalRequest.URL.absoluteString];
NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey:failureReason};
NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:userInfo];
if (handler.failureBlock) {
dispatch_async(dispatch_get_main_queue(), ^{
handler.failureBlock(imageDownloadReceipt.task.originalRequest, nil, error);
});
}
}
if (mergedTask.responseHandlers.count == 0 && mergedTask.task.state == NSURLSessionTaskStateSuspended) {
[mergedTask.task cancel];
[self removeMergedTaskWithURLIdentifier:URLIdentifier];
}
});
}
- (AFImageDownloaderMergedTask*)safelyRemoveMergedTaskWithURLIdentifier:(NSString *)URLIdentifier {
__block AFImageDownloaderMergedTask *mergedTask = nil;
dispatch_sync(self.synchronizationQueue, ^{
mergedTask = [self removeMergedTaskWithURLIdentifier:URLIdentifier];
});
return mergedTask;
}
//This method should only be called from safely within the synchronizationQueue
- (AFImageDownloaderMergedTask *)removeMergedTaskWithURLIdentifier:(NSString *)URLIdentifier {
AFImageDownloaderMergedTask *mergedTask = self.mergedTasks[URLIdentifier];
[self.mergedTasks removeObjectForKey:URLIdentifier];
return mergedTask;
}
- (void)safelyDecrementActiveTaskCount {
dispatch_sync(self.synchronizationQueue, ^{
if (self.activeRequestCount > 0) {
self.activeRequestCount -= 1;
}
});
}
- (void)safelyStartNextTaskIfNecessary {
dispatch_sync(self.synchronizationQueue, ^{
if ([self isActiveRequestCountBelowMaximumLimit]) {
while (self.queuedMergedTasks.count > 0) {
AFImageDownloaderMergedTask *mergedTask = [self dequeueMergedTask];
if (mergedTask.task.state == NSURLSessionTaskStateSuspended) {
[self startMergedTask:mergedTask];
break;
}
}
}
});
}
- (void)startMergedTask:(AFImageDownloaderMergedTask *)mergedTask {
[mergedTask.task resume];
++self.activeRequestCount;
}
- (void)enqueueMergedTask:(AFImageDownloaderMergedTask *)mergedTask {
switch (self.downloadPrioritizaton) {
case AFImageDownloadPrioritizationFIFO:
[self.queuedMergedTasks addObject:mergedTask];
break;
case AFImageDownloadPrioritizationLIFO:
[self.queuedMergedTasks insertObject:mergedTask atIndex:0];
break;
}
}
- (AFImageDownloaderMergedTask *)dequeueMergedTask {
AFImageDownloaderMergedTask *mergedTask = nil;
mergedTask = [self.queuedMergedTasks firstObject];
[self.queuedMergedTasks removeObject:mergedTask];
return mergedTask;
}
- (BOOL)isActiveRequestCountBelowMaximumLimit {
return self.activeRequestCount < self.maximumActiveDownloads;
}
@end
#endif
@@ -1,5 +1,5 @@
// AFNetworkActivityIndicatorManager.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -21,16 +21,16 @@
#import <Foundation/Foundation.h>
#import <Availability.h>
#import <TargetConditionals.h>
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
/**
`AFNetworkActivityIndicatorManager` manages the state of the network activity indicator in the status bar. When enabled, it will listen for notifications indicating that a network request operation has started or finished, and start or stop animating the indicator accordingly. The number of active requests is incremented and decremented much like a stack or a semaphore, and the activity indicator will animate so long as that number is greater than zero.
`AFNetworkActivityIndicatorManager` manages the state of the network activity indicator in the status bar. When enabled, it will listen for notifications indicating that a session task has started or finished, and start or stop animating the indicator accordingly. The number of active requests is incremented and decremented much like a stack or a semaphore, and the activity indicator will animate so long as that number is greater than zero.
You should enable the shared instance of `AFNetworkActivityIndicatorManager` when your application finishes launching. In `AppDelegate application:didFinishLaunchingWithOptions:` you can do so with the following code:
@@ -52,9 +52,25 @@ NS_EXTENSION_UNAVAILABLE_IOS("Use view controller based solutions where appropri
@property (nonatomic, assign, getter = isEnabled) BOOL enabled;
/**
A Boolean value indicating whether the network activity indicator is currently displayed in the status bar.
A Boolean value indicating whether the network activity indicator manager is currently active.
*/
@property (readonly, nonatomic, assign, getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;
/**
A time interval indicating the minimum duration of networking activity that should occur before the activity indicator is displayed. The default value 1 second. If the network activity indicator should be displayed immediately when network activity occurs, this value should be set to 0 seconds.
Apple's HIG describes the following:
> Display the network activity indicator to provide feedback when your app accesses the network for more than a couple of seconds. If the operation finishes sooner than that, you don’t have to show the network activity indicator, because the indicator is likely to disappear before users notice its presence.
*/
@property (readonly, nonatomic, assign) BOOL isNetworkActivityIndicatorVisible;
@property (nonatomic, assign) NSTimeInterval activationDelay;
/**
A time interval indicating the duration of time of no networking activity required before the activity indicator is disabled. This allows for continuous display of the network activity indicator across multiple requests. The default value is 0.17 seconds.
*/
@property (nonatomic, assign) NSTimeInterval completionDelay;
/**
Returns the shared network activity indicator manager object for the system.
@@ -73,6 +89,13 @@ NS_EXTENSION_UNAVAILABLE_IOS("Use view controller based solutions where appropri
*/
- (void)decrementActivityCount;
/**
Set the a custom method to be executed when the network activity indicator manager should be hidden/shown. By default, this is null, and the UIApplication Network Activity Indicator will be managed automatically. If this block is set, it is the responsiblity of the caller to manager the network activity indicator going forward.
@param block A block to be executed when the network activity indicator status changes.
*/
- (void)setNetworkingActivityActionWithBlock:(nullable void (^)(BOOL networkActivityIndicatorVisible))block;
@end
NS_ASSUME_NONNULL_END
@@ -1,5 +1,5 @@
// AFNetworkActivityIndicatorManager.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -21,41 +21,42 @@
#import "AFNetworkActivityIndicatorManager.h"
#if defined(__IPHONE_OS_VERSION_MAX_ALLOWED)
#import "AFHTTPRequestOperation.h"
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
#if TARGET_OS_IOS
#import "AFURLSessionManager.h"
#endif
static NSTimeInterval const kAFNetworkActivityIndicatorInvisibilityDelay = 0.17;
typedef NS_ENUM(NSInteger, AFNetworkActivityManagerState) {
AFNetworkActivityManagerStateNotActive,
AFNetworkActivityManagerStateDelayingStart,
AFNetworkActivityManagerStateActive,
AFNetworkActivityManagerStateDelayingEnd
};
static NSTimeInterval const kDefaultAFNetworkActivityManagerActivationDelay = 1.0;
static NSTimeInterval const kDefaultAFNetworkActivityManagerCompletionDelay = 0.17;
static NSURLRequest * AFNetworkRequestFromNotification(NSNotification *notification) {
if ([[notification object] isKindOfClass:[AFURLConnectionOperation class]]) {
return [(AFURLConnectionOperation *)[notification object] request];
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
if ([[notification object] respondsToSelector:@selector(originalRequest)]) {
return [(NSURLSessionTask *)[notification object] originalRequest];
} else {
return nil;
}
#endif
return nil;
}
typedef void (^AFNetworkActivityActionBlock)(BOOL networkActivityIndicatorVisible);
@interface AFNetworkActivityIndicatorManager ()
@property (readwrite, nonatomic, assign) NSInteger activityCount;
@property (readwrite, nonatomic, strong) NSTimer *activityIndicatorVisibilityTimer;
@property (readonly, nonatomic, getter = isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;
@property (readwrite, nonatomic, strong) NSTimer *activationDelayTimer;
@property (readwrite, nonatomic, strong) NSTimer *completionDelayTimer;
@property (readonly, nonatomic, getter = isNetworkActivityOccurring) BOOL networkActivityOccurring;
@property (nonatomic, copy) AFNetworkActivityActionBlock networkActivityActionBlock;
@property (nonatomic, assign) AFNetworkActivityManagerState currentState;
@property (nonatomic, assign, getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible;
- (void)updateNetworkActivityIndicatorVisibility;
- (void)updateNetworkActivityIndicatorVisibilityDelayed;
- (void)updateCurrentStateForNetworkActivityChange;
@end
@implementation AFNetworkActivityIndicatorManager
@dynamic networkActivityIndicatorVisible;
+ (instancetype)sharedManager {
static AFNetworkActivityIndicatorManager *_sharedManager = nil;
@@ -67,24 +68,17 @@ static NSURLRequest * AFNetworkRequestFromNotification(NSNotification *notificat
return _sharedManager;
}
+ (NSSet *)keyPathsForValuesAffectingIsNetworkActivityIndicatorVisible {
return [NSSet setWithObject:@"activityCount"];
}
- (id)init {
- (instancetype)init {
self = [super init];
if (!self) {
return nil;
}
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidStart:) name:AFNetworkingOperationDidStartNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidFinish:) name:AFNetworkingOperationDidFinishNotification object:nil];
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000
self.currentState = AFNetworkActivityManagerStateNotActive;
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidStart:) name:AFNetworkingTaskDidResumeNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidFinish:) name:AFNetworkingTaskDidSuspendNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidFinish:) name:AFNetworkingTaskDidCompleteNotification object:nil];
#endif
self.activationDelay = kDefaultAFNetworkActivityManagerActivationDelay;
self.completionDelay = kDefaultAFNetworkActivityManagerCompletionDelay;
return self;
}
@@ -92,28 +86,40 @@ static NSURLRequest * AFNetworkRequestFromNotification(NSNotification *notificat
- (void)dealloc {
[[NSNotificationCenter defaultCenter] removeObserver:self];
[_activityIndicatorVisibilityTimer invalidate];
[_activationDelayTimer invalidate];
[_completionDelayTimer invalidate];
}
- (void)updateNetworkActivityIndicatorVisibilityDelayed {
if (self.enabled) {
// Delay hiding of activity indicator for a short interval, to avoid flickering
if (![self isNetworkActivityIndicatorVisible]) {
[self.activityIndicatorVisibilityTimer invalidate];
self.activityIndicatorVisibilityTimer = [NSTimer timerWithTimeInterval:kAFNetworkActivityIndicatorInvisibilityDelay target:self selector:@selector(updateNetworkActivityIndicatorVisibility) userInfo:nil repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:self.activityIndicatorVisibilityTimer forMode:NSRunLoopCommonModes];
} else {
[self performSelectorOnMainThread:@selector(updateNetworkActivityIndicatorVisibility) withObject:nil waitUntilDone:NO modes:@[NSRunLoopCommonModes]];
}
- (void)setEnabled:(BOOL)enabled {
_enabled = enabled;
if (enabled == NO) {
[self setCurrentState:AFNetworkActivityManagerStateNotActive];
}
}
- (BOOL)isNetworkActivityIndicatorVisible {
return self.activityCount > 0;
- (void)setNetworkingActivityActionWithBlock:(void (^)(BOOL networkActivityIndicatorVisible))block {
self.networkActivityActionBlock = block;
}
- (void)updateNetworkActivityIndicatorVisibility {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:[self isNetworkActivityIndicatorVisible]];
- (BOOL)isNetworkActivityOccurring {
@synchronized(self) {
return self.activityCount > 0;
}
}
- (void)setNetworkActivityIndicatorVisible:(BOOL)networkActivityIndicatorVisible {
if (_networkActivityIndicatorVisible != networkActivityIndicatorVisible) {
[self willChangeValueForKey:@"networkActivityIndicatorVisible"];
@synchronized(self) {
_networkActivityIndicatorVisible = networkActivityIndicatorVisible;
}
[self didChangeValueForKey:@"networkActivityIndicatorVisible"];
if (self.networkActivityActionBlock) {
self.networkActivityActionBlock(networkActivityIndicatorVisible);
} else {
[[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:networkActivityIndicatorVisible];
}
}
}
- (void)setActivityCount:(NSInteger)activityCount {
@@ -122,7 +128,7 @@ static NSURLRequest * AFNetworkRequestFromNotification(NSNotification *notificat
}
dispatch_async(dispatch_get_main_queue(), ^{
[self updateNetworkActivityIndicatorVisibilityDelayed];
[self updateCurrentStateForNetworkActivityChange];
});
}
@@ -134,7 +140,7 @@ static NSURLRequest * AFNetworkRequestFromNotification(NSNotification *notificat
[self didChangeValueForKey:@"activityCount"];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateNetworkActivityIndicatorVisibilityDelayed];
[self updateCurrentStateForNetworkActivityChange];
});
}
@@ -149,7 +155,7 @@ static NSURLRequest * AFNetworkRequestFromNotification(NSNotification *notificat
[self didChangeValueForKey:@"activityCount"];
dispatch_async(dispatch_get_main_queue(), ^{
[self updateNetworkActivityIndicatorVisibilityDelayed];
[self updateCurrentStateForNetworkActivityChange];
});
}
@@ -165,6 +171,91 @@ static NSURLRequest * AFNetworkRequestFromNotification(NSNotification *notificat
}
}
#pragma mark - Internal State Management
- (void)setCurrentState:(AFNetworkActivityManagerState)currentState {
@synchronized(self) {
if (_currentState != currentState) {
[self willChangeValueForKey:@"currentState"];
_currentState = currentState;
switch (currentState) {
case AFNetworkActivityManagerStateNotActive:
[self cancelActivationDelayTimer];
[self cancelCompletionDelayTimer];
[self setNetworkActivityIndicatorVisible:NO];
break;
case AFNetworkActivityManagerStateDelayingStart:
[self startActivationDelayTimer];
break;
case AFNetworkActivityManagerStateActive:
[self cancelCompletionDelayTimer];
[self setNetworkActivityIndicatorVisible:YES];
break;
case AFNetworkActivityManagerStateDelayingEnd:
[self startCompletionDelayTimer];
break;
}
}
[self didChangeValueForKey:@"currentState"];
}
}
- (void)updateCurrentStateForNetworkActivityChange {
if (self.enabled) {
switch (self.currentState) {
case AFNetworkActivityManagerStateNotActive:
if (self.isNetworkActivityOccurring) {
[self setCurrentState:AFNetworkActivityManagerStateDelayingStart];
}
break;
case AFNetworkActivityManagerStateDelayingStart:
//No op. Let the delay timer finish out.
break;
case AFNetworkActivityManagerStateActive:
if (!self.isNetworkActivityOccurring) {
[self setCurrentState:AFNetworkActivityManagerStateDelayingEnd];
}
break;
case AFNetworkActivityManagerStateDelayingEnd:
if (self.isNetworkActivityOccurring) {
[self setCurrentState:AFNetworkActivityManagerStateActive];
}
break;
}
}
}
- (void)startActivationDelayTimer {
self.activationDelayTimer = [NSTimer
timerWithTimeInterval:self.activationDelay target:self selector:@selector(activationDelayTimerFired) userInfo:nil repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:self.activationDelayTimer forMode:NSRunLoopCommonModes];
}
- (void)activationDelayTimerFired {
if (self.networkActivityOccurring) {
[self setCurrentState:AFNetworkActivityManagerStateActive];
} else {
[self setCurrentState:AFNetworkActivityManagerStateNotActive];
}
}
- (void)startCompletionDelayTimer {
[self.completionDelayTimer invalidate];
self.completionDelayTimer = [NSTimer timerWithTimeInterval:self.completionDelay target:self selector:@selector(completionDelayTimerFired) userInfo:nil repeats:NO];
[[NSRunLoop mainRunLoop] addTimer:self.completionDelayTimer forMode:NSRunLoopCommonModes];
}
- (void)completionDelayTimerFired {
[self setCurrentState:AFNetworkActivityManagerStateNotActive];
}
- (void)cancelActivationDelayTimer {
[self.activationDelayTimer invalidate];
}
- (void)cancelCompletionDelayTimer {
[self.completionDelayTimer invalidate];
}
@end
#endif
@@ -1,5 +1,5 @@
// UIActivityIndicatorView+AFNetworking.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -21,16 +21,14 @@
#import <Foundation/Foundation.h>
#import <Availability.h>
#import <TargetConditionals.h>
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS || TARGET_OS_TV
#import <UIKit/UIKit.h>
@class AFURLConnectionOperation;
/**
This category adds methods to the UIKit framework's `UIActivityIndicatorView` class. The methods in this category provide support for automatically starting and stopping animation depending on the loading state of a request operation or session task.
This category adds methods to the UIKit framework's `UIActivityIndicatorView` class. The methods in this category provide support for automatically starting and stopping animation depending on the loading state of a session task.
*/
@interface UIActivityIndicatorView (AFNetworking)
@@ -43,20 +41,7 @@
@param task The task. If `nil`, automatic updating from any previously specified operation will be disabled.
*/
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
- (void)setAnimatingWithStateOfTask:(nullable NSURLSessionTask *)task;
#endif
///---------------------------------------
/// @name Animating for Request Operations
///---------------------------------------
/**
Binds the animating state to the execution state of the specified operation.
@param operation The operation. If `nil`, automatic updating from any previously specified operation will be disabled.
*/
- (void)setAnimatingWithStateOfOperation:(nullable AFURLConnectionOperation *)operation;
@end
@@ -1,5 +1,5 @@
// UIActivityIndicatorView+AFNetworking.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -22,22 +22,15 @@
#import "UIActivityIndicatorView+AFNetworking.h"
#import <objc/runtime.h>
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS || TARGET_OS_TV
#import "AFHTTPRequestOperation.h"
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
#import "AFURLSessionManager.h"
#endif
@interface AFActivityIndicatorViewNotificationObserver : NSObject
@property (readonly, nonatomic, weak) UIActivityIndicatorView *activityIndicatorView;
- (instancetype)initWithActivityIndicatorView:(UIActivityIndicatorView *)activityIndicatorView;
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
- (void)setAnimatingWithStateOfTask:(NSURLSessionTask *)task;
#endif
- (void)setAnimatingWithStateOfOperation:(AFURLConnectionOperation *)operation;
@end
@@ -52,15 +45,9 @@
return notificationObserver;
}
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
- (void)setAnimatingWithStateOfTask:(NSURLSessionTask *)task {
[[self af_notificationObserver] setAnimatingWithStateOfTask:task];
}
#endif
- (void)setAnimatingWithStateOfOperation:(AFURLConnectionOperation *)operation {
[[self af_notificationObserver] setAnimatingWithStateOfOperation:operation];
}
@end
@@ -75,7 +62,6 @@
return self;
}
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
- (void)setAnimatingWithStateOfTask:(NSURLSessionTask *)task {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
@@ -102,34 +88,6 @@
}
}
}
#endif
#pragma mark -
- (void)setAnimatingWithStateOfOperation:(AFURLConnectionOperation *)operation {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter removeObserver:self name:AFNetworkingOperationDidStartNotification object:nil];
[notificationCenter removeObserver:self name:AFNetworkingOperationDidFinishNotification object:nil];
if (operation) {
if (![operation isFinished]) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreceiver-is-weak"
#pragma clang diagnostic ignored "-Warc-repeated-use-of-weak"
if ([operation isExecuting]) {
[self.activityIndicatorView startAnimating];
} else {
[self.activityIndicatorView stopAnimating];
}
#pragma clang diagnostic pop
[notificationCenter addObserver:self selector:@selector(af_startAnimating) name:AFNetworkingOperationDidStartNotification object:operation];
[notificationCenter addObserver:self selector:@selector(af_stopAnimating) name:AFNetworkingOperationDidFinishNotification object:operation];
}
}
}
#pragma mark -
@@ -156,14 +114,9 @@
- (void)dealloc {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
[notificationCenter removeObserver:self name:AFNetworkingTaskDidCompleteNotification object:nil];
[notificationCenter removeObserver:self name:AFNetworkingTaskDidResumeNotification object:nil];
[notificationCenter removeObserver:self name:AFNetworkingTaskDidSuspendNotification object:nil];
#endif
[notificationCenter removeObserver:self name:AFNetworkingOperationDidStartNotification object:nil];
[notificationCenter removeObserver:self name:AFNetworkingOperationDidFinishNotification object:nil];
}
@end
@@ -1,99 +0,0 @@
// UIAlertView+AFNetworking.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import <Foundation/Foundation.h>
#import <Availability.h>
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class AFURLConnectionOperation;
/**
This category adds methods to the UIKit framework's `UIAlertView` class. The methods in this category provide support for automatically showing an alert if a session task or request operation finishes with an error. Alert title and message are filled from the corresponding `localizedDescription` & `localizedRecoverySuggestion` or `localizedFailureReason` of the error.
*/
@interface UIAlertView (AFNetworking)
///-------------------------------------
/// @name Showing Alert for Session Task
///-------------------------------------
/**
Shows an alert view with the error of the specified session task, if any.
@param task The session task.
@param delegate The alert view delegate.
*/
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
+ (void)showAlertViewForTaskWithErrorOnCompletion:(NSURLSessionTask *)task
delegate:(nullable id)delegate NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extensions.");
#endif
/**
Shows an alert view with the error of the specified session task, if any, with a custom cancel button title and other button titles.
@param task The session task.
@param delegate The alert view delegate.
@param cancelButtonTitle The title of the cancel button or nil if there is no cancel button. Using this argument is equivalent to setting the cancel button index to the value returned by invoking addButtonWithTitle: specifying this title.
@param otherButtonTitles The title of another button. Using this argument is equivalent to invoking addButtonWithTitle: with this title to add more buttons. Too many buttons can cause the alert view to scroll. For guidelines on the best ways to use an alert in an app, see "Temporary Views". Titles of additional buttons to add to the receiver, terminated with `nil`.
*/
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
+ (void)showAlertViewForTaskWithErrorOnCompletion:(NSURLSessionTask *)task
delegate:(nullable id)delegate
cancelButtonTitle:(nullable NSString *)cancelButtonTitle
otherButtonTitles:(nullable NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extensions.");
#endif
///------------------------------------------
/// @name Showing Alert for Request Operation
///------------------------------------------
/**
Shows an alert view with the error of the specified request operation, if any.
@param operation The request operation.
@param delegate The alert view delegate.
*/
+ (void)showAlertViewForRequestOperationWithErrorOnCompletion:(AFURLConnectionOperation *)operation
delegate:(nullable id)delegate NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extensions.");
/**
Shows an alert view with the error of the specified request operation, if any, with a custom cancel button title and other button titles.
@param operation The request operation.
@param delegate The alert view delegate.
@param cancelButtonTitle The title of the cancel button or nil if there is no cancel button. Using this argument is equivalent to setting the cancel button index to the value returned by invoking addButtonWithTitle: specifying this title.
@param otherButtonTitles The title of another button. Using this argument is equivalent to invoking addButtonWithTitle: with this title to add more buttons. Too many buttons can cause the alert view to scroll. For guidelines on the best ways to use an alert in an app, see "Temporary Views". Titles of additional buttons to add to the receiver, terminated with `nil`.
*/
+ (void)showAlertViewForRequestOperationWithErrorOnCompletion:(AFURLConnectionOperation *)operation
delegate:(nullable id)delegate
cancelButtonTitle:(nullable NSString *)cancelButtonTitle
otherButtonTitles:(nullable NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION NS_EXTENSION_UNAVAILABLE_IOS("Not available in app extensions.");
@end
NS_ASSUME_NONNULL_END
#endif
@@ -1,141 +0,0 @@
// UIAlertView+AFNetworking.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#import "UIAlertView+AFNetworking.h"
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#import "AFURLConnectionOperation.h"
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
#import "AFURLSessionManager.h"
#endif
static void AFGetAlertViewTitleAndMessageFromError(NSError *error, NSString * __autoreleasing *title, NSString * __autoreleasing *message) {
if (error.localizedDescription && (error.localizedRecoverySuggestion || error.localizedFailureReason)) {
*title = error.localizedDescription;
if (error.localizedRecoverySuggestion) {
*message = error.localizedRecoverySuggestion;
} else {
*message = error.localizedFailureReason;
}
} else if (error.localizedDescription) {
*title = NSLocalizedStringFromTable(@"Error", @"AFNetworking", @"Fallback Error Description");
*message = error.localizedDescription;
} else {
*title = NSLocalizedStringFromTable(@"Error", @"AFNetworking", @"Fallback Error Description");
*message = [NSString stringWithFormat:NSLocalizedStringFromTable(@"%@ Error: %ld", @"AFNetworking", @"Fallback Error Failure Reason Format"), error.domain, (long)error.code];
}
}
@implementation UIAlertView (AFNetworking)
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
+ (void)showAlertViewForTaskWithErrorOnCompletion:(NSURLSessionTask *)task
delegate:(id)delegate
{
[self showAlertViewForTaskWithErrorOnCompletion:task delegate:delegate cancelButtonTitle:NSLocalizedStringFromTable(@"Dismiss", @"AFNetworking", @"UIAlertView Cancel Button Title") otherButtonTitles:nil, nil];
}
+ (void)showAlertViewForTaskWithErrorOnCompletion:(NSURLSessionTask *)task
delegate:(id)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION
{
NSMutableArray *mutableOtherTitles = [NSMutableArray array];
va_list otherButtonTitleList;
va_start(otherButtonTitleList, otherButtonTitles);
{
for (NSString *otherButtonTitle = otherButtonTitles; otherButtonTitle != nil; otherButtonTitle = va_arg(otherButtonTitleList, NSString *)) {
[mutableOtherTitles addObject:otherButtonTitle];
}
}
va_end(otherButtonTitleList);
__block __weak id<NSObject> observer = [[NSNotificationCenter defaultCenter] addObserverForName:AFNetworkingTaskDidCompleteNotification object:task queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) {
NSError *error = notification.userInfo[AFNetworkingTaskDidCompleteErrorKey];
if (error) {
NSString *title, *message;
AFGetAlertViewTitleAndMessageFromError(error, &title, &message);
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:nil delegate:delegate cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil, nil];
for (NSString *otherButtonTitle in mutableOtherTitles) {
[alertView addButtonWithTitle:otherButtonTitle];
}
[alertView setTitle:title];
[alertView setMessage:message];
[alertView show];
}
[[NSNotificationCenter defaultCenter] removeObserver:observer];
}];
}
#endif
#pragma mark -
+ (void)showAlertViewForRequestOperationWithErrorOnCompletion:(AFURLConnectionOperation *)operation
delegate:(id)delegate
{
[self showAlertViewForRequestOperationWithErrorOnCompletion:operation delegate:delegate cancelButtonTitle:NSLocalizedStringFromTable(@"Dismiss", @"AFNetworking", @"UIAlertView Cancel Button Title") otherButtonTitles:nil, nil];
}
+ (void)showAlertViewForRequestOperationWithErrorOnCompletion:(AFURLConnectionOperation *)operation
delegate:(id)delegate
cancelButtonTitle:(NSString *)cancelButtonTitle
otherButtonTitles:(NSString *)otherButtonTitles, ... NS_REQUIRES_NIL_TERMINATION
{
NSMutableArray *mutableOtherTitles = [NSMutableArray array];
va_list otherButtonTitleList;
va_start(otherButtonTitleList, otherButtonTitles);
{
for (NSString *otherButtonTitle = otherButtonTitles; otherButtonTitle != nil; otherButtonTitle = va_arg(otherButtonTitleList, NSString *)) {
[mutableOtherTitles addObject:otherButtonTitle];
}
}
va_end(otherButtonTitleList);
__block __weak id<NSObject> observer = [[NSNotificationCenter defaultCenter] addObserverForName:AFNetworkingOperationDidFinishNotification object:operation queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification *notification) {
if (notification.object && [notification.object isKindOfClass:[AFURLConnectionOperation class]]) {
NSError *error = [(AFURLConnectionOperation *)notification.object error];
if (error) {
NSString *title, *message;
AFGetAlertViewTitleAndMessageFromError(error, &title, &message);
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:nil message:nil delegate:delegate cancelButtonTitle:cancelButtonTitle otherButtonTitles:nil, nil];
for (NSString *otherButtonTitle in mutableOtherTitles) {
[alertView addButtonWithTitle:otherButtonTitle];
}
[alertView setTitle:title];
[alertView setMessage:message];
[alertView show];
}
}
[[NSNotificationCenter defaultCenter] removeObserver:observer];
}];
}
@end
#endif
@@ -1,5 +1,5 @@
// UIButton+AFNetworking.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -21,15 +21,15 @@
#import <Foundation/Foundation.h>
#import <Availability.h>
#import <TargetConditionals.h>
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS || TARGET_OS_TV
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@protocol AFURLResponseSerialization, AFImageCache;
@class AFImageDownloader;
/**
This category adds methods to the UIKit framework's `UIButton` class. The methods in this category provide support for loading remote images and background images asynchronously from a URL.
@@ -38,32 +38,21 @@ NS_ASSUME_NONNULL_BEGIN
*/
@interface UIButton (AFNetworking)
///----------------------------
/// @name Accessing Image Cache
///----------------------------
/**
The image cache used to improve image loading performance on scroll views. By default, `UIButton` will use the `sharedImageCache` of `UIImageView`.
*/
+ (id <AFImageCache>)sharedImageCache;
/**
Set the cache used for image loading.
@param imageCache The image cache.
*/
+ (void)setSharedImageCache:(__nullable id <AFImageCache>)imageCache;
///------------------------------------
/// @name Accessing Response Serializer
/// @name Accessing the Image Downloader
///------------------------------------
/**
The response serializer used to create an image representation from the server response and response data. By default, this is an instance of `AFImageResponseSerializer`.
Set the shared image downloader used to download images.
@discussion Subclasses of `AFImageResponseSerializer` could be used to perform post-processing, such as color correction, face detection, or other effects. See https://github.com/AFNetworking/AFCoreImageSerializer
@param imageDownloader The shared image downloader used to download images.
*/
+ (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader;
/**
The shared image downloader used to download images.
*/
@property (nonatomic, strong) id <AFURLResponseSerialization> imageResponseSerializer;
+ (AFImageDownloader *)sharedImageDownloader;
///--------------------
/// @name Setting Image
@@ -103,14 +92,14 @@ NS_ASSUME_NONNULL_BEGIN
@param state The control state.
@param urlRequest The URL request used for the image request.
@param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the button will not change its image until the image request finishes.
@param success A block to be executed when the image request operation finishes successfully. This block has no return value and takes two arguments: the server response and the image. If the image was returned from cache, the response parameter will be `nil`.
@param failure A block object to be executed when the image request operation finishes unsuccessfully, or that finishes successfully. This block has no return value and takes a single argument: the error that occurred.
@param success A block to be executed when the image data task finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the image created from the response data of request. If the image was returned from cache, the response parameter will be `nil`.
@param failure A block object to be executed when the image data task finishes unsuccessfully, or that finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error object describing the network or parsing error that occurred.
*/
- (void)setImageForState:(UIControlState)state
withURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(nullable UIImage *)placeholderImage
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * __nullable response, UIImage *image))success
failure:(nullable void (^)(NSError *error))failure;
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure;
///-------------------------------
@@ -151,14 +140,14 @@ NS_ASSUME_NONNULL_BEGIN
@param state The control state.
@param urlRequest The URL request used for the image request.
@param placeholderImage The background image to be set initially, until the background image request finishes. If `nil`, the button will not change its background image until the background image request finishes.
@param success A block to be executed when the image request operation finishes successfully. This block has no return value and takes two arguments: the server response and the image. If the image was returned from cache, the response parameter will be `nil`.
@param failure A block object to be executed when the image request operation finishes unsuccessfully, or that finishes successfully. This block has no return value and takes a single argument: the error that occurred.
@param success A block to be executed when the image data task finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the image created from the response data of request. If the image was returned from cache, the response parameter will be `nil`.
@param failure A block object to be executed when the image data task finishes unsuccessfully, or that finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error object describing the network or parsing error that occurred.
*/
- (void)setBackgroundImageForState:(UIControlState)state
withURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(nullable UIImage *)placeholderImage
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * __nullable response, UIImage *image))success
failure:(nullable void (^)(NSError *error))failure;
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure;
///------------------------------
@@ -166,18 +155,18 @@ NS_ASSUME_NONNULL_BEGIN
///------------------------------
/**
Cancels any executing image operation for the specified control state of the receiver, if one exists.
Cancels any executing image task for the specified control state of the receiver, if one exists.
@param state The control state.
*/
- (void)cancelImageRequestOperationForState:(UIControlState)state;
- (void)cancelImageDownloadTaskForState:(UIControlState)state;
/**
Cancels any executing background image operation for the specified control state of the receiver, if one exists.
Cancels any executing background image task for the specified control state of the receiver, if one exists.
@param state The control state.
*/
- (void)cancelBackgroundImageRequestOperationForState:(UIControlState)state;
- (void)cancelBackgroundImageDownloadTaskForState:(UIControlState)state;
@end
@@ -1,5 +1,5 @@
// UIButton+AFNetworking.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,89 +23,76 @@
#import <objc/runtime.h>
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#import "AFURLResponseSerialization.h"
#import "AFHTTPRequestOperation.h"
#if TARGET_OS_IOS || TARGET_OS_TV
#import "UIImageView+AFNetworking.h"
#import "AFImageDownloader.h"
@interface UIButton (_AFNetworking)
@end
@implementation UIButton (_AFNetworking)
+ (NSOperationQueue *)af_sharedImageRequestOperationQueue {
static NSOperationQueue *_af_sharedImageRequestOperationQueue = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_af_sharedImageRequestOperationQueue = [[NSOperationQueue alloc] init];
_af_sharedImageRequestOperationQueue.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount;
});
return _af_sharedImageRequestOperationQueue;
}
#pragma mark -
static char AFImageRequestOperationNormal;
static char AFImageRequestOperationHighlighted;
static char AFImageRequestOperationSelected;
static char AFImageRequestOperationDisabled;
static char AFImageDownloadReceiptNormal;
static char AFImageDownloadReceiptHighlighted;
static char AFImageDownloadReceiptSelected;
static char AFImageDownloadReceiptDisabled;
static const char * af_imageRequestOperationKeyForState(UIControlState state) {
static const char * af_imageDownloadReceiptKeyForState(UIControlState state) {
switch (state) {
case UIControlStateHighlighted:
return &AFImageRequestOperationHighlighted;
return &AFImageDownloadReceiptHighlighted;
case UIControlStateSelected:
return &AFImageRequestOperationSelected;
return &AFImageDownloadReceiptSelected;
case UIControlStateDisabled:
return &AFImageRequestOperationDisabled;
return &AFImageDownloadReceiptDisabled;
case UIControlStateNormal:
default:
return &AFImageRequestOperationNormal;
return &AFImageDownloadReceiptNormal;
}
}
- (AFHTTPRequestOperation *)af_imageRequestOperationForState:(UIControlState)state {
return (AFHTTPRequestOperation *)objc_getAssociatedObject(self, af_imageRequestOperationKeyForState(state));
- (AFImageDownloadReceipt *)af_imageDownloadReceiptForState:(UIControlState)state {
return (AFImageDownloadReceipt *)objc_getAssociatedObject(self, af_imageDownloadReceiptKeyForState(state));
}
- (void)af_setImageRequestOperation:(AFHTTPRequestOperation *)imageRequestOperation
- (void)af_setImageDownloadReceipt:(AFImageDownloadReceipt *)imageDownloadReceipt
forState:(UIControlState)state
{
objc_setAssociatedObject(self, af_imageRequestOperationKeyForState(state), imageRequestOperation, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_setAssociatedObject(self, af_imageDownloadReceiptKeyForState(state), imageDownloadReceipt, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#pragma mark -
static char AFBackgroundImageRequestOperationNormal;
static char AFBackgroundImageRequestOperationHighlighted;
static char AFBackgroundImageRequestOperationSelected;
static char AFBackgroundImageRequestOperationDisabled;
static char AFBackgroundImageDownloadReceiptNormal;
static char AFBackgroundImageDownloadReceiptHighlighted;
static char AFBackgroundImageDownloadReceiptSelected;
static char AFBackgroundImageDownloadReceiptDisabled;
static const char * af_backgroundImageRequestOperationKeyForState(UIControlState state) {
static const char * af_backgroundImageDownloadReceiptKeyForState(UIControlState state) {
switch (state) {
case UIControlStateHighlighted:
return &AFBackgroundImageRequestOperationHighlighted;
return &AFBackgroundImageDownloadReceiptHighlighted;
case UIControlStateSelected:
return &AFBackgroundImageRequestOperationSelected;
return &AFBackgroundImageDownloadReceiptSelected;
case UIControlStateDisabled:
return &AFBackgroundImageRequestOperationDisabled;
return &AFBackgroundImageDownloadReceiptDisabled;
case UIControlStateNormal:
default:
return &AFBackgroundImageRequestOperationNormal;
return &AFBackgroundImageDownloadReceiptNormal;
}
}
- (AFHTTPRequestOperation *)af_backgroundImageRequestOperationForState:(UIControlState)state {
return (AFHTTPRequestOperation *)objc_getAssociatedObject(self, af_backgroundImageRequestOperationKeyForState(state));
- (AFImageDownloadReceipt *)af_backgroundImageDownloadReceiptForState:(UIControlState)state {
return (AFImageDownloadReceipt *)objc_getAssociatedObject(self, af_backgroundImageDownloadReceiptKeyForState(state));
}
- (void)af_setBackgroundImageRequestOperation:(AFHTTPRequestOperation *)imageRequestOperation
- (void)af_setBackgroundImageDownloadReceipt:(AFImageDownloadReceipt *)imageDownloadReceipt
forState:(UIControlState)state
{
objc_setAssociatedObject(self, af_backgroundImageRequestOperationKeyForState(state), imageRequestOperation, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
objc_setAssociatedObject(self, af_backgroundImageDownloadReceiptKeyForState(state), imageDownloadReceipt, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
@@ -114,34 +101,16 @@ static const char * af_backgroundImageRequestOperationKeyForState(UIControlState
@implementation UIButton (AFNetworking)
+ (id <AFImageCache>)sharedImageCache {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
return objc_getAssociatedObject(self, @selector(sharedImageCache)) ?: [UIImageView sharedImageCache];
#pragma clang diagnostic pop
}
+ (void)setSharedImageCache:(__nullable id <AFImageCache>)imageCache {
objc_setAssociatedObject(self, @selector(sharedImageCache), imageCache, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#pragma mark -
- (id <AFURLResponseSerialization>)imageResponseSerializer {
static id <AFURLResponseSerialization> _af_defaultImageResponseSerializer = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_af_defaultImageResponseSerializer = [AFImageResponseSerializer serializer];
});
+ (AFImageDownloader *)sharedImageDownloader {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
return objc_getAssociatedObject(self, @selector(imageResponseSerializer)) ?: _af_defaultImageResponseSerializer;
return objc_getAssociatedObject(self, @selector(sharedImageDownloader)) ?: [AFImageDownloader defaultInstance];
#pragma clang diagnostic pop
}
- (void)setImageResponseSerializer:(id <AFURLResponseSerialization>)serializer {
objc_setAssociatedObject(self, @selector(imageResponseSerializer), serializer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+ (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader {
objc_setAssociatedObject(self, @selector(sharedImageDownloader), imageDownloader, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#pragma mark -
@@ -164,49 +133,62 @@ static const char * af_backgroundImageRequestOperationKeyForState(UIControlState
- (void)setImageForState:(UIControlState)state
withURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(UIImage *)placeholderImage
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse * __nullable response, UIImage *image))success
failure:(void (^)(NSError *error))failure
placeholderImage:(nullable UIImage *)placeholderImage
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure
{
[self cancelImageRequestOperationForState:state];
if ([self isActiveTaskURLEqualToURLRequest:urlRequest forState:state]) {
return;
}
UIImage *cachedImage = [[[self class] sharedImageCache] cachedImageForRequest:urlRequest];
[self cancelImageDownloadTaskForState:state];
AFImageDownloader *downloader = [[self class] sharedImageDownloader];
id <AFImageRequestCache> imageCache = downloader.imageCache;
//Use the image from the image cache if it exists
UIImage *cachedImage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil];
if (cachedImage) {
if (success) {
success(urlRequest, nil, cachedImage);
} else {
[self setImage:cachedImage forState:state];
}
[self af_setImageRequestOperation:nil forState:state];
[self af_setImageDownloadReceipt:nil forState:state];
} else {
if (placeholderImage) {
[self setImage:placeholderImage forState:state];
}
__weak __typeof(self)weakSelf = self;
AFHTTPRequestOperation *imageRequestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
imageRequestOperation.responseSerializer = self.imageResponseSerializer;
[imageRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if ([[urlRequest URL] isEqual:[operation.request URL]]) {
if (success) {
success(operation.request, operation.response, responseObject);
} else if (responseObject) {
[strongSelf setImage:responseObject forState:state];
}
}
[[[strongSelf class] sharedImageCache] cacheImage:responseObject forRequest:urlRequest];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if ([[urlRequest URL] isEqual:[operation.request URL]]) {
if (failure) {
failure(error);
}
}
}];
NSUUID *downloadID = [NSUUID UUID];
AFImageDownloadReceipt *receipt;
receipt = [downloader
downloadImageForURLRequest:urlRequest
withReceiptID:downloadID
success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if ([[strongSelf af_imageDownloadReceiptForState:state].receiptID isEqual:downloadID]) {
if (success) {
success(request, response, responseObject);
} else if(responseObject) {
[strongSelf setImage:responseObject forState:state];
}
[strongSelf af_setImageDownloadReceipt:nil forState:state];
}
[self af_setImageRequestOperation:imageRequestOperation forState:state];
[[[self class] af_sharedImageRequestOperationQueue] addOperation:imageRequestOperation];
}
failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if ([[strongSelf af_imageDownloadReceiptForState:state].receiptID isEqual:downloadID]) {
if (failure) {
failure(request, response, error);
}
[strongSelf af_setImageDownloadReceipt:nil forState:state];
}
}];
[self af_setImageDownloadReceipt:receipt forState:state];
}
}
@@ -220,7 +202,7 @@ static const char * af_backgroundImageRequestOperationKeyForState(UIControlState
- (void)setBackgroundImageForState:(UIControlState)state
withURL:(NSURL *)url
placeholderImage:(UIImage *)placeholderImage
placeholderImage:(nullable UIImage *)placeholderImage
{
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request addValue:@"image/*" forHTTPHeaderField:@"Accept"];
@@ -230,64 +212,94 @@ static const char * af_backgroundImageRequestOperationKeyForState(UIControlState
- (void)setBackgroundImageForState:(UIControlState)state
withURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(UIImage *)placeholderImage
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse * __nullable response, UIImage *image))success
failure:(void (^)(NSError *error))failure
placeholderImage:(nullable UIImage *)placeholderImage
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure
{
[self cancelBackgroundImageRequestOperationForState:state];
if ([self isActiveBackgroundTaskURLEqualToURLRequest:urlRequest forState:state]) {
return;
}
UIImage *cachedImage = [[[self class] sharedImageCache] cachedImageForRequest:urlRequest];
[self cancelBackgroundImageDownloadTaskForState:state];
AFImageDownloader *downloader = [[self class] sharedImageDownloader];
id <AFImageRequestCache> imageCache = downloader.imageCache;
//Use the image from the image cache if it exists
UIImage *cachedImage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil];
if (cachedImage) {
if (success) {
success(urlRequest, nil, cachedImage);
} else {
[self setBackgroundImage:cachedImage forState:state];
}
[self af_setBackgroundImageRequestOperation:nil forState:state];
[self af_setBackgroundImageDownloadReceipt:nil forState:state];
} else {
if (placeholderImage) {
[self setBackgroundImage:placeholderImage forState:state];
}
__weak __typeof(self)weakSelf = self;
AFHTTPRequestOperation *backgroundImageRequestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
backgroundImageRequestOperation.responseSerializer = self.imageResponseSerializer;
[backgroundImageRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if ([[urlRequest URL] isEqual:[operation.request URL]]) {
if (success) {
success(operation.request, operation.response, responseObject);
} else if (responseObject) {
[strongSelf setBackgroundImage:responseObject forState:state];
}
}
[[[strongSelf class] sharedImageCache] cacheImage:responseObject forRequest:urlRequest];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if ([[urlRequest URL] isEqual:[operation.request URL]]) {
if (failure) {
failure(error);
}
}
}];
NSUUID *downloadID = [NSUUID UUID];
AFImageDownloadReceipt *receipt;
receipt = [downloader
downloadImageForURLRequest:urlRequest
withReceiptID:downloadID
success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if ([[strongSelf af_backgroundImageDownloadReceiptForState:state].receiptID isEqual:downloadID]) {
if (success) {
success(request, response, responseObject);
} else if(responseObject) {
[strongSelf setBackgroundImage:responseObject forState:state];
}
[strongSelf af_setBackgroundImageDownloadReceipt:nil forState:state];
}
[self af_setBackgroundImageRequestOperation:backgroundImageRequestOperation forState:state];
[[[self class] af_sharedImageRequestOperationQueue] addOperation:backgroundImageRequestOperation];
}
failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if ([[strongSelf af_backgroundImageDownloadReceiptForState:state].receiptID isEqual:downloadID]) {
if (failure) {
failure(request, response, error);
}
[strongSelf af_setBackgroundImageDownloadReceipt:nil forState:state];
}
}];
[self af_setBackgroundImageDownloadReceipt:receipt forState:state];
}
}
#pragma mark -
- (void)cancelImageRequestOperationForState:(UIControlState)state {
[[self af_imageRequestOperationForState:state] cancel];
[self af_setImageRequestOperation:nil forState:state];
- (void)cancelImageDownloadTaskForState:(UIControlState)state {
AFImageDownloadReceipt *receipt = [self af_imageDownloadReceiptForState:state];
if (receipt != nil) {
[[self.class sharedImageDownloader] cancelTaskForImageDownloadReceipt:receipt];
[self af_setImageDownloadReceipt:nil forState:state];
}
}
- (void)cancelBackgroundImageRequestOperationForState:(UIControlState)state {
[[self af_backgroundImageRequestOperationForState:state] cancel];
[self af_setBackgroundImageRequestOperation:nil forState:state];
- (void)cancelBackgroundImageDownloadTaskForState:(UIControlState)state {
AFImageDownloadReceipt *receipt = [self af_backgroundImageDownloadReceiptForState:state];
if (receipt != nil) {
[[self.class sharedImageDownloader] cancelTaskForImageDownloadReceipt:receipt];
[self af_setBackgroundImageDownloadReceipt:nil forState:state];
}
}
- (BOOL)isActiveTaskURLEqualToURLRequest:(NSURLRequest *)urlRequest forState:(UIControlState)state {
AFImageDownloadReceipt *receipt = [self af_imageDownloadReceiptForState:state];
return [receipt.task.originalRequest.URL.absoluteString isEqualToString:urlRequest.URL.absoluteString];
}
- (BOOL)isActiveBackgroundTaskURLEqualToURLRequest:(NSURLRequest *)urlRequest forState:(UIControlState)state {
AFImageDownloadReceipt *receipt = [self af_backgroundImageDownloadReceiptForState:state];
return [receipt.task.originalRequest.URL.absoluteString isEqualToString:urlRequest.URL.absoluteString];
}
@end
#endif
@@ -22,7 +22,7 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS || TARGET_OS_TV
#import <UIKit/UIKit.h>
@@ -1,5 +1,5 @@
// UIImageView+AFNetworking.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -21,47 +21,36 @@
#import <Foundation/Foundation.h>
#import <Availability.h>
#import <TargetConditionals.h>
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS || TARGET_OS_TV
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@protocol AFURLResponseSerialization, AFImageCache;
@class AFImageDownloader;
/**
This category adds methods to the UIKit framework's `UIImageView` class. The methods in this category provide support for loading remote images asynchronously from a URL.
*/
@interface UIImageView (AFNetworking)
///----------------------------
/// @name Accessing Image Cache
///----------------------------
/**
The image cache used to improve image loading performance on scroll views. By default, this is an `NSCache` subclass conforming to the `AFImageCache` protocol, which listens for notification warnings and evicts objects accordingly.
*/
+ (id <AFImageCache>)sharedImageCache;
/**
Set the cache used for image loading.
@param imageCache The image cache.
*/
+ (void)setSharedImageCache:(__nullable id <AFImageCache>)imageCache;
///------------------------------------
/// @name Accessing Response Serializer
/// @name Accessing the Image Downloader
///------------------------------------
/**
The response serializer used to create an image representation from the server response and response data. By default, this is an instance of `AFImageResponseSerializer`.
Set the shared image downloader used to download images.
@discussion Subclasses of `AFImageResponseSerializer` could be used to perform post-processing, such as color correction, face detection, or other effects. See https://github.com/AFNetworking/AFCoreImageSerializer
@param imageDownloader The shared image downloader used to download images.
*/
@property (nonatomic, strong) id <AFURLResponseSerialization> imageResponseSerializer;
+ (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader;
/**
The shared image downloader used to download images.
*/
+ (AFImageDownloader *)sharedImageDownloader;
///--------------------
/// @name Setting Image
@@ -100,47 +89,21 @@ NS_ASSUME_NONNULL_BEGIN
@param urlRequest The URL request used for the image request.
@param placeholderImage The image to be set initially, until the image request finishes. If `nil`, the image view will not change its image until the image request finishes.
@param success A block to be executed when the image request operation finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the image created from the response data of request. If the image was returned from cache, the response parameter will be `nil`.
@param failure A block object to be executed when the image request operation finishes unsuccessfully, or that finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error object describing the network or parsing error that occurred.
@param success A block to be executed when the image data task finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the image created from the response data of request. If the image was returned from cache, the response parameter will be `nil`.
@param failure A block object to be executed when the image data task finishes unsuccessfully, or that finishes successfully. This block has no return value and takes three arguments: the request sent from the client, the response received from the server, and the error object describing the network or parsing error that occurred.
*/
- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(nullable UIImage *)placeholderImage
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * __nullable response, UIImage *image))success
failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * __nullable response, NSError *error))failure;
success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure;
/**
Cancels any executing image operation for the receiver, if one exists.
*/
- (void)cancelImageRequestOperation;
- (void)cancelImageDownloadTask;
@end
#pragma mark -
/**
The `AFImageCache` protocol is adopted by an object used to cache images loaded by the AFNetworking category on `UIImageView`.
*/
@protocol AFImageCache <NSObject>
/**
Returns a cached image for the specified request, if available.
@param request The image request.
@return The cached image.
*/
- (nullable UIImage *)cachedImageForRequest:(NSURLRequest *)request;
/**
Caches a particular image for the specified request.
@param image The image to cache.
@param request The request to be used as a cache key.
*/
- (void)cacheImage:(UIImage *)image
forRequest:(NSURLRequest *)request;
@end
NS_ASSUME_NONNULL_END
#endif
@@ -1,5 +1,5 @@
// UIImageView+AFNetworking.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,38 +23,22 @@
#import <objc/runtime.h>
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS || TARGET_OS_TV
#import "AFHTTPRequestOperation.h"
@interface AFImageCache : NSCache <AFImageCache>
@end
#pragma mark -
#import "AFImageDownloader.h"
@interface UIImageView (_AFNetworking)
@property (readwrite, nonatomic, strong, setter = af_setImageRequestOperation:) AFHTTPRequestOperation *af_imageRequestOperation;
@property (readwrite, nonatomic, strong, setter = af_setActiveImageDownloadReceipt:) AFImageDownloadReceipt *af_activeImageDownloadReceipt;
@end
@implementation UIImageView (_AFNetworking)
+ (NSOperationQueue *)af_sharedImageRequestOperationQueue {
static NSOperationQueue *_af_sharedImageRequestOperationQueue = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_af_sharedImageRequestOperationQueue = [[NSOperationQueue alloc] init];
_af_sharedImageRequestOperationQueue.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount;
});
return _af_sharedImageRequestOperationQueue;
- (AFImageDownloadReceipt *)af_activeImageDownloadReceipt {
return (AFImageDownloadReceipt *)objc_getAssociatedObject(self, @selector(af_activeImageDownloadReceipt));
}
- (AFHTTPRequestOperation *)af_imageRequestOperation {
return (AFHTTPRequestOperation *)objc_getAssociatedObject(self, @selector(af_imageRequestOperation));
}
- (void)af_setImageRequestOperation:(AFHTTPRequestOperation *)imageRequestOperation {
objc_setAssociatedObject(self, @selector(af_imageRequestOperation), imageRequestOperation, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- (void)af_setActiveImageDownloadReceipt:(AFImageDownloadReceipt *)imageDownloadReceipt {
objc_setAssociatedObject(self, @selector(af_activeImageDownloadReceipt), imageDownloadReceipt, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
@@ -62,46 +46,17 @@
#pragma mark -
@implementation UIImageView (AFNetworking)
@dynamic imageResponseSerializer;
+ (id <AFImageCache>)sharedImageCache {
static AFImageCache *_af_defaultImageCache = nil;
static dispatch_once_t oncePredicate;
dispatch_once(&oncePredicate, ^{
_af_defaultImageCache = [[AFImageCache alloc] init];
[[NSNotificationCenter defaultCenter] addObserverForName:UIApplicationDidReceiveMemoryWarningNotification object:nil queue:[NSOperationQueue mainQueue] usingBlock:^(NSNotification * __unused notification) {
[_af_defaultImageCache removeAllObjects];
}];
});
+ (AFImageDownloader *)sharedImageDownloader {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
return objc_getAssociatedObject(self, @selector(sharedImageCache)) ?: _af_defaultImageCache;
return objc_getAssociatedObject(self, @selector(sharedImageDownloader)) ?: [AFImageDownloader defaultInstance];
#pragma clang diagnostic pop
}
+ (void)setSharedImageCache:(__nullable id <AFImageCache>)imageCache {
objc_setAssociatedObject(self, @selector(sharedImageCache), imageCache, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#pragma mark -
- (id <AFURLResponseSerialization>)imageResponseSerializer {
static id <AFURLResponseSerialization> _af_defaultImageResponseSerializer = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_af_defaultImageResponseSerializer = [AFImageResponseSerializer serializer];
});
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
return objc_getAssociatedObject(self, @selector(imageResponseSerializer)) ?: _af_defaultImageResponseSerializer;
#pragma clang diagnostic pop
}
- (void)setImageResponseSerializer:(id <AFURLResponseSerialization>)serializer {
objc_setAssociatedObject(self, @selector(imageResponseSerializer), serializer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+ (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader {
objc_setAssociatedObject(self, @selector(sharedImageDownloader), imageDownloader, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
#pragma mark -
@@ -121,93 +76,84 @@
- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest
placeholderImage:(UIImage *)placeholderImage
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse * __nullable response, UIImage *image))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse * __nullable response, NSError *error))failure
success:(void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success
failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure
{
[self cancelImageRequestOperation];
UIImage *cachedImage = [[[self class] sharedImageCache] cachedImageForRequest:urlRequest];
if ([urlRequest URL] == nil) {
[self cancelImageDownloadTask];
self.image = placeholderImage;
return;
}
if ([self isActiveTaskURLEqualToURLRequest:urlRequest]){
return;
}
[self cancelImageDownloadTask];
AFImageDownloader *downloader = [[self class] sharedImageDownloader];
id <AFImageRequestCache> imageCache = downloader.imageCache;
//Use the image from the image cache if it exists
UIImage *cachedImage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil];
if (cachedImage) {
if (success) {
success(urlRequest, nil, cachedImage);
} else {
self.image = cachedImage;
}
self.af_imageRequestOperation = nil;
[self clearActiveDownloadInformation];
} else {
if (placeholderImage) {
self.image = placeholderImage;
}
__weak __typeof(self)weakSelf = self;
self.af_imageRequestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:urlRequest];
self.af_imageRequestOperation.responseSerializer = self.imageResponseSerializer;
[self.af_imageRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if ([[urlRequest URL] isEqual:[strongSelf.af_imageRequestOperation.request URL]]) {
if (success) {
success(urlRequest, operation.response, responseObject);
} else if (responseObject) {
strongSelf.image = responseObject;
}
NSUUID *downloadID = [NSUUID UUID];
AFImageDownloadReceipt *receipt;
receipt = [downloader
downloadImageForURLRequest:urlRequest
withReceiptID:downloadID
success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if ([strongSelf.af_activeImageDownloadReceipt.receiptID isEqual:downloadID]) {
if (success) {
success(request, response, responseObject);
} else if(responseObject) {
strongSelf.image = responseObject;
}
[strongSelf clearActiveDownloadInformation];
}
if (operation == strongSelf.af_imageRequestOperation){
strongSelf.af_imageRequestOperation = nil;
}
}
}
failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if ([strongSelf.af_activeImageDownloadReceipt.receiptID isEqual:downloadID]) {
if (failure) {
failure(request, response, error);
}
[strongSelf clearActiveDownloadInformation];
}
}];
[[[strongSelf class] sharedImageCache] cacheImage:responseObject forRequest:urlRequest];
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
if ([[urlRequest URL] isEqual:[strongSelf.af_imageRequestOperation.request URL]]) {
if (failure) {
failure(urlRequest, operation.response, error);
}
if (operation == strongSelf.af_imageRequestOperation){
strongSelf.af_imageRequestOperation = nil;
}
}
}];
[[[self class] af_sharedImageRequestOperationQueue] addOperation:self.af_imageRequestOperation];
self.af_activeImageDownloadReceipt = receipt;
}
}
- (void)cancelImageRequestOperation {
[self.af_imageRequestOperation cancel];
self.af_imageRequestOperation = nil;
- (void)cancelImageDownloadTask {
if (self.af_activeImageDownloadReceipt != nil) {
[[self.class sharedImageDownloader] cancelTaskForImageDownloadReceipt:self.af_activeImageDownloadReceipt];
[self clearActiveDownloadInformation];
}
}
@end
#pragma mark -
static inline NSString * AFImageCacheKeyFromURLRequest(NSURLRequest *request) {
return [[request URL] absoluteString];
- (void)clearActiveDownloadInformation {
self.af_activeImageDownloadReceipt = nil;
}
@implementation AFImageCache
- (UIImage *)cachedImageForRequest:(NSURLRequest *)request {
switch ([request cachePolicy]) {
case NSURLRequestReloadIgnoringCacheData:
case NSURLRequestReloadIgnoringLocalAndRemoteCacheData:
return nil;
default:
break;
}
return [self objectForKey:AFImageCacheKeyFromURLRequest(request)];
}
- (void)cacheImage:(UIImage *)image
forRequest:(NSURLRequest *)request
{
if (image && request) {
[self setObject:image forKey:AFImageCacheKeyFromURLRequest(request)];
}
- (BOOL)isActiveTaskURLEqualToURLRequest:(NSURLRequest *)urlRequest {
return [self.af_activeImageDownloadReceipt.task.originalRequest.URL.absoluteString isEqualToString:urlRequest.URL.absoluteString];
}
@end
@@ -1,6 +1,6 @@
// UIKit+AFNetworking.h
//
// Copyright (c) 2013 AFNetworking (http://afnetworking.com/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -20,20 +20,23 @@
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#if TARGET_OS_IOS
#if TARGET_OS_IOS || TARGET_OS_TV
#import <UIKit/UIKit.h>
#ifndef _UIKIT_AFNETWORKING_
#define _UIKIT_AFNETWORKING_
#if TARGET_OS_IOS
#import "AFAutoPurgingImageCache.h"
#import "AFImageDownloader.h"
#import "AFNetworkActivityIndicatorManager.h"
#import "UIRefreshControl+AFNetworking.h"
#import "UIWebView+AFNetworking.h"
#endif
#import "UIActivityIndicatorView+AFNetworking.h"
#import "UIAlertView+AFNetworking.h"
#import "UIButton+AFNetworking.h"
#import "UIImageView+AFNetworking.h"
#import "UIProgressView+AFNetworking.h"
#import "UIRefreshControl+AFNetworking.h"
#import "UIWebView+AFNetworking.h"
#endif /* _UIKIT_AFNETWORKING_ */
#endif
@@ -1,5 +1,5 @@
// UIProgressView+AFNetworking.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -21,18 +21,17 @@
#import <Foundation/Foundation.h>
#import <Availability.h>
#import <TargetConditionals.h>
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS || TARGET_OS_TV
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class AFURLConnectionOperation;
/**
This category adds methods to the UIKit framework's `UIProgressView` class. The methods in this category provide support for binding the progress to the upload and download progress of a session task or request operation.
This category adds methods to the UIKit framework's `UIProgressView` class. The methods in this category provide support for binding the progress to the upload and download progress of a session task.
*/
@interface UIProgressView (AFNetworking)
@@ -46,10 +45,8 @@ NS_ASSUME_NONNULL_BEGIN
@param task The session task.
@param animated `YES` if the change should be animated, `NO` if the change should happen immediately.
*/
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
- (void)setProgressWithUploadProgressOfTask:(NSURLSessionUploadTask *)task
animated:(BOOL)animated;
#endif
/**
Binds the progress to the download progress of the specified session task.
@@ -57,32 +54,8 @@ NS_ASSUME_NONNULL_BEGIN
@param task The session task.
@param animated `YES` if the change should be animated, `NO` if the change should happen immediately.
*/
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
- (void)setProgressWithDownloadProgressOfTask:(NSURLSessionDownloadTask *)task
animated:(BOOL)animated;
#endif
///------------------------------------
/// @name Setting Session Task Progress
///------------------------------------
/**
Binds the progress to the upload progress of the specified request operation.
@param operation The request operation.
@param animated `YES` if the change should be animated, `NO` if the change should happen immediately.
*/
- (void)setProgressWithUploadProgressOfOperation:(AFURLConnectionOperation *)operation
animated:(BOOL)animated;
/**
Binds the progress to the download progress of the specified request operation.
@param operation The request operation.
@param animated `YES` if the change should be animated, `NO` if the change should happen immediately.
*/
- (void)setProgressWithDownloadProgressOfOperation:(AFURLConnectionOperation *)operation
animated:(BOOL)animated;
@end
@@ -1,5 +1,5 @@
// UIProgressView+AFNetworking.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,33 +23,13 @@
#import <objc/runtime.h>
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS || TARGET_OS_TV
#import "AFURLConnectionOperation.h"
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
#import "AFURLSessionManager.h"
#endif
static void * AFTaskCountOfBytesSentContext = &AFTaskCountOfBytesSentContext;
static void * AFTaskCountOfBytesReceivedContext = &AFTaskCountOfBytesReceivedContext;
@interface AFURLConnectionOperation (_UIProgressView)
@property (readwrite, nonatomic, copy) void (^uploadProgress)(NSUInteger bytes, long long totalBytes, long long totalBytesExpected);
@property (readwrite, nonatomic, assign, setter = af_setUploadProgressAnimated:) BOOL af_uploadProgressAnimated;
@property (readwrite, nonatomic, copy) void (^downloadProgress)(NSUInteger bytes, long long totalBytes, long long totalBytesExpected);
@property (readwrite, nonatomic, assign, setter = af_setDownloadProgressAnimated:) BOOL af_downloadProgressAnimated;
@end
@implementation AFURLConnectionOperation (_UIProgressView)
@dynamic uploadProgress; // Implemented in AFURLConnectionOperation
@dynamic af_uploadProgressAnimated;
@dynamic downloadProgress; // Implemented in AFURLConnectionOperation
@dynamic af_downloadProgressAnimated;
@end
#pragma mark -
@implementation UIProgressView (AFNetworking)
@@ -72,7 +52,6 @@ static void * AFTaskCountOfBytesReceivedContext = &AFTaskCountOfBytesReceivedCon
#pragma mark -
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
- (void)setProgressWithUploadProgressOfTask:(NSURLSessionUploadTask *)task
animated:(BOOL)animated
{
@@ -90,47 +69,6 @@ static void * AFTaskCountOfBytesReceivedContext = &AFTaskCountOfBytesReceivedCon
[self af_setDownloadProgressAnimated:animated];
}
#endif
#pragma mark -
- (void)setProgressWithUploadProgressOfOperation:(AFURLConnectionOperation *)operation
animated:(BOOL)animated
{
__weak __typeof(self)weakSelf = self;
void (^original)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) = [operation.uploadProgress copy];
[operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) {
if (original) {
original(bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
}
dispatch_async(dispatch_get_main_queue(), ^{
if (totalBytesExpectedToWrite > 0) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf setProgress:(totalBytesWritten / (totalBytesExpectedToWrite * 1.0f)) animated:animated];
}
});
}];
}
- (void)setProgressWithDownloadProgressOfOperation:(AFURLConnectionOperation *)operation
animated:(BOOL)animated
{
__weak __typeof(self)weakSelf = self;
void (^original)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) = [operation.downloadProgress copy];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
if (original) {
original(bytesRead, totalBytesRead, totalBytesExpectedToRead);
}
dispatch_async(dispatch_get_main_queue(), ^{
if (totalBytesExpectedToRead > 0) {
__strong __typeof(weakSelf)strongSelf = weakSelf;
[strongSelf setProgress:(totalBytesRead / (totalBytesExpectedToRead * 1.0f)) animated:animated];
}
});
}];
}
#pragma mark - NSKeyValueObserving
@@ -139,7 +77,6 @@ static void * AFTaskCountOfBytesReceivedContext = &AFTaskCountOfBytesReceivedCon
change:(__unused NSDictionary *)change
context:(void *)context
{
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
if (context == AFTaskCountOfBytesSentContext || context == AFTaskCountOfBytesReceivedContext) {
if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) {
if ([object countOfBytesExpectedToSend] > 0) {
@@ -174,7 +111,6 @@ static void * AFTaskCountOfBytesReceivedContext = &AFTaskCountOfBytesReceivedCon
}
}
}
#endif
}
@end
@@ -1,6 +1,6 @@
// UIRefreshControl+AFNetworking.m
//
// Copyright (c) 2014 AFNetworking (http://afnetworking.com)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -22,18 +22,16 @@
#import <Foundation/Foundation.h>
#import <Availability.h>
#import <TargetConditionals.h>
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class AFURLConnectionOperation;
/**
This category adds methods to the UIKit framework's `UIRefreshControl` class. The methods in this category provide support for automatically beginning and ending refreshing depending on the loading state of a request operation or session task.
This category adds methods to the UIKit framework's `UIRefreshControl` class. The methods in this category provide support for automatically beginning and ending refreshing depending on the loading state of a session task.
*/
@interface UIRefreshControl (AFNetworking)
@@ -46,20 +44,7 @@ NS_ASSUME_NONNULL_BEGIN
@param task The task. If `nil`, automatic updating from any previously specified operation will be disabled.
*/
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
- (void)setRefreshingWithStateOfTask:(NSURLSessionTask *)task;
#endif
///----------------------------------------
/// @name Refreshing for Request Operations
///----------------------------------------
/**
Binds the refreshing state to the execution state of the specified operation.
@param operation The operation. If `nil`, automatic updating from any previously specified operation will be disabled.
*/
- (void)setRefreshingWithStateOfOperation:(AFURLConnectionOperation *)operation;
@end
@@ -1,6 +1,6 @@
// UIRefreshControl+AFNetworking.m
//
// Copyright (c) 2014 AFNetworking (http://afnetworking.com)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,22 +23,15 @@
#import "UIRefreshControl+AFNetworking.h"
#import <objc/runtime.h>
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS
#import "AFHTTPRequestOperation.h"
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
#import "AFURLSessionManager.h"
#endif
@interface AFRefreshControlNotificationObserver : NSObject
@property (readonly, nonatomic, weak) UIRefreshControl *refreshControl;
- (instancetype)initWithActivityRefreshControl:(UIRefreshControl *)refreshControl;
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
- (void)setRefreshingWithStateOfTask:(NSURLSessionTask *)task;
#endif
- (void)setRefreshingWithStateOfOperation:(AFURLConnectionOperation *)operation;
@end
@@ -53,15 +46,9 @@
return notificationObserver;
}
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
- (void)setRefreshingWithStateOfTask:(NSURLSessionTask *)task {
[[self af_notificationObserver] setRefreshingWithStateOfTask:task];
}
#endif
- (void)setRefreshingWithStateOfOperation:(AFURLConnectionOperation *)operation {
[[self af_notificationObserver] setRefreshingWithStateOfOperation:operation];
}
@end
@@ -76,7 +63,6 @@
return self;
}
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
- (void)setRefreshingWithStateOfTask:(NSURLSessionTask *)task {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
@@ -100,31 +86,6 @@
#pragma clang diagnostic pop
}
}
#endif
- (void)setRefreshingWithStateOfOperation:(AFURLConnectionOperation *)operation {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter removeObserver:self name:AFNetworkingOperationDidStartNotification object:nil];
[notificationCenter removeObserver:self name:AFNetworkingOperationDidFinishNotification object:nil];
if (operation) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wreceiver-is-weak"
#pragma clang diagnostic ignored "-Warc-repeated-use-of-weak"
if (![operation isFinished]) {
if ([operation isExecuting]) {
[self.refreshControl beginRefreshing];
} else {
[self.refreshControl endRefreshing];
}
[notificationCenter addObserver:self selector:@selector(af_beginRefreshing) name:AFNetworkingOperationDidStartNotification object:operation];
[notificationCenter addObserver:self selector:@selector(af_endRefreshing) name:AFNetworkingOperationDidFinishNotification object:operation];
}
#pragma clang diagnostic pop
}
}
#pragma mark -
@@ -151,14 +112,9 @@
- (void)dealloc {
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
[notificationCenter removeObserver:self name:AFNetworkingTaskDidCompleteNotification object:nil];
[notificationCenter removeObserver:self name:AFNetworkingTaskDidResumeNotification object:nil];
[notificationCenter removeObserver:self name:AFNetworkingTaskDidSuspendNotification object:nil];
#endif
[notificationCenter removeObserver:self name:AFNetworkingOperationDidStartNotification object:nil];
[notificationCenter removeObserver:self name:AFNetworkingOperationDidFinishNotification object:nil];
}
@end
@@ -1,5 +1,5 @@
// UIWebView+AFNetworking.h
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -21,16 +21,15 @@
#import <Foundation/Foundation.h>
#import <Availability.h>
#import <TargetConditionals.h>
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@class AFHTTPRequestSerializer, AFHTTPResponseSerializer;
@protocol AFURLRequestSerialization, AFURLResponseSerialization;
@class AFHTTPSessionManager;
/**
This category adds methods to the UIKit framework's `UIWebView` class. The methods in this category provide increased control over the request cycle, including progress monitoring and success / failure handling.
@@ -40,25 +39,20 @@ NS_ASSUME_NONNULL_BEGIN
@interface UIWebView (AFNetworking)
/**
The request serializer used to serialize requests made with the `-loadRequest:...` category methods. By default, this is an instance of `AFHTTPRequestSerializer`.
The session manager used to download all requests.
*/
@property (nonatomic, strong) AFHTTPRequestSerializer <AFURLRequestSerialization> * requestSerializer;
/**
The response serializer used to serialize responses made with the `-loadRequest:...` category methods. By default, this is an instance of `AFHTTPResponseSerializer`.
*/
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
@property (nonatomic, strong) AFHTTPSessionManager *sessionManager;
/**
Asynchronously loads the specified request.
@param request A URL request identifying the location of the content to load. This must not be `nil`.
@param progress A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes three arguments: the number of bytes read since the last time the download progress block was called, the total bytes read, and the total bytes expected to be read during the request, as initially determined by the expected content size of the `NSHTTPURLResponse` object. This block may be called multiple times, and will execute on the main thread.
@param progress A progress object monitoring the current download progress.
@param success A block object to be executed when the request finishes loading successfully. This block returns the HTML string to be loaded by the web view, and takes two arguments: the response, and the response string.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error that occurred.
@param failure A block object to be executed when the data task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error that occurred.
*/
- (void)loadRequest:(NSURLRequest *)request
progress:(nullable void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
progress:(NSProgress * _Nullable __autoreleasing * _Nullable)progress
success:(nullable NSString * (^)(NSHTTPURLResponse *response, NSString *HTML))success
failure:(nullable void (^)(NSError *error))failure;
@@ -68,14 +62,14 @@ NS_ASSUME_NONNULL_BEGIN
@param request A URL request identifying the location of the content to load. This must not be `nil`.
@param MIMEType The MIME type of the content. Defaults to the content type of the response if not specified.
@param textEncodingName The IANA encoding name, as in `utf-8` or `utf-16`. Defaults to the response text encoding if not specified.
@param progress A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes three arguments: the number of bytes read since the last time the download progress block was called, the total bytes read, and the total bytes expected to be read during the request, as initially determined by the expected content size of the `NSHTTPURLResponse` object. This block may be called multiple times, and will execute on the main thread.
@param progress A progress object monitoring the current download progress.
@param success A block object to be executed when the request finishes loading successfully. This block returns the data to be loaded by the web view and takes two arguments: the response, and the downloaded data.
@param failure A block object to be executed when the request operation finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error that occurred.
@param failure A block object to be executed when the data task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a single argument: the error that occurred.
*/
- (void)loadRequest:(NSURLRequest *)request
MIMEType:(nullable NSString *)MIMEType
textEncodingName:(nullable NSString *)textEncodingName
progress:(nullable void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
progress:(NSProgress * _Nullable __autoreleasing * _Nullable)progress
success:(nullable NSData * (^)(NSHTTPURLResponse *response, NSData *data))success
failure:(nullable void (^)(NSError *error))failure;
@@ -1,5 +1,5 @@
// UIWebView+AFNetworking.m
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@@ -23,24 +23,24 @@
#import <objc/runtime.h>
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
#if TARGET_OS_IOS
#import "AFHTTPRequestOperation.h"
#import "AFHTTPSessionManager.h"
#import "AFURLResponseSerialization.h"
#import "AFURLRequestSerialization.h"
@interface UIWebView (_AFNetworking)
@property (readwrite, nonatomic, strong, setter = af_setHTTPRequestOperation:) AFHTTPRequestOperation *af_HTTPRequestOperation;
@property (readwrite, nonatomic, strong, setter = af_setURLSessionTask:) NSURLSessionDataTask *af_URLSessionTask;
@end
@implementation UIWebView (_AFNetworking)
- (AFHTTPRequestOperation *)af_HTTPRequestOperation {
return (AFHTTPRequestOperation *)objc_getAssociatedObject(self, @selector(af_HTTPRequestOperation));
- (NSURLSessionDataTask *)af_URLSessionTask {
return (NSURLSessionDataTask *)objc_getAssociatedObject(self, @selector(af_URLSessionTask));
}
- (void)af_setHTTPRequestOperation:(AFHTTPRequestOperation *)operation {
objc_setAssociatedObject(self, @selector(af_HTTPRequestOperation), operation, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- (void)af_setURLSessionTask:(NSURLSessionDataTask *)af_URLSessionTask {
objc_setAssociatedObject(self, @selector(af_URLSessionTask), af_URLSessionTask, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
@end
@@ -49,21 +49,23 @@
@implementation UIWebView (AFNetworking)
- (AFHTTPRequestSerializer <AFURLRequestSerialization> *)requestSerializer {
static AFHTTPRequestSerializer <AFURLRequestSerialization> *_af_defaultRequestSerializer = nil;
- (AFHTTPSessionManager *)sessionManager {
static AFHTTPSessionManager *_af_defaultHTTPSessionManager = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_af_defaultRequestSerializer = [AFHTTPRequestSerializer serializer];
_af_defaultHTTPSessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
_af_defaultHTTPSessionManager.requestSerializer = [AFHTTPRequestSerializer serializer];
_af_defaultHTTPSessionManager.responseSerializer = [AFHTTPResponseSerializer serializer];
});
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
return objc_getAssociatedObject(self, @selector(requestSerializer)) ?: _af_defaultRequestSerializer;
return objc_getAssociatedObject(self, @selector(sessionManager)) ?: _af_defaultHTTPSessionManager;
#pragma clang diagnostic pop
}
- (void)setRequestSerializer:(AFHTTPRequestSerializer<AFURLRequestSerialization> *)requestSerializer {
objc_setAssociatedObject(self, @selector(requestSerializer), requestSerializer, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
- (void)setSessionManager:(AFHTTPSessionManager *)sessionManager {
objc_setAssociatedObject(self, @selector(sessionManager), sessionManager, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
}
- (AFHTTPResponseSerializer <AFURLResponseSerialization> *)responseSerializer {
@@ -86,7 +88,7 @@
#pragma mark -
- (void)loadRequest:(NSURLRequest *)request
progress:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
progress:(NSProgress * _Nullable __autoreleasing * _Nullable)progress
success:(NSString * (^)(NSHTTPURLResponse *response, NSString *HTML))success
failure:(void (^)(NSError *error))failure
{
@@ -111,43 +113,44 @@
- (void)loadRequest:(NSURLRequest *)request
MIMEType:(NSString *)MIMEType
textEncodingName:(NSString *)textEncodingName
progress:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))progress
progress:(NSProgress * _Nullable __autoreleasing * _Nullable)progress
success:(NSData * (^)(NSHTTPURLResponse *response, NSData *data))success
failure:(void (^)(NSError *error))failure
{
NSParameterAssert(request);
if (self.af_HTTPRequestOperation) {
[self.af_HTTPRequestOperation cancel];
if (self.af_URLSessionTask.state == NSURLSessionTaskStateRunning || self.af_URLSessionTask.state == NSURLSessionTaskStateSuspended) {
[self.af_URLSessionTask cancel];
}
request = [self.requestSerializer requestBySerializingRequest:request withParameters:nil error:nil];
self.af_HTTPRequestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
self.af_HTTPRequestOperation.responseSerializer = self.responseSerializer;
self.af_URLSessionTask = nil;
__weak __typeof(self)weakSelf = self;
[self.af_HTTPRequestOperation setDownloadProgressBlock:progress];
[self.af_HTTPRequestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id __unused responseObject) {
NSData *data = success ? success(operation.response, operation.responseData) : operation.responseData;
NSURLSessionDataTask *dataTask;
dataTask = [self.sessionManager
GET:request.URL.absoluteString
parameters:nil
progress:nil
success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) {
__strong __typeof(weakSelf) strongSelf = weakSelf;
if (success) {
success((NSHTTPURLResponse *)task.response, responseObject);
}
[strongSelf loadData:responseObject MIMEType:MIMEType textEncodingName:textEncodingName baseURL:[task.currentRequest URL]];
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu"
__strong __typeof(weakSelf) strongSelf = weakSelf;
[strongSelf loadData:data MIMEType:(MIMEType ?: [operation.response MIMEType]) textEncodingName:(textEncodingName ?: [operation.response textEncodingName]) baseURL:[operation.response URL]];
if ([strongSelf.delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) {
[strongSelf.delegate webViewDidFinishLoad:strongSelf];
}
#pragma clang diagnostic pop
} failure:^(AFHTTPRequestOperation * __unused operation, NSError *error) {
if (failure) {
failure(error);
}
}];
[self.af_HTTPRequestOperation start];
if ([strongSelf.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[strongSelf.delegate webViewDidFinishLoad:strongSelf];
}
}
failure:^(NSURLSessionDataTask * _Nonnull task, NSError * _Nonnull error) {
if (failure) {
failure(error);
}
}];
self.af_URLSessionTask = dataTask;
if (progress != nil) {
*progress = [self.sessionManager downloadProgressForTask:dataTask];
}
[self.af_URLSessionTask resume];
if ([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) {
[self.delegate webViewDidStartLoad:self];
@@ -156,4 +159,4 @@
@end
#endif
#endif
@@ -41,12 +41,12 @@ class SignUpRequestManager: NSObject {
}
let baseURLString: String
let manager: AFHTTPRequestOperationManager
let manager: AFHTTPSessionManager
let sessionManager: AFURLSessionManager
init(baseURLString: String = "") {
self.baseURLString = baseURLString
manager = AFHTTPRequestOperationManager(baseURL: URL(string: baseURLString))
manager = AFHTTPSessionManager(baseURL: URL(string: baseURLString))
manager.requestSerializer = AFJSONRequestSerializer() as AFHTTPRequestSerializer
manager.requestSerializer.timeoutInterval = Application.RequestTimeout
manager.responseSerializer = AFJSONResponseSerializer() as AFHTTPResponseSerializer
@@ -65,7 +65,7 @@ class SignUpRequestManager: NSObject {
{
let urlString = "\(basePathString)/access_token"
manager.requestSerializer.setAuthorizationHeaderFieldWithUsername(userName, password: password)
manager.post(urlString, parameters: nil, success: { (requestOperation, responseObject) in
manager.post(urlString, parameters: nil, progress: nil, success: { (requestOperation, responseObject) in
self.postAccessTokenSuccess(responseObject: responseObject, success: success, failure: failure)
}) { (requestOperation, error) in
self.postAccessTokenFailure(error: error, failure: failure)
@@ -113,7 +113,7 @@ class SignUpRequestManager: NSObject {
failure: @escaping (_ error: Error, _ message: String?) -> Void)
{
if let urlString = "\(basePathString)/create_user?username=\(userName)&email=\(email)&fullName=\(fullName)&company=\(company)&password=\(password)".addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) {
manager.post(urlString, parameters: nil, success: { (requestOperation, responseObject) in
manager.post(urlString, parameters: nil, progress: nil, success: { (requestOperation, responseObject) in
self.postCreateUserSuccess(responseObject: responseObject, success: success, failure: failure)
}) { (requestOperation, error) in
self.postCreateUserFailure(error: error, failure: failure)
@@ -180,7 +180,7 @@ class SignUpRequestManager: NSObject {
success: @escaping () -> Void,
failure: @escaping (_ error: Error, _ message: String?) -> Void)
{
manager.post(urlString, parameters: nil, success: { (requestOperation, responseObject) in
manager.post(urlString, parameters: nil, progress: nil, success: { (requestOperation, responseObject) in
self.postForgotPasswordSuccess(responseObject: responseObject, success: success, failure: failure)
}) { (requestOperation, error) in
self.postForgotPasswordFailure(error: error, failure: failure)
@@ -209,7 +209,7 @@ class SignUpRequestManager: NSObject {
failure: @escaping (_ error: Error, _ message: String?) -> Void)
{
let urlString = "\(basePathString)/hello"
manager.post(urlString, parameters: nil, success: { (requestOperation, responseObject) in
manager.post(urlString, parameters: nil, progress: nil, success: { (requestOperation, responseObject) in
self.postHelloSuccess(responseObject: responseObject, success: success, failure: failure)
}) { (requestOperation, error) in
self.postHelloFailure(error: error, failure: failure)
@@ -254,7 +254,7 @@ class SignUpRequestManager: NSObject {
{
let urlString = "\(basePathString)/logout/"
manager.requestSerializer.clearAuthorizationHeader()
manager.post(urlString, parameters: nil, success: { (requestOperation, responseObject) in
manager.post(urlString, parameters: nil, progress: nil, success: { (requestOperation, responseObject) in
self.postLogoutSuccess(success: success)
}) { (requestOperation, error) in
self.postLogoutFailure(error: error, failure: failure)
@@ -19,12 +19,12 @@ class TrainingRequestManager: NSObject {
fileprivate let basePathString = "/sailingserver/api/v1"
let baseURLString: String
let manager: AFHTTPRequestOperationManager
let manager: AFHTTPSessionManager
let sessionManager: AFURLSessionManager
init(baseURLString: String = "") {
self.baseURLString = baseURLString
manager = AFHTTPRequestOperationManager(baseURL: URL(string: baseURLString))
manager = AFHTTPSessionManager(baseURL: URL(string: baseURLString))
manager.requestSerializer = AFHTTPRequestSerializer()
manager.requestSerializer.timeoutInterval = Application.RequestTimeout
manager.responseSerializer = AFHTTPResponseSerializer()
@@ -59,7 +59,7 @@ class TrainingRequestManager: NSObject {
body["createregatta"] = "true" as AnyObject
body["boatclassname"] = boatClassName as AnyObject
body["numberofraces"] = "0" as AnyObject
manager.post(urlString, parameters: body, success: { (requestOperation, responseObject) in
manager.post(urlString, parameters: body, progress: nil, success: { (requestOperation, responseObject) in
self.postCreateEventSuccess(responseObject: responseObject, success: success, failure: failure)
}) { (requestOperation, error) in
self.postCreateEventFailure(error: error, failure: failure)
@@ -133,7 +133,7 @@ class TrainingRequestManager: NSObject {
let encodedRegattaName = regattaName.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? ""
let encodedCompetitorID = competitorID.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
let urlString = "\(basePathString)/regattas/\(encodedRegattaName)/competitors/\(encodedCompetitorID)/add"
manager.post(urlString, parameters: nil, success: { (requestOperation, responseObject) in
manager.post(urlString, parameters: nil, progress: nil, success: { (requestOperation, responseObject) in
self.postRegattaCompetitorAddSuccess(responseObject: responseObject, success: success)
}) { (requestOperation, error) in
self.postRegattaCompetitorAddFailure(error: error, failure: failure)
@@ -165,7 +165,7 @@ class TrainingRequestManager: NSObject {
let encodedSailID = sailID.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
let encodedNationality = nationality.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
let urlString = "\(basePathString)/regattas/\(encodedRegattaName)/competitors/createandadd?boatclass=\(encodedBoatClassName)&sailid=\(encodedSailID)&nationalityIOC=\(encodedNationality)"
manager.post(urlString, parameters: nil, success: { (requestOperation, responseObject) in
manager.post(urlString, parameters: nil, progress: nil, success: { (requestOperation, responseObject) in
self.postRegattaCompetitorCreateAndAddSuccess(responseObject: responseObject, success: success, failure: failure)
}) { (requestOperation, error) in
self.postRegattaCompetitorCreateAndAddFailure(error: error, failure: failure)
@@ -203,7 +203,7 @@ class TrainingRequestManager: NSObject {
{
let encodedRegattaName = regattaName.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? ""
let urlString = "\(basePathString)/regattas/\(encodedRegattaName)/addracecolumns"
manager.post(urlString, parameters: nil, success: { (requestOperation, responseObject) in
manager.post(urlString, parameters: nil, progress: nil, success: { (requestOperation, responseObject) in
self.postRegattaRaceColumnAddSuccess(responseObject: responseObject, success: success, failure: failure)
}) { (requestOperation, error) in
self.postRegattaRaceColumnAddAddFailure(error: error, failure: failure)
@@ -280,7 +280,7 @@ class TrainingRequestManager: NSObject {
let encodedRaceColumnName = raceColumnName.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
let encodedFleetName = fleetName.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
let urlString = "\(basePathString)/leaderboards/\(encodedLeaderboardName)/settrackingtimes?race_column=\(encodedRaceColumnName)&fleet=\(encodedFleetName)&\(millisParameter)=\(millisSince1970())"
manager.post(urlString, parameters: nil, success: { (requestOperation, responseObject) in
manager.post(urlString, parameters: nil, progress: nil, success: { (requestOperation, responseObject) in
self.postLeaderboardRaceSetTrackingTimeMillisSuccess(responseObject: responseObject, success: success)
}) { (requestOperation, error) in
self.postLeaderboardRaceSetTrackingTimeMillisFailure(error: error, failure: failure)
@@ -310,7 +310,7 @@ class TrainingRequestManager: NSObject {
let encodedRaceColumnName = raceColumnName.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
let encodedFleetName = fleetName.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
let urlString = "\(basePathString)/leaderboards/\(encodedLeaderboardName)/starttracking?race_column=\(encodedRaceColumnName)&fleet=\(encodedFleetName)"
manager.post(urlString, parameters: nil, success: { (requestOperation, responseObject) in
manager.post(urlString, parameters: nil, progress: nil, success: { (requestOperation, responseObject) in
self.postLeaderboardStartTrackingSuccess(responseObject: responseObject, success: success)
}) { (requestOperation, error) in
self.postLeaderboardStartTrackingFailure(error: error, failure: failure)
@@ -366,7 +366,7 @@ class TrainingRequestManager: NSObject {
let encodedLeaderboardName = leaderboardName.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? ""
let encodedQuery = query.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
let urlString = "\(basePathString)/leaderboards/\(encodedLeaderboardName)/stoptracking?\(encodedQuery)"
manager.post(urlString, parameters: nil, success: { (requestOperation, responseObject) in
manager.post(urlString, parameters: nil, progress: nil, success: { (requestOperation, responseObject) in
self.postLeaderboardStopTrackingSuccess(responseObject: responseObject, success: success)
}) { (requestOperation, error) in
self.postLeaderboardStopTrackingFailure(error: error, failure: failure)
@@ -392,7 +392,7 @@ class TrainingRequestManager: NSObject {
{
let encodedLeaderboardName = leaderboardName.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? ""
let urlString = "\(basePathString)/leaderboardgroups/\(encodedLeaderboardName)"
manager.get(urlString, parameters: nil, success: { (requestOperation, responseObject) in
manager.get(urlString, parameters: nil, progress: nil, success: { (requestOperation, responseObject) in
self.getLeaderboardGroupSuccess(responseObject: responseObject, success: success, failure: failure)
}) { (requestOperation, error) in
self.getLeaderboardGroupFailure(error: error, failure: failure)
@@ -432,7 +432,7 @@ class TrainingRequestManager: NSObject {
let encodedRegattaName = regattaName.addingPercentEncoding(withAllowedCharacters: .urlPathAllowed) ?? ""
let encodedRaceName = raceName.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
let urlString = "\(basePathString)/regattas/\(encodedRegattaName)/races/\(encodedRaceName)/course"
manager.get(urlString, parameters: nil, success: { (requestOperation, responseObject) in
manager.get(urlString, parameters: nil, progress: nil, success: { (requestOperation, responseObject) in
self.getRegattaRaceCourseSuccess(responseObject: responseObject, success: success, failure: failure)
}) { (requestOperation, error) in
self.getRegattaRaceCourseFailure(error: error, failure: failure)
@@ -474,7 +474,7 @@ class TrainingRequestManager: NSObject {
let encodedRaceColumnName = raceColumnName.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
let encodedFleetName = fleetName.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? ""
let urlString = "\(basePathString)/leaderboards/\(encodedLeaderboardName)/autocourse?race_column=\(encodedRaceColumnName)&fleet=\(encodedFleetName)"
manager.post(urlString, parameters: nil, success: { (requestOperation, responseObject) in
manager.post(urlString, parameters: nil, progress: nil, success: { (requestOperation, responseObject) in
self.postLeaderboardAutoCourseSuccess(responseObject: responseObject, success: success, failure: failure)
}) { (requestOperation, error) in
self.postLeaderboardAutoCourseFailure(error: error, failure: failure)
@@ -31,6 +31,7 @@ public enum BoatClassMasterdata {
CANOE_TAIFUN ("Canoe Taifun", true, 5.20, 1.32, BoatHullType.MONOHULL, false, "Taifun", "Taifun Kanu", "Kanu Taifun"),
CONTENDER ("Contender", true, 4.88, 1.42, BoatHullType.MONOHULL, false),
CC_30 ("C&C 30", true, 9.12, 3.25, BoatHullType.MONOHULL, true),
CLUB_SWAN_50 ("Club Swan 50", true, 16.74, 4.20, BoatHullType.MONOHULL, true, "ClubSwan50"),
D_ONE ("D-One", true, 4.23, 2.31, BoatHullType.MONOHULL, true, "Devoti D-One", "DOne", "D_One"),
DRAGON_INT ("Dragon Int.", true, 8.89, 1.96, BoatHullType.MONOHULL, true, "Drachen", "Dragon"),
DELPHIA_24 ("Delphia 24", true, 7.70, 2.50, BoatHullType.MONOHULL, true, "Delphia 24 One Design", "Delphia 24 OD"),
@@ -5,10 +5,9 @@ import static com.sap.sailing.domain.common.SortingOrder.DESCENDING;
import static com.sap.sailing.domain.common.SortingOrder.NONE;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.LinkedHashSet;
/**
* Identifies details that can be requested from the racing service. Optionally, the details can specify a precision as
@@ -244,11 +243,11 @@ public enum DetailType implements Serializable {
}
/**
* Special List of DetailTypes, that allows operators to select for example the RideHeight, that is usually only
* selectable, if it already has data.
* Special collection of {@link DetailType}s, that allows operators to select for example the RideHeight, that is
* usually only selectable, if it already has data.
*/
public static List<DetailType> getAutoplayDetailTypesForChart() {
List<DetailType> availableDetailsTypes = new ArrayList<>();
public static Collection<DetailType> getAutoplayDetailTypesForChart() {
final Collection<DetailType> availableDetailsTypes = new LinkedHashSet<>();
availableDetailsTypes.add(DetailType.CHART_WINDWARD_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD);
availableDetailsTypes.add(DetailType.LEG_CURRENT_SPEED_OVER_GROUND_IN_KNOTS);
availableDetailsTypes.add(DetailType.LEG_DISTANCE_TRAVELED);
@@ -266,8 +265,8 @@ public enum DetailType implements Serializable {
return availableDetailsTypes;
}
public static List<DetailType> getRaceExpeditionDetailTypes() {
ArrayList<DetailType> allowed = new ArrayList<>();
public static Collection<DetailType> getRaceExpeditionDetailTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(EXPEDITION_RACE_AWA);
allowed.add(EXPEDITION_RACE_AWS);
allowed.add(EXPEDITION_RACE_TWA);
@@ -310,15 +309,15 @@ public enum DetailType implements Serializable {
return allowed;
}
public static List<DetailType> getLegExtendedBravoDetailTypes() {
ArrayList<DetailType> allowed = new ArrayList<>();
public static Collection<DetailType> getLegExtendedBravoDetailTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(DetailType.BRAVOEXTENDED_LEG_CURRENT_DISTANCE_FOILED_IN_METERS);
allowed.add(DetailType.BRAVOEXTENDED_LEG_CURRENT_DURATION_FOILED_IN_SECONDS);
return allowed;
}
public static List<DetailType> getRaceExtendedBravoDetailTypes() {
ArrayList<DetailType> allowed = new ArrayList<>();
public static Collection<DetailType> getRaceExtendedBravoDetailTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(DetailType.BRAVOEXTENDED_RACE_CURRENT_PORT_DAGGERBOARD_RAKE);
allowed.add(DetailType.BRAVOEXTENDED_RACE_CURRENT_STBD_DAGGERBOARD_RAKE);
allowed.add(DetailType.BRAVOEXTENDED_RACE_CURRENT_PORT_RUDDER_RAKE);
@@ -340,24 +339,24 @@ public enum DetailType implements Serializable {
return allowed;
}
public static List<DetailType> getRaceBravoDetailTypes() {
ArrayList<DetailType> allowed = new ArrayList<>();
public static Collection<DetailType> getRaceBravoDetailTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(DetailType.BRAVO_RACE_HEEL_IN_DEGREES);
allowed.add(DetailType.BRAVO_RACE_PITCH_IN_DEGREES);
allowed.add(DetailType.BRAVO_RACE_CURRENT_RIDE_HEIGHT_IN_METERS);
return allowed;
}
public static List<DetailType> getLegBravoDetailTypes() {
ArrayList<DetailType> allowed = new ArrayList<>();
public static Collection<DetailType> getLegBravoDetailTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(DetailType.BRAVO_LEG_CURRENT_HEEL_IN_DEGREES);
allowed.add(DetailType.BRAVO_LEG_CURRENT_PITCH_IN_DEGREES);
allowed.add(DetailType.BRAVO_LEG_CURRENT_RIDE_HEIGHT_IN_METERS);
return allowed;
}
public static List<DetailType> getAllRaceDetailTypes() {
ArrayList<DetailType> allowed = new ArrayList<>();
public static Collection<DetailType> getAllRaceDetailTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(RACE_GAP_TO_LEADER_IN_SECONDS);
allowed.add(RACE_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS);
allowed.add(RACE_DISTANCE_TRAVELED);
@@ -366,7 +365,6 @@ public enum DetailType implements Serializable {
allowed.add(RACE_CALCULATED_TIME_TRAVELED);
allowed.add(RACE_CALCULATED_TIME_AT_ESTIMATED_ARRIVAL_AT_COMPETITOR_FARTHEST_AHEAD);
allowed.add(RACE_CURRENT_SPEED_OVER_GROUND_IN_KNOTS);
allowed.add(BRAVO_RACE_CURRENT_RIDE_HEIGHT_IN_METERS);
allowed.add(RACE_CURRENT_DISTANCE_FOILED_IN_METERS);
allowed.add(RACE_CURRENT_DURATION_FOILED_IN_SECONDS);
allowed.add(RACE_DISTANCE_TO_COMPETITOR_FARTHEST_AHEAD_IN_METERS);
@@ -388,7 +386,7 @@ public enum DetailType implements Serializable {
* @return
*/
public static Collection<DetailType> getAllNonRestrictedDetailTypes() {
List<DetailType> all = new ArrayList<>(Arrays.asList(values()));
final Collection<DetailType> all = new LinkedHashSet<>(Arrays.asList(values()));
all.removeAll(getRaceBravoDetailTypes());
all.removeAll(getLegBravoDetailTypes());
all.removeAll(getRaceExtendedBravoDetailTypes());
@@ -398,80 +396,148 @@ public enum DetailType implements Serializable {
return all;
}
public static List<DetailType> getAvailableOverallDetailColumnTypes() {
return Arrays.asList(new DetailType[] { DetailType.REGATTA_RANK, DetailType.OVERALL_TOTAL_DISTANCE_TRAVELED,
DetailType.OVERALL_TOTAL_AVERAGE_SPEED_OVER_GROUND, DetailType.OVERALL_TOTAL_TIME_SAILED_IN_SECONDS,
DetailType.OVERALL_MAXIMUM_SPEED_OVER_GROUND_IN_KNOTS, DetailType.OVERALL_TIME_ON_TIME_FACTOR,
DetailType.OVERALL_TIME_ON_DISTANCE_ALLOWANCE_IN_SECONDS_PER_NAUTICAL_MILE,
DetailType.OVERALL_TOTAL_SCORED_RACE_COUNT, TOTAL_TIME_SAILED_UPWIND_IN_SECONDS,
TOTAL_TIME_SAILED_REACHING_IN_SECONDS, TOTAL_TIME_SAILED_DOWNWIND_IN_SECONDS });
public static Collection<DetailType> getAvailableOverallDetailColumnTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(REGATTA_RANK);
allowed.add(OVERALL_TOTAL_DISTANCE_TRAVELED);
allowed.add(OVERALL_TOTAL_AVERAGE_SPEED_OVER_GROUND);
allowed.add(OVERALL_TOTAL_TIME_SAILED_IN_SECONDS);
allowed.add(OVERALL_MAXIMUM_SPEED_OVER_GROUND_IN_KNOTS);
allowed.add(OVERALL_TIME_ON_TIME_FACTOR);
allowed.add(OVERALL_TIME_ON_DISTANCE_ALLOWANCE_IN_SECONDS_PER_NAUTICAL_MILE);
allowed.add(OVERALL_TOTAL_SCORED_RACE_COUNT);
allowed.add(TOTAL_TIME_SAILED_UPWIND_IN_SECONDS);
allowed.add(TOTAL_TIME_SAILED_REACHING_IN_SECONDS);
allowed.add(TOTAL_TIME_SAILED_DOWNWIND_IN_SECONDS);
return allowed;
}
public static List<DetailType> getOverallBravoDetailTypes() {
return Arrays.asList(new DetailType[] { DetailType.OVERALL_TOTAL_DISTANCE_FOILED_IN_METERS,
OVERALL_TOTAL_DURATION_FOILED_IN_SECONDS });
public static Collection<DetailType> getOverallBravoDetailTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(OVERALL_TOTAL_DISTANCE_FOILED_IN_METERS);
allowed.add(OVERALL_TOTAL_DURATION_FOILED_IN_SECONDS);
return allowed;
}
public static List<DetailType> getLegDetailColumnTypes() {
return Arrays.asList(new DetailType[] { DetailType.LEG_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS,
DetailType.LEG_DISTANCE_TRAVELED, DetailType.LEG_DISTANCE_TRAVELED_INCLUDING_GATE_START,
DetailType.LEG_GAP_TO_LEADER_IN_SECONDS, DetailType.LEG_GAP_CHANGE_SINCE_LEG_START_IN_SECONDS,
DetailType.LEG_SIDE_TO_WHICH_MARK_AT_LEG_START_WAS_ROUNDED,
DetailType.LEG_CURRENT_SPEED_OVER_GROUND_IN_KNOTS, DetailType.LEG_WINDWARD_DISTANCE_TO_GO_IN_METERS,
DetailType.NUMBER_OF_MANEUVERS, DetailType.LEG_ESTIMATED_TIME_TO_NEXT_WAYPOINT_IN_SECONDS,
DetailType.LEG_VELOCITY_MADE_GOOD_IN_KNOTS, DetailType.LEG_TIME_TRAVELED,
DetailType.LEG_CORRECTED_TIME_TRAVELED, DetailType.LEG_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS,
DetailType.LEG_AVERAGE_SIGNED_CROSS_TRACK_ERROR_IN_METERS, DetailType.LEG_RANK_GAIN });
public static Collection<DetailType> getLegDetailColumnTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(LEG_AVERAGE_SPEED_OVER_GROUND_IN_KNOTS);
allowed.add(LEG_DISTANCE_TRAVELED);
allowed.add(LEG_DISTANCE_TRAVELED_INCLUDING_GATE_START);
allowed.add(LEG_GAP_TO_LEADER_IN_SECONDS);
allowed.add(LEG_GAP_CHANGE_SINCE_LEG_START_IN_SECONDS);
allowed.add(LEG_SIDE_TO_WHICH_MARK_AT_LEG_START_WAS_ROUNDED);
allowed.add(LEG_CURRENT_SPEED_OVER_GROUND_IN_KNOTS);
allowed.add(LEG_WINDWARD_DISTANCE_TO_GO_IN_METERS);
allowed.add(NUMBER_OF_MANEUVERS);
allowed.add(LEG_ESTIMATED_TIME_TO_NEXT_WAYPOINT_IN_SECONDS);
allowed.add(LEG_VELOCITY_MADE_GOOD_IN_KNOTS);
allowed.add(LEG_TIME_TRAVELED);
allowed.add(LEG_CORRECTED_TIME_TRAVELED);
allowed.add(LEG_AVERAGE_ABSOLUTE_CROSS_TRACK_ERROR_IN_METERS);
allowed.add(LEG_AVERAGE_SIGNED_CROSS_TRACK_ERROR_IN_METERS);
allowed.add(LEG_RANK_GAIN);
return allowed;
}
public static List<DetailType> getRaceStartAnalysisColumnTypes() {
return Arrays.asList(new DetailType[] { DetailType.RACE_DISTANCE_TO_START_FIVE_SECONDS_BEFORE_RACE_START,
DetailType.RACE_SPEED_OVER_GROUND_FIVE_SECONDS_BEFORE_START, DetailType.DISTANCE_TO_START_AT_RACE_START,
DetailType.TIME_BETWEEN_RACE_START_AND_COMPETITOR_START, DetailType.SPEED_OVER_GROUND_AT_RACE_START,
DetailType.SPEED_OVER_GROUND_WHEN_PASSING_START,
DetailType.DISTANCE_TO_STARBOARD_END_OF_STARTLINE_WHEN_PASSING_START_IN_METERS,
DetailType.START_TACK });
public static Collection<DetailType> getRaceStartAnalysisColumnTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(RACE_DISTANCE_TO_START_FIVE_SECONDS_BEFORE_RACE_START);
allowed.add(RACE_SPEED_OVER_GROUND_FIVE_SECONDS_BEFORE_START);
allowed.add(DISTANCE_TO_START_AT_RACE_START);
allowed.add(TIME_BETWEEN_RACE_START_AND_COMPETITOR_START);
allowed.add(SPEED_OVER_GROUND_AT_RACE_START);
allowed.add(SPEED_OVER_GROUND_WHEN_PASSING_START);
allowed.add(DISTANCE_TO_STARBOARD_END_OF_STARTLINE_WHEN_PASSING_START_IN_METERS);
allowed.add(START_TACK);
return allowed;
}
public static List<DetailType> getLegExpeditionDetailColumnTypes() {
return Arrays.asList(new DetailType[] { EXPEDITION_LEG_AWA, EXPEDITION_LEG_AWS, EXPEDITION_LEG_TWA,
EXPEDITION_LEG_TWS, EXPEDITION_LEG_TWD, EXPEDITION_LEG_TARG_TWA, EXPEDITION_LEG_BOAT_SPEED,
EXPEDITION_LEG_TARG_BOAT_SPEED, EXPEDITION_LEG_SOG, EXPEDITION_LEG_COG, EXPEDITION_LEG_FORESTAY_LOAD,
EXPEDITION_LEG_RAKE, EXPEDITION_LEG_COURSE, EXPEDITION_LEG_HEADING, EXPEDITION_LEG_VMG,
EXPEDITION_LEG_VMG_TARG_VMG_DELTA, EXPEDITION_LEG_RATE_OF_TURN, EXPEDITION_LEG_RUDDER_ANGLE,
EXPEDITION_LEG_TARGET_HEEL, EXPEDITION_LEG_TIME_TO_PORT_LAYLINE,
EXPEDITION_LEG_TIME_TO_STB_LAYLINE, EXPEDITION_LEG_DIST_TO_PORT_LAYLINE,
EXPEDITION_LEG_DIST_TO_STB_LAYLINE, EXPEDITION_LEG_TIME_TO_GUN, EXPEDITION_LEG_TIME_TO_COMMITTEE_BOAT,
EXPEDITION_LEG_TIME_TO_PIN, EXPEDITION_LEG_TIME_TO_BURN_TO_LINE,
EXPEDITION_LEG_TIME_TO_BURN_TO_COMMITTEE_BOAT, EXPEDITION_LEG_TIME_TO_BURN_TO_PIN,
EXPEDITION_LEG_DISTANCE_TO_COMMITTEE_BOAT, EXPEDITION_LEG_DISTANCE_TO_PIN,
EXPEDITION_LEG_DISTANCE_BELOW_LINE, EXPEDITION_LEG_LINE_SQUARE_FOR_WIND_DIRECTION, EXPEDITION_LEG_BARO,
EXPEDITION_LEG_LOAD_S, EXPEDITION_LEG_LOAD_P, EXPEDITION_LEG_JIB_CAR_PORT, EXPEDITION_LEG_JIB_CAR_STBD,
EXPEDITION_LEG_MAST_BUTT });
public static Collection<DetailType> getLegExpeditionDetailColumnTypes() {
final Collection<DetailType> allowed = new LinkedHashSet<>();
allowed.add(EXPEDITION_LEG_AWA);
allowed.add(EXPEDITION_LEG_AWS);
allowed.add(EXPEDITION_LEG_TWA);
allowed.add(EXPEDITION_LEG_TWS);
allowed.add(EXPEDITION_LEG_TWD);
allowed.add(EXPEDITION_LEG_TARG_TWA);
allowed.add(EXPEDITION_LEG_BOAT_SPEED);
allowed.add(EXPEDITION_LEG_TARG_BOAT_SPEED);
allowed.add(EXPEDITION_LEG_SOG);
allowed.add(EXPEDITION_LEG_COG);
allowed.add(EXPEDITION_LEG_FORESTAY_LOAD);
allowed.add(EXPEDITION_LEG_RAKE);
allowed.add(EXPEDITION_LEG_COURSE);
allowed.add(EXPEDITION_LEG_HEADING);
allowed.add(EXPEDITION_LEG_VMG);
allowed.add(EXPEDITION_LEG_VMG_TARG_VMG_DELTA);
allowed.add(EXPEDITION_LEG_RATE_OF_TURN);
allowed.add(EXPEDITION_LEG_RUDDER_ANGLE);
allowed.add(EXPEDITION_LEG_TARGET_HEEL);
allowed.add(EXPEDITION_LEG_TIME_TO_PORT_LAYLINE);
allowed.add(EXPEDITION_LEG_TIME_TO_STB_LAYLINE);
allowed.add(EXPEDITION_LEG_DIST_TO_PORT_LAYLINE);
allowed.add(EXPEDITION_LEG_DIST_TO_STB_LAYLINE);
allowed.add(EXPEDITION_LEG_TIME_TO_GUN);
allowed.add(EXPEDITION_LEG_TIME_TO_COMMITTEE_BOAT);
allowed.add(EXPEDITION_LEG_TIME_TO_PIN);
allowed.add(EXPEDITION_LEG_TIME_TO_BURN_TO_LINE);
allowed.add(EXPEDITION_LEG_TIME_TO_BURN_TO_COMMITTEE_BOAT);
allowed.add(EXPEDITION_LEG_TIME_TO_BURN_TO_PIN);
allowed.add(EXPEDITION_LEG_DISTANCE_TO_COMMITTEE_BOAT);
allowed.add(EXPEDITION_LEG_DISTANCE_TO_PIN);
allowed.add(EXPEDITION_LEG_DISTANCE_BELOW_LINE);
allowed.add(EXPEDITION_LEG_LINE_SQUARE_FOR_WIND_DIRECTION);
allowed.add(EXPEDITION_LEG_BARO);
allowed.add(EXPEDITION_LEG_LOAD_S);
allowed.add(EXPEDITION_LEG_LOAD_P);
allowed.add(EXPEDITION_LEG_JIB_CAR_PORT);
allowed.add(EXPEDITION_LEG_JIB_CAR_STBD);
allowed.add(EXPEDITION_LEG_MAST_BUTT);
return allowed;
}
/**
* Not yet implemented types can be added here, they will be hidden from any user under all circumstances
*/
public static List<DetailType> getDisabledDetailColumTypes() {
return Arrays.asList(new DetailType[] { EXPEDITION_LEG_TARG_TWA, EXPEDITION_LEG_VMG,
EXPEDITION_LEG_VMG_TARG_VMG_DELTA, EXPEDITION_LEG_RATE_OF_TURN, EXPEDITION_LEG_RUDDER_ANGLE,
EXPEDITION_LEG_TIME_TO_PORT_LAYLINE, EXPEDITION_LEG_TIME_TO_STB_LAYLINE,
EXPEDITION_LEG_DIST_TO_PORT_LAYLINE, EXPEDITION_LEG_DIST_TO_STB_LAYLINE,
EXPEDITION_LEG_TIME_TO_COMMITTEE_BOAT, EXPEDITION_LEG_TIME_TO_PIN, EXPEDITION_LEG_TIME_TO_BURN_TO_COMMITTEE_BOAT,
EXPEDITION_LEG_TIME_TO_BURN_TO_PIN, EXPEDITION_LEG_DISTANCE_TO_COMMITTEE_BOAT,
EXPEDITION_LEG_DISTANCE_TO_PIN, EXPEDITION_LEG_LINE_SQUARE_FOR_WIND_DIRECTION, EXPEDITION_RACE_TARG_TWA,
EXPEDITION_RACE_VMG, EXPEDITION_RACE_VMG_TARG_VMG_DELTA,
EXPEDITION_RACE_RUDDER_ANGLE, EXPEDITION_RACE_TIME_TO_PORT_LAYLINE, EXPEDITION_RACE_TIME_TO_STB_LAYLINE,
EXPEDITION_RACE_DIST_TO_PORT_LAYLINE, EXPEDITION_RACE_DIST_TO_STB_LAYLINE,
EXPEDITION_RACE_TIME_TO_COMMITTEE_BOAT, EXPEDITION_RACE_TIME_TO_PIN,
EXPEDITION_RACE_TIME_TO_BURN_TO_PIN, EXPEDITION_RACE_TIME_TO_BURN_TO_COMMITTEE_BOAT,
EXPEDITION_RACE_DISTANCE_TO_COMMITTEE_BOAT, EXPEDITION_RACE_DISTANCE_TO_PIN,
EXPEDITION_RACE_LINE_SQUARE_FOR_WIND_DIRECTION });
public static Collection<DetailType> getDisabledDetailColumTypes() {
final Collection<DetailType> disabled = new LinkedHashSet<>();
disabled.add(EXPEDITION_LEG_TARG_TWA);
disabled.add(EXPEDITION_LEG_VMG);
disabled.add(EXPEDITION_LEG_VMG_TARG_VMG_DELTA);
disabled.add(EXPEDITION_LEG_RATE_OF_TURN);
disabled.add(EXPEDITION_LEG_RUDDER_ANGLE);
disabled.add(EXPEDITION_LEG_TIME_TO_PORT_LAYLINE);
disabled.add(EXPEDITION_LEG_TIME_TO_STB_LAYLINE);
disabled.add(EXPEDITION_LEG_DIST_TO_PORT_LAYLINE);
disabled.add(EXPEDITION_LEG_DIST_TO_STB_LAYLINE);
disabled.add(EXPEDITION_LEG_TIME_TO_COMMITTEE_BOAT);
disabled.add(EXPEDITION_LEG_TIME_TO_PIN);
disabled.add(EXPEDITION_LEG_TIME_TO_BURN_TO_COMMITTEE_BOAT);
disabled.add(EXPEDITION_LEG_TIME_TO_BURN_TO_PIN);
disabled.add(EXPEDITION_LEG_DISTANCE_TO_COMMITTEE_BOAT);
disabled.add(EXPEDITION_LEG_DISTANCE_TO_PIN);
disabled.add(EXPEDITION_LEG_LINE_SQUARE_FOR_WIND_DIRECTION);
disabled.add(EXPEDITION_RACE_TARG_TWA);
disabled.add(EXPEDITION_RACE_VMG);
disabled.add(EXPEDITION_RACE_VMG_TARG_VMG_DELTA);
disabled.add(EXPEDITION_RACE_RUDDER_ANGLE);
disabled.add(EXPEDITION_RACE_TIME_TO_PORT_LAYLINE);
disabled.add(EXPEDITION_RACE_TIME_TO_STB_LAYLINE);
disabled.add(EXPEDITION_RACE_DIST_TO_PORT_LAYLINE);
disabled.add(EXPEDITION_RACE_DIST_TO_STB_LAYLINE);
disabled.add(EXPEDITION_RACE_TIME_TO_COMMITTEE_BOAT);
disabled.add(EXPEDITION_RACE_TIME_TO_PIN);
disabled.add(EXPEDITION_RACE_TIME_TO_BURN_TO_PIN);
disabled.add(EXPEDITION_RACE_TIME_TO_BURN_TO_COMMITTEE_BOAT);
disabled.add(EXPEDITION_RACE_DISTANCE_TO_COMMITTEE_BOAT);
disabled.add(EXPEDITION_RACE_DISTANCE_TO_PIN);
disabled.add(EXPEDITION_RACE_LINE_SQUARE_FOR_WIND_DIRECTION);
return disabled;
}
public static List<DetailType> getAllLegDetailColumnTypes() {
ArrayList<DetailType> all = new ArrayList<>();
public static Collection<DetailType> getAllLegDetailColumnTypes() {
final Collection<DetailType> all = new LinkedHashSet<>();
all.addAll(getLegDetailColumnTypes());
all.addAll(getLegBravoDetailTypes());
all.addAll(getLegExtendedBravoDetailTypes());
@@ -5,6 +5,7 @@ import java.io.ObjectInputStream;
import java.net.URI;
import java.util.HashSet;
import java.util.Set;
import java.util.logging.Logger;
import com.sap.sailing.domain.base.Nationality;
import com.sap.sailing.domain.base.NationalityChangeListener;
@@ -15,6 +16,7 @@ import com.sap.sse.common.impl.NamedImpl;
public class TeamImpl extends NamedImpl implements DynamicTeam {
private static final long serialVersionUID = 4646922280429210183L;
private static final Logger logger = Logger.getLogger(TeamImpl.class.getName());
private final Iterable<? extends DynamicPerson> sailors;
private final DynamicPerson coach;
private final NationalityChangeListener personNationalityChangeForwarder;
@@ -116,14 +118,19 @@ public class TeamImpl extends NamedImpl implements DynamicTeam {
public void setNationality(Nationality newNationality) {
Nationality oldNationality = getNationality();
if (!Util.equalsWithNull(oldNationality, newNationality)) {
for (Person sailor : getSailors()) {
((DynamicPerson) sailor).setNationality(newNationality);
}
if (getCoach() != null) {
getCoach().setNationality(newNationality);
}
for (NationalityChangeListener listener : getNationalityChangeListeners()) {
listener.nationalityChanged(this, oldNationality, newNationality);
if (Util.isEmpty(getSailors()) && getCoach() == null) {
logger.warning("Would like to update nationality of team "+this+
" to "+newNationality+" but cannot because neither sailors nor coach are set");
} else {
for (Person sailor : getSailors()) {
((DynamicPerson) sailor).setNationality(newNationality);
}
if (getCoach() != null) {
getCoach().setNationality(newNationality);
}
for (NationalityChangeListener listener : getNationalityChangeListeners()) {
listener.nationalityChanged(this, oldNationality, newNationality);
}
}
}
}
@@ -127,10 +127,16 @@ public class DomainFactoryImpl implements DomainFactory {
CompetitorWithBoat domainCompetitor = competitorAndBoatStore.getExistingCompetitorWithBoatById(competitorId);
if (domainCompetitor == null || competitorAndBoatStore.isCompetitorToUpdateDuringGetOrCreate(domainCompetitor)) {
List<DynamicPerson> teamMembers = new ArrayList<DynamicPerson>();
for (CrewMember crewMember: competitor.getCrew()) {
DynamicPerson person = new PersonImpl(crewMember.getName().trim(), getOrCreateNationality(crewMember.getNationality()),
/* dateOfBirth */ null, crewMember.getPosition());
teamMembers.add(person);
if (competitor.getCrew().isEmpty()) {
DynamicPerson dummyPerson = new PersonImpl(competitor.getName().trim(), getOrCreateNationality(competitor.getThreeLetterIOCCode()),
/* dateOfBirth */ null, /* description */ "Team");
teamMembers.add(dummyPerson);
} else {
for (CrewMember crewMember: competitor.getCrew()) {
DynamicPerson person = new PersonImpl(crewMember.getName().trim(), getOrCreateNationality(crewMember.getNationality()),
/* dateOfBirth */ null, crewMember.getPosition());
teamMembers.add(person);
}
}
DynamicTeam team = new TeamImpl(competitor.getName(), teamMembers, /* coach */ null);
final DynamicBoat domainBoat = competitorAndBoatStore.getOrCreateBoat(competitorId, /* name */ null, boatClass, competitor.getBoatID(), /* color */ null);
@@ -120,9 +120,7 @@ public class SwissTimingAdapterImpl implements SwissTimingAdapter {
person.getGivenName() + " " + person.getFamilyName(),
person.getNOC().name(), crewMember.getPosition().name()));
}
Crew firstCrewMember = team.getCrew().get(0);
Person person = persons.get(firstCrewMember.getPersonID());
String nationality = person.getNOC().name();
String nationality = team.getNOC().name();
CompetitorWithID competitor = new CompetitorWithID(team.getTeamID(),
boat.getSailNumber(), nationality, team.getTeamName(), crew);
competitors.add(competitor);
+79 -13
View File
@@ -29,7 +29,7 @@ html {
body {
background: url(images/spectatorview-bg.png) no-repeat left top #ebebeb;
background: #eee;
font-family: 'Open Sans', Arial, Verdana, sans-serif;
line-height: 1;
font-size: 14px;
@@ -150,11 +150,6 @@ input.magnifier {
z-index: 2000;
}
.mainPanel {
width: 100%;
margin-left: 13px;
}
.errorLabel {
color: #FF0000;
}
@@ -221,15 +216,32 @@ input.magnifier {
top: 9px;
}
.groupingProvider {
padding: 3px 0px;
}
.groupingProviderElement {
margin: 2px;
display: inline-block;
}
.statisticProvider {
padding: 5px 0px 0px 0px;
}
.statisticProviderElement {
margin: 10px 2px 2px 2px;
margin: 2px;
display: inline-block;
}
.statisticSuggestBoxPopup {
z-index: 2;
}
.statisticSuggestBoxPopup .suggestPopupContent {
max-height: 700px;
overflow-y: scroll;
}
.definitionProviderControls {
margin: 2px;
}
@@ -238,14 +250,17 @@ input.magnifier {
margin: 2px;
}
.queryProviderElementLabel {
margin-left: 0px;
}
.queryDefinitionViewerContent {
background-color: white;
padding: 5px;
}
.statisticSuggestBoxPopup .suggestPopupContent {
max-height: 700px;
overflow-y: scroll;
.filterDimensionsTitleLabel {
padding-top: 5px;
}
.filterFilterDimensionsPanel {
@@ -254,7 +269,6 @@ input.magnifier {
.dimensionFilterSelectionTablesContainer {
overflow-x: auto;
border-left: 2px solid #6f7277;
}
.dimensionFilterSelectionHeader {
@@ -267,6 +281,58 @@ input.magnifier {
text-shadow: #ddf 1px 1px 0;
}
.dimensionFilterSelectionTable {
border-top: 2px solid #6f7277;
.dataMiningBorderTop {
border-top: 2px solid #6f7277;
}
.dataMiningBorderLeft {
border-left: 2px solid #6f7277;
}
.dataMiningBorderBottom {
border-border: 2px solid #6f7277;
}
.dataMiningBorderRight {
border-right: 2px solid #6f7277;
}
.gwt-SplitLayoutPanel-VDragger {
background: #fff url(images/thumb_horz.png) center center no-repeat;
width: 100% !important;
height: 100% !important;
left: 0 !important;
top: 0 !important;
border: none;
border-radius: 0px;
opacity: 1;
}
.gwt-SplitLayoutPanel-HDragger {
background: #fff url(images/thumb_vertical.png) center center no-repeat;
width: 100% !important;
height: 100% !important;
left: 0 !important;
top: 0 !important;
border: none;
border-radius: 0px;
margin: 0px;
opacity: 1;
}
.dataMiningMarginBase {
margin: 0px 5px;
}
.dataMiningMarginLeft {
margin-left: 5px;
}
.dataMiningMarginRight {
margin-right: 5px;
}
.resultsPresenterTabHeader * {
display: inline-block;
margin: 0px 3px;
vertical-align: bottom;
}
.emphasizedLabel {
font-weight: 600;
}
@@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<launchConfiguration type="com.github.sdbg.debug.core.chromeLaunchConfig">
<stringAttribute key="applicationArguments" value=""/>
<stringAttribute key="applicationName" value=""/>
<booleanAttribute key="launchFile" value="false"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/com.sap.sailing.gwt.ui"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
</listAttribute>
<stringAttribute key="projectName" value="com.sap.sailing.gwt.ui"/>
<booleanAttribute key="showLaunchOutput" value="false"/>
<stringAttribute key="url" value="http://127.0.0.1:8888/gwt/DataMining.html"/>
<stringAttribute key="urlQueryParams" value=""/>
</launchConfiguration>
@@ -1,10 +1,13 @@
package com.sap.sailing.gwt.autoplay.client.configs;
import com.google.gwt.http.client.UrlBuilder;
import com.google.gwt.user.client.Window;
import com.sap.sailing.gwt.autoplay.client.app.AutoPlayClientFactory;
import com.sap.sailing.gwt.ui.shared.EventDTO;
import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
import com.sap.sse.gwt.settings.SettingsToUrlSerializer;
import com.sap.sse.gwt.settings.UrlBuilderUtil;
import com.sap.sse.security.ui.client.UserService;
public abstract class AutoPlayConfiguration {
@@ -19,20 +22,28 @@ public abstract class AutoPlayConfiguration {
OnSettingsCallback holder, PerspectiveCompositeSettings<?> settings, AutoPlayContextDefinition apcd,
UserService userService) {
Window.alert("This configuration does not have settings");
}
/**
* This method should be pure/standalone, it is not allowed to make any guesses on fields written by startRootNode,
* as it can be called before that
*/
public void loadSettingsDefault(EventDTO selectedEvent, StrippedLeaderboardDTO leaderboard, UserService userService,
OnSettingsCallback holder) {
holder.newSettings(null);
public void loadSettingsDefault(EventDTO selectedEvent, AutoPlayContextDefinition apcd,
StrippedLeaderboardDTO leaderboard, UserService userService, OnSettingsCallback holder) {
holder.newSettings(null, getUrlWithSettings(apcd, null));
}
private String getUrlWithSettings(AutoPlayContextDefinition apcd, PerspectiveCompositeSettings<?> settings) {
UrlBuilder urlBuilder = UrlBuilderUtil.createUrlBuilderFromCurrentLocationWithCleanParameters();
SettingsToUrlSerializer urlSerializer = new SettingsToUrlSerializer();
if (settings != null) {
urlSerializer.serializeSettingsMapToUrlBuilder(settings, urlBuilder);
}
urlSerializer.serializeToUrlBuilder(apcd, urlBuilder);
return urlBuilder.buildString();
}
public interface OnSettingsCallback {
void newSettings(PerspectiveCompositeSettings<?> newSettings);
void newSettings(PerspectiveCompositeSettings<?> newSettings, String urlWithSettings);
}
}
@@ -26,58 +26,81 @@ import com.sap.sse.security.ui.client.UserService;
public class AutoPlayClassicConfiguration extends AutoPlayConfiguration {
private static final Logger logger = Logger.getLogger(AutoPlayClassicConfiguration.class.getName());
@Override
public void startRootNode(AutoPlayClientFactory cf, AutoPlayContextDefinition context,
PerspectiveCompositeSettings<?> settings, EventDTO initialEventData) {
cf.getSailingService().getAvailableDetailTypesForLeaderboard(context.getLeaderboardName(), new AsyncCallback<Iterable<DetailType>>() {
@Override
public void onFailure(Throwable caught) {
logger.log(Level.WARNING, "Could not load detailtypes for leaderboard", caught);
}
cf.getSailingService().getAvailableDetailTypesForLeaderboard(context.getLeaderboardName(),
new AsyncCallback<Iterable<DetailType>>() {
@Override
public void onFailure(Throwable caught) {
logger.log(Level.WARNING, "Could not load detailtypes for leaderboard", caught);
}
@SuppressWarnings("unchecked")
@Override
public void onSuccess(Iterable<DetailType> result) {
StrippedLeaderboardDTO leaderBoardDTO = AutoplayHelper.getSelectedLeaderboard(initialEventData,
context.getLeaderboardName());
AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderBoardDTO, cf.getUserService(), result);
cf.setAutoPlayContext(new AutoPlayContextImpl(autoplayLifecycle,
(PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>) settings,
AutoPlayClassicConfiguration.this, context, initialEventData));
// start sixty inch slide loop nodes...
RootNodeClassic root = new RootNodeClassic(cf);
root.start(cf.getEventBus());
}
});
@SuppressWarnings("unchecked")
@Override
public void onSuccess(Iterable<DetailType> result) {
StrippedLeaderboardDTO leaderBoardDTO = AutoplayHelper.getSelectedLeaderboard(initialEventData,
context.getLeaderboardName());
AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(
leaderBoardDTO, cf.getUserService(), result);
cf.setAutoPlayContext(new AutoPlayContextImpl(autoplayLifecycle,
(PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>) settings,
AutoPlayClassicConfiguration.this, context, initialEventData));
// start sixty inch slide loop nodes...
RootNodeClassic root = new RootNodeClassic(cf);
root.start(cf.getEventBus());
}
});
}
@Override
public void openSettingsDialog(EventDTO selectedEvent, StrippedLeaderboardDTO leaderboard,
OnSettingsCallback settingsCallback, PerspectiveCompositeSettings<?> settings, AutoPlayContextDefinition apcd, UserService userService) {
OnSettingsCallback settingsCallback, PerspectiveCompositeSettings<?> settings,
AutoPlayContextDefinition apcd, UserService userService) {
DialogCallback<PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>> callback = new DialogCallback<PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>>() {
@Override
public void ok(PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings> editedObject) {
settingsCallback.newSettings(editedObject);
settingsCallback.newSettings(editedObject,
getUrlWithSettings(apcd, editedObject, leaderboard, userService));
}
@Override
public void cancel() {
}
};
AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderboard, userService, Arrays.asList(DetailType.values()));
PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings> autoplayPerspectiveSettings = autoplayLifecycle
.createDefaultSettings();
LinkWithSettingsGenerator<PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>> settingsGenerator = new LinkWithSettingsGenerator<>(Window.Location.getPath(), autoplayLifecycle::createDefaultSettings, apcd);
new SettingsDialogForLinkSharing<PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>>(settingsGenerator,
autoplayLifecycle, autoplayPerspectiveSettings, StringMessages.INSTANCE, true, callback).show();
AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderboard, userService,
Arrays.asList(DetailType.values()));
@SuppressWarnings("unchecked")
PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings> autoplayPerspectiveSettings = settings != null
? (PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>) settings
: autoplayLifecycle.createDefaultSettings();
LinkWithSettingsGenerator<PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>> settingsGenerator = new LinkWithSettingsGenerator<>(
Window.Location.getPath(), autoplayLifecycle::createDefaultSettings, apcd);
new SettingsDialogForLinkSharing<PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>>(
settingsGenerator, autoplayLifecycle, autoplayPerspectiveSettings, StringMessages.INSTANCE, true,
callback).show();
}
@Override
public void loadSettingsDefault(EventDTO selectedEvent, StrippedLeaderboardDTO leaderboard,
UserService userService, OnSettingsCallback settingsCallback) {
AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderboard, userService, Arrays.asList(DetailType.values()));
settingsCallback.newSettings(autoplayLifecycle.createDefaultSettings());
public void loadSettingsDefault(EventDTO selectedEvent, AutoPlayContextDefinition apcd,
StrippedLeaderboardDTO leaderboard, UserService userService, OnSettingsCallback settingsCallback) {
AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderboard, userService,
Arrays.asList(DetailType.values()));
PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings> defaultSettings = autoplayLifecycle
.createDefaultSettings();
settingsCallback.newSettings(defaultSettings,
getUrlWithSettings(apcd, defaultSettings, leaderboard, userService));
}
private String getUrlWithSettings(AutoPlayContextDefinition apcd,
PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings> settings, StrippedLeaderboardDTO leaderboard,
UserService userService) {
AutoplayPerspectiveLifecycle autoplayLifecycle = new AutoplayPerspectiveLifecycle(leaderboard, userService,
Arrays.asList(DetailType.values()));
LinkWithSettingsGenerator<PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings>> settingsGenerator = new LinkWithSettingsGenerator<>(
Window.Location.getPath(), autoplayLifecycle::createDefaultSettings, apcd);
return settingsGenerator.createUrl(settings);
}
}
@@ -17,6 +17,7 @@ import com.sap.sailing.gwt.autoplay.client.utils.AutoplayHelper;
import com.sap.sailing.gwt.ui.client.CompetitorSelectionModel;
import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.leaderboard.LeaderboardEntryPoint;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
@@ -35,6 +36,7 @@ public class IdleRaceLeaderboard extends FiresPlaceNode {
}
public void onStart() {
leaderboardTimer.setTime(MillisecondsTimePoint.now().asMillis());
leaderboardTimer.play();
PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings> settings = cf.getAutoPlayCtxSignalError()
.getAutoplaySettings();
@@ -24,6 +24,7 @@ import com.sap.sailing.gwt.ui.client.StringMessages;
import com.sap.sailing.gwt.ui.raceboard.RaceBoardPanel;
import com.sap.sailing.gwt.ui.shared.RaceTimesInfoDTO;
import com.sap.sailing.gwt.ui.shared.RaceboardDataDTO;
import com.sap.sse.common.impl.MillisecondsTimePoint;
import com.sap.sse.gwt.client.player.Timer;
import com.sap.sse.gwt.client.player.Timer.PlayModes;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
@@ -54,6 +55,8 @@ public class LiveRaceBoardNode extends FiresPlaceNode implements RaceTimesInfoPr
}
public void onStart() {
raceboardTimer.setTime(MillisecondsTimePoint.now().asMillis());
raceboardTimer.play();
raceTimesInfoProvider.addRaceIdentifier(cf.getAutoPlayCtxSignalError().getLifeOrPreLiveRace(), true);
PerspectiveCompositeSettings<AutoplayPerspectiveOwnSettings> settings = cf.getAutoPlayCtxSignalError().getAutoplaySettings();
@@ -55,10 +55,10 @@ public class AutoPlayStartPresenterImpl extends AbstractActivity implements Auto
StrippedLeaderboardDTO leaderBoard = AutoplayHelper.getSelectedLeaderboard(event,
apcd.getLeaderboardName());
apcd.getType().getConfig().loadSettingsDefault(event, leaderBoard, clientFactory.getUserService(), new OnSettingsCallback() {
apcd.getType().getConfig().loadSettingsDefault(event, apcd, leaderBoard, clientFactory.getUserService(), new OnSettingsCallback() {
@Override
public void newSettings(PerspectiveCompositeSettings<?> newSettings) {
public void newSettings(PerspectiveCompositeSettings<?> newSettings, String urlWithSettings) {
if (newSettings != null) {
serializer.deserializeSettingsMapFromCurrentLocation(newSettings);
}
@@ -8,7 +8,6 @@ import com.google.gwt.dom.client.DivElement;
import com.google.gwt.dom.client.Style.Display;
import com.google.gwt.event.dom.client.ChangeEvent;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.http.client.UrlBuilder;
import com.google.gwt.i18n.client.LocaleInfo;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
@@ -30,8 +29,6 @@ import com.sap.sailing.gwt.ui.shared.StrippedLeaderboardDTO;
import com.sap.sse.common.Util;
import com.sap.sse.gwt.client.GWTLocaleUtil;
import com.sap.sse.gwt.client.shared.perspective.PerspectiveCompositeSettings;
import com.sap.sse.gwt.settings.SettingsToUrlSerializer;
import com.sap.sse.gwt.settings.UrlBuilderUtil;
public class AutoPlayStartViewImpl extends Composite implements AutoPlayStartView {
private static StartPageViewUiBinder uiBinder = GWT.create(StartPageViewUiBinder.class);
@@ -151,9 +148,9 @@ public class AutoPlayStartViewImpl extends Composite implements AutoPlayStartVie
selectedAutoPlayType.getConfig().openSettingsDialog(selectedEvent, selectedLeaderboard,
new OnSettingsCallback() {
@Override
public void newSettings(PerspectiveCompositeSettings<?> newSettings) {
public void newSettings(PerspectiveCompositeSettings<?> newSettings, String urlWithSettings) {
settings = newSettings;
updateURL();
updateURL(urlWithSettings);
}
}, settings, apcd, currentPresenter.getUserService());
}
@@ -197,12 +194,12 @@ public class AutoPlayStartViewImpl extends Composite implements AutoPlayStartVie
settingsButton.removeStyleName(SharedResources.INSTANCE.mainCss().buttoninactive());
startAutoPlayButton.removeStyleName(SharedResources.INSTANCE.mainCss().buttoninactive());
apcd = new AutoPlayContextDefinitionImpl(selectedAutoPlayType, selectedEvent.id, selectedLeaderboardName);
apcd.getType().getConfig().loadSettingsDefault(selectedEvent, selectedLeaderboard, currentPresenter.getUserService(),
apcd.getType().getConfig().loadSettingsDefault(selectedEvent, apcd, selectedLeaderboard, currentPresenter.getUserService(),
new OnSettingsCallback() {
@Override
public void newSettings(PerspectiveCompositeSettings<?> newSettings) {
public void newSettings(PerspectiveCompositeSettings<?> newSettings, String urlWithSettings) {
settings = newSettings;
updateURL();
updateURL(urlWithSettings);
}
});
}
@@ -210,16 +207,9 @@ public class AutoPlayStartViewImpl extends Composite implements AutoPlayStartVie
return readyToGo;
}
private void updateURL() {
UrlBuilder urlBuilder = UrlBuilderUtil.createUrlBuilderFromCurrentLocationWithCleanParameters();
SettingsToUrlSerializer urlSerializer = new SettingsToUrlSerializer();
if (settings != null) {
urlSerializer.serializeSettingsMapToUrlBuilder(settings, urlBuilder);
}
urlSerializer.serializeToUrlBuilder(apcd, urlBuilder);
configuratedUrl = urlBuilder.buildString();
configStarter.setText(configuratedUrl);
configStarter.setHref(configuratedUrl);
private void updateURL(String urlWithSettings) {
configStarter.setText(urlWithSettings);
configStarter.setHref(urlWithSettings);
}
@UiHandler("localeSelectionBox")
@@ -45,6 +45,7 @@ public class BoatClassImageResolver {
boatClassIconsMap.put(BoatClassMasterdata.CANOE_TAIFUN.getDisplayName(), imageResources.CanoeTaifunIcon());
boatClassIconsMap.put(BoatClassMasterdata.CONTENDER.getDisplayName(), imageResources.ContenderIcon());
boatClassIconsMap.put(BoatClassMasterdata.CC_30.getDisplayName(), imageResources.CC30Icon());
boatClassIconsMap.put(BoatClassMasterdata.CLUB_SWAN_50.getDisplayName(), imageResources.CLUBSWAN50Icon());
boatClassIconsMap.put(BoatClassMasterdata.DELPHIA_24.getDisplayName(), imageResources.Delphia24Icon());
boatClassIconsMap.put(BoatClassMasterdata.DRAGON_INT.getDisplayName(), imageResources.DragonIcon());
boatClassIconsMap.put(BoatClassMasterdata.DYAS.getDisplayName(), imageResources.DyasIcon());
@@ -396,6 +396,10 @@ public interface BoatClassImageResources extends ClientBundle {
@ImageOptions(preventInlining = true)
ImageResource CC30Icon();
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/CLUBSWAN50.png")
@ImageOptions(preventInlining = true)
ImageResource CLUBSWAN50Icon();
@Source("com/sap/sailing/gwt/ui/client/images/boatclass/GP_26.png")
@ImageOptions(preventInlining = true)
ImageResource GP26Icon();
@@ -25,6 +25,7 @@
.tabExtension {
float: right;
margin-top: .5em;
}
.tabExtension > * {
@@ -20,12 +20,12 @@ public class SailorInfo extends Composite {
FlowPanel panel = new FlowPanel();
Style panelStyle = panel.getElement().getStyle();
panelStyle.setDisplay(Display.INLINE_BLOCK);
panelStyle.setVerticalAlign(VerticalAlign.BOTTOM);
Label sailorInfoLabel = new Label();
sailorInfoLabel.getElement().setInnerHTML(i18n.sailorInfoLongText().replace("\n", "<br />"));
Style labelStyle = sailorInfoLabel.getElement().getStyle();
labelStyle.setDisplay(Display.INLINE_BLOCK);
sailorInfoLabel.getElement().getStyle().setMarginTop(0.5, Unit.EM);
sailorInfoLabel.getElement().getStyle().setMarginRight(0.5, Unit.EM);
panel.add(sailorInfoLabel);
@@ -2,6 +2,7 @@ package com.sap.sailing.gwt.home.desktop.places.event.regatta;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.Style;
import com.google.gwt.dom.client.Style.TextTransform;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
@@ -65,7 +66,12 @@ public class TabletAndDesktopRegattaEventView extends Composite implements Event
racesTabUi = new RegattaRacesTabView(flagImageResolver);
regattaOverviewTabUi = new RegattaOverviewTabView(flagImageResolver);
initWidget(uiBinder.createAndBindUi(this));
String sailorsInfoURL = currentPresenter.getEventDTO().getSailorsInfoWebsiteURL();
if (sailorsInfoURL != null && !sailorsInfoURL.isEmpty()) {
tabPanelUi.addTabExtension(new SailorInfo(sailorsInfoURL));
}
if(currentPresenter.getEventDTO().getType() == EventType.SERIES) {
final PlaceNavigation<SeriesDefaultPlace> currentEventSeriesNavigation = currentPresenter.getCurrentEventSeriesNavigation();
Anchor seriesAnchor = new Anchor(i18n.overallLeaderboardSelection());
@@ -82,14 +88,10 @@ public class TabletAndDesktopRegattaEventView extends Composite implements Event
seriesAnchor.setStyleName(SharedResources.INSTANCE.mainCss().button());
seriesAnchor.addStyleName(SharedResources.INSTANCE.mainCss().buttonprimary());
Style style = seriesAnchor.getElement().getStyle();
style.setFontSize(16, Unit.PX);
style.setPadding(0.75, Unit.EM);
style.setPaddingLeft(0.75, Unit.EM);
style.setPaddingRight(0.75, Unit.EM);
style.setTextTransform(TextTransform.UPPERCASE);
tabPanelUi.addTabExtension(seriesAnchor);
} else {
String sailorsInfoURL = currentPresenter.getEventDTO().getSailorsInfoWebsiteURL();
if(sailorsInfoURL != null && ! sailorsInfoURL.isEmpty()) {
tabPanelUi.addTabExtension(new SailorInfo(sailorsInfoURL));
}
}
final Iterable<SpotDTO> spots = currentPresenter.getEventDTO().getAllWindFinderSpotIdsUsedByEvent();
@@ -9,6 +9,7 @@
<li>In <tt>RaceBoard.html</tt> the availability of media is now visualized under the time slider via a bar overlay. When hovering the bar, the title of the video is shown.</li>
<li>In <tt>RaceBoard.html</tt> video players are now ensured to be on top of all video players when clicking/touching them.
This means you can bring a specific video window in the foreground in case there are multiple ones that overlap each other.</li>
<li>In <tt>RaceBoard.html</tt> the various areas (e.g. leaderboard and charts) now keep their size on expansion/collapsion.</li>
<li>The filter selection in <tt>DataMining.html</tt> has been overhauled.
<ul class="bulletList">
<li>All available filter dimensions are now listed where the different data retriever levels have been listed previously.
@@ -18,13 +19,10 @@
<li>Selecting a filter dimension adds a table containing the available values of the selected dimension. The order of
the value tables is equal to the order of the dimensions list.
</li>
<li>Note that the selection of the filter dimensions follows the <q>table with checkbox column</q> pattern. So simply clicking on a
dimension will result in deselecting all previously selected dimensions, removing possible filter values. Clicking on the
checkbox column or using <q>ctrl+click</q> is advised.
</li>
<li>Each filter value table now has its own scroll-bar.</li>
</ul>
</li>
<li>The grouping dimensions are now ordered alphabetically.</li>
</ul>
<h5 class="articleSubheadline">April 2018</h5>
@@ -6,6 +6,7 @@ import java.util.Set;
import java.util.UUID;
import com.google.gwt.core.client.GWT;
import com.google.gwt.dom.client.DivElement;
import com.google.gwt.safehtml.shared.SafeHtmlUtils;
import com.google.gwt.uibinder.client.UiBinder;
import com.google.gwt.uibinder.client.UiField;
@@ -39,9 +40,11 @@ public abstract class AbstractEventView<P extends EventViewBase.Presenter> exten
static class AbstractEventViewLayout {
@UiField(provided = true) EventHeader eventHeaderUi;
@UiField Quickfinder quickFinderUi;
@UiField SimpleInfoBlock simpleInfoUi;
@UiField SimpleInfoBlock sailorInfoUi;
@UiField SimpleInfoBlock seriesNavigationoUi;
@UiField DivElement windfinderWrapperUi;
@UiField(provided = true) WindfinderControl windfinderUi;
@UiField SimplePanel viewContentUi;;
@UiField SimplePanel viewContentUi;
private AbstractEventViewLayout(EventViewDTO event, String regattaName, PlaceNavigation<?> logoNavigation) {
this.eventHeaderUi = new EventHeader(event, regattaName, logoNavigation);
@@ -125,18 +128,19 @@ public abstract class AbstractEventView<P extends EventViewBase.Presenter> exten
@Override
public void setSailorInfos(String description, String buttonLabel, String url) {
layout.simpleInfoUi.setDescription(SafeHtmlUtils.fromString(description.replace("\n", " ")));
layout.simpleInfoUi.setAction(buttonLabel, url);
layout.sailorInfoUi.setDescription(SafeHtmlUtils.fromString(description.replace("\n", " ")));
layout.sailorInfoUi.setAction(buttonLabel, url);
}
@Override
public void setWindfinderNavigations(Iterable<SpotDTO> spotData) {
layout.windfinderWrapperUi.getStyle().clearDisplay();
layout.windfinderUi.setSpotData(spotData);
}
@Override
public void setSeriesNavigation(String buttonLabel, PlaceNavigation<?> placeNavigation) {
layout.simpleInfoUi.setAction(buttonLabel, placeNavigation);
layout.seriesNavigationoUi.setAction(buttonLabel, placeNavigation);
}
}
@@ -7,9 +7,12 @@
.headerWrapper {
background-color: #f2f2f2;
}
.windfinderWrapper {
padding-bottom: 10px;
margin: 0 10px;
}
.windfinder {
display: block;
margin: 0 10px 10px;
width: 100%;
border-radius: .384615384615385em;
text-align: center;
}
@@ -18,8 +21,11 @@
<div class="{style.headerWrapper}">
<mp:eventheader.EventHeader ui:field="eventHeaderUi" />
<mp:quickfinder.Quickfinder ui:field="quickFinderUi" />
<mp:simpleinfoblock.SimpleInfoBlock ui:field="simpleInfoUi" />
<sp:windfinder.WindfinderControl ui:field="windfinderUi" addStyleNames="{style.windfinder}" />
<mp:simpleinfoblock.SimpleInfoBlock ui:field="sailorInfoUi" />
<mp:simpleinfoblock.SimpleInfoBlock ui:field="seriesNavigationoUi" />
<div class="{style.windfinderWrapper}" style="display:none;" ui:field="windfinderWrapperUi">
<sp:windfinder.WindfinderControl ui:field="windfinderUi" addStyleNames="{style.windfinder}" />
</div>
</div>
<g:SimplePanel ui:field="viewContentUi"></g:SimplePanel>
</g:HTMLPanel>
@@ -30,11 +30,11 @@ public class RegattaActivity extends AbstractEventActivity<RegattaOverviewPlace>
@Override
protected EventViewBase initView() {
final AbstractEventOverview view = new RegattaOverviewImpl(this, flagImageResolver);
initSailorInfo(view);
initSeriesNavigation(view);
initQuickfinder(view, true);
initWindfinderNavigations(view);
if (!isMultiRegattaEvent()) {
// initSailorInfo(view);
initMedia(view);
}
return view;
@@ -92,7 +92,7 @@ public class HomePlacesNavigator extends AbstractPlaceNavigator {
}
public PlaceNavigation<ConfirmationPlace> getMailVerifiedConfirmationNavigation() {
return createLocalPlaceNavigation(new ConfirmationPlace(Action.MAIL_VERIFIED));
return createLocalPlaceNavigation(new ConfirmationPlace(Action.MAIL_VERIFIED, null, null));
}
public PlaceNavigation<ConfirmationPlace> getPasswordResettedConfirmationNavigation(String username) {
@@ -7,7 +7,7 @@
text-decoration: none;
vertical-align: bottom;
padding-left: 1em;
padding-right: 0.5em
padding-right: 0.5em;
}
.windfindercontrol_text, .windfindercontrol_icon {
display: inline-block;
@@ -86,7 +86,22 @@ public class ConfirmationPlace extends AbstractBasePlace implements HasMobileVer
@Override
public String getToken(ConfirmationPlace place) {
return place.getAction().name()+"?u="+URL.encodeQueryString(place.getName())+"&v="+URL.encodeQueryString(place.getValidationSecret());
final StringBuilder result = new StringBuilder(place.getAction().name());
if (place.getName() != null || place.getValidationSecret() != null) {
result.append('?');
if (place.getName() != null) {
result.append("u=");
result.append(URL.encodeQueryString(place.getName()));
}
if (place.getValidationSecret() != null) {
if (place.getName() != null) {
result.append('&');
}
result.append("v=");
result.append(URL.encodeQueryString(place.getValidationSecret()));
}
}
return result.toString();
}
}
}
@@ -748,6 +748,7 @@ public class EventListComposite extends Composite implements EventsRefresher, Le
allEvents.clear();
allEvents.addAll(events);
filterTextbox.updateAll(allEvents);
eventTable.redraw();
}
});
}
@@ -1264,7 +1264,7 @@ removeResult=Löschergebnis: {0} {1}
uploadSuccessful=Hochladen erfolgreich
fileUploadResult=Ergebnis des Hochladens: {0} {1}\nIm Fehlerfall bitte die Konfiguration für "Datei Speicherung" prüfen.
removeUploadedFile=Hochgeladene Datei löschen
showCompetitorBoatColumn=Boat des Teilnehmers anzeigen
showCompetitorBoatColumn=Boot des Teilnehmers anzeigen
showCompetitorSailIdColumn=Segelnummer anzeigen
showCompetitorSailIdColumnTooltip=Zeigt die Segelnummer sowie eine Nationalitäten-Flagge oder ein Teilnehmerbild an. Ein Teilnehmerbild wird hierbei bevorzugt angzeigt, falls vorhanden. Falls auch "{0}" ausgewählt ist, werden stets beide Bilder angezeigt.
showCompetitorShortNameColumn=Kurzen Teilnehmernamen anzeigen
@@ -1607,8 +1607,8 @@ favoriteCompetitors=Favorisierte Teilnehmer
favoriteBoatClasses=Favorisierte Bootsklassen
notificationAboutNewResults=Über neue Ergebnisse informieren
notificationAboutUpcomingRaces=Über demnächst stattfindende Rennen informieren
currentHeelInDegree=Seitenneigung
currentHeelInDegreeTooltip=Die aktuelle Seitenneigung in Grad
currentHeelInDegree=Krängung
currentHeelInDegreeTooltip=Die aktuelle Krängung in Grad
currentPitchInDegree=Neigung
currentPitchDegreeTooltip=Die aktuelle Neigung in Grad
currentRideHeightInMeters=Fahrhöhe
@@ -9,10 +9,12 @@ trackedBefore=Historial de eventos rastreados
general=General
listRaces=Listar carreras
listRegattas=Listar regatas
numberPairResultsPresenter=Diagrama de dispersión
wind=Viento
maneuverType=Maniobra
windPanelLabel=Este es el panel de vientos, y hasta el momento está totalmente vacío.
refresh=Refrescar
remove=Eliminar
removeNumber=Eliminar ({0})
windSource=Fuente de vientos
dampeningInterval=Intervalo de amortiguación
@@ -51,6 +53,7 @@ trackedRaceConnectedToSelectedRaceName=Carrera rastreada conectada al nombre de
linkToColumn=Enlace a columna
unlink=Quitar enlace
leaderboardName=Nombre de tabla de clasificación
cancel=Cancelar
pleaseEnterAName=Indique un nombre
pleaseEnterABoatClass=Indique una clase de embarcación
discardRacesFromHowManyStartedRacesOn=Descartar un inicio de carrera más con cuántas carreras iniciadas
@@ -62,6 +65,7 @@ startingFromNumberOfRaces=Empezando por cuántas carreras
renameLeaderboard=Cambiar nombre de tabla de clasificación
addColumnToLeaderboard=Añadir columna a tabla de clasificación
pleaseEnterNameForNewRaceColumn=Indique un nombre para la nueva columna de carrera
ok=OK
medalRace=Medal Race
renameRace=Cambiar nombre de carrera
openSelectedLeaderboard=Abrir tabla de clasificación seleccionada
@@ -85,6 +89,7 @@ sapSailingAnalytics=Sailing Analytics
leaderboard=Tabla de clasificación
leaderboards=Tablas de clasificación
leaderboardSettings=Opciones de tabla de clasificación
settings=Opciones
selectAtLeastOneLegDetail=Seleccione al menos un detalle de tramo
currentSpeedOverGroundInKnots=SOG (speed over ground)
currentSpeedOverGroundInKnotsTooltip=Velocidad actual sobre el fondo.
@@ -168,6 +173,7 @@ tacks=Bordadas
jibes=Trasluchadas
penaltyCircles=Círculos de penalización
medalRaceIsNull=Valor de regata final no permitido
configuration=Configuración
maneuverTypes=Maniobras
chooseChart=Seleccionar gráfico
distanceTraveled=Distancia viajada
@@ -185,11 +191,13 @@ secondsPerNauticalMileUnit=s/NM
metersUnit=m
millimetersUnit=mm
degreesUnit=°
close=Cerrar
compareCompetitors=Comparar competidores
description=Descripción
sailNumber=Número de vela
country=País
no3LetterCodes=No es posible encontrar los códigos IOC de 3 letras.
add=Añadir
delete=Borrar
showCharts=Mostrar gráficos
raceWithThisNameAlreadyExists=Ya existe una carrera con este nombre.
@@ -261,6 +269,7 @@ printHint=Imprime la versión aplicada
blockedApplyButton=Los competidores registrados difieren de los competidores de la lista de emparejamientos
multiplierInfo=Multiplica los flights y los crea uno junto a otro de modo que sea posible una competición con menos modificaciones de embarcación.
noPairingListAvailable=La función de impresión solo está disponible si ya se han aplicado las listas de emparejamientos a los registros de carrera de las clasificaciones seleccionadas.
settingsForComponent=Opciones para {0}
noEventsFound=No se han encontrado eventos
noEventSelected=Ningún evento seleccionado
noLeaderboardsFound=No se han encontrado tablas de clasificación
@@ -298,6 +307,8 @@ leaderboardGroup=Grupo de tablas de clasificación
pleaseEnterNonEmptyDescription=Indique una descripción no vacía
groupWithThisNameAlreadyExists=Ya existe un grupo de tablas de clasificación con este nombre.
detailsOfLeaderboardGroup=Detalles del grupo de tablas de clasificación
edit=Editar
save=Grabar
abort=Detener
noLeaderboardGroupWithNameFound=No se ha encontrado ningún grupo de tablas de clasificación con el nombre {0}
overview=Resumen
@@ -332,6 +343,7 @@ degreesShort=grados
untracked=No rastreado
delayForLiveMode=Retraso para modo en directo
notAvailable=No disponible
details=Detalles
noGroupSelected=Ningún grupo seleccionado
combinedWindSourceTypeName=Combinado
legMiddleWindSourceTypeName=Mitad de tramo
@@ -413,6 +425,7 @@ simulateAsLiveRace=Simular como carrera en directo
simulateWithOffset=Offset antes de inicio en minutos:
boatClassDoesNotMatchSelectedRegatta=Las carreras seleccionadas contienen clases de embarcación distintas de la clase ''''{0}'''' de la regata seleccionada. No se cargará ninguna carrera.
regattaExistForSelectedBoatClass=Hay al menos una regata para las clases de embarcación seleccionadas. ¿Realmente desea crear regata(s) por defecto para esta(s) carrera(s)?
reload=Recargar
addRegatta=Añadir regata...
importRegattas=Importar regatas...
exchangeName=Intercambiar nombre
@@ -634,6 +647,7 @@ totalNetPointsColumnTooltip=El total de puntos netos de un competidor de la rega
windData=Datos de vientos
gpsData=Datos de GPS
status=Status
noDataFound=No se han encontrado datos
displayName=Visualizar nombre
histogram=Histograma
numberOfDataPoints=Número de puntos de datos
@@ -881,9 +895,12 @@ legType=Tipo de tramo
sailID=Número de vela
seriesLeaderboard=Tabla de clasificación de serie
regattaLeaderboards=Clasificaciones de regata
clearSelection=Borrar selección
running=En ejecución
runAsSubstantive=Ejecutar
done=Hecho
lastFinished=Último que ha terminado
run=Ejecutar
times=tiempos
dataAmount=Cantidad de datos
averageCleanedServerTime=∅ Tiempo de servidor limpio
@@ -907,8 +924,12 @@ selectSheet=Seleccionar hoja
cleanedServerTime=Tiempo de servidor limpio
overallTime=Tiempo total
cleanedOverallTime=Tiempo global limpio
dataMiningResult=Resultado de minería de datos
groupBy=Agrupar por
statisticToCalculate=Calcular estadística
queryResultsChartSubtitle=Se ha trabajado en {0} entradas de datos en {1} segundos
noQuerySelected=Ninguna consulta seleccionada
runAutomatically=Ejecutar automáticamente
windImport_Upload=Cargar
windImport_Title=Importar viento desde expedición
windImport_BoatId=ID de embarcación:
@@ -938,9 +959,14 @@ raceTimeTooltip=Tiempo total recorrido en esta carrera, se empieza a medir cuand
raceTimeDownwindTooltip=Tiempo total de empopada recorrido en esta carrera
raceTimeReachingTooltip=Tiempo total de alcance recorrido en esta carrera
raceTimeUpwindTooltip=Tiempo total de ceñida recorrido en esta carrera
noStatisticSelectedError=No se ha seleccionado ninguna estadística para calcular
noCustomGrouperScriptTextError=El script de grupo está vacío
noDimensionToGroupBySelectedError=No se ha seleccionado ninguna dimensión para agrupar
noGrouperSelectedError=No se ha seleccionado ningún tipo de agrupador
noDataRetrieverChainDefinitonSelectedError=No se ha seleccionado ningún recuperador de datos
queryNotValidBecause=No se puede hacer ninguna consulta porque
dataMining=Minería de datos
errorRunningDataMiningQuery=Se ha producido un error al ejecutar la consulta
hideToolbar=Ocultar barra de herramientas
showSeriesLeaderboards=Mostrar tablas de clasificación de las series
showOverallLeaderboard=Mostrar tabla de clasificación general
@@ -963,6 +989,7 @@ id=ID
allowReload=Permitir recarga
compress=Comprimir
compressTooltip=Utilizar solamente si la instancia del servidor de exportación funciona al menos con la confirmación 0fbf6071dea125bec4a56dee55d61c99def4a62e.
queryRunner=Ejecutor de la consulta
rerunQueryAfterRefresh=Volver a ejecutar la consulta después de actualizar
refreshIntervalMustntBeEmpty=El intervalo de actualización no debe estar en blanco
selectionTables=Tablas de selección
@@ -1047,7 +1074,12 @@ TWATooltip=Ángulo entre la dirección de los competidores y el viento
TWA=Ángulo real del viento
showBoatClassChartsLabel=También puede visualizar el diagrama global para las clases de embarcación disponibles.
showDiagram=Mostrar diagrama
runAutomaticallyTooltip=Ejecute la consulta automáticamente después de modificar, por ejemplo, la estadística o la agrupación.
rerunQueryAfterRefreshTooltip=Vuelve a ejecutar la consulta después de que se hayan refrescado las tablas.
queryDefinitionProvider=Proveedor de definición de consultas
statisticProvider=Proveedor de estadísticas
calculateThe=Calcular
groupingProvider=Proveedor de agrupación
releaseNotes=Historial de noticias y lanzamientos
hasSplitFleetContiguousScoring=Dividir flotas puntuadas de forma contigua
addRaceLogTracker=Añadir rastreador de registro de carrera
@@ -1205,6 +1237,7 @@ showAll=Mostrar todo
raceVisibilityColumn=Visibilidad
enterCarryValueFor=Introducir puntos acumulados para el competidor {0}
advanced=Avanzado
basedOn=Basado en
retrieveWith=Recuperar con
mappingDetails=Detalles de asignación
deviceMappingQrCodeExplanation=Si utiliza la aplicación de rastreo, también puede añadir la asignación de dispositivos seleccionando un competidor/marca, definiendo las fechas de inicio y fin y escaneando este código QR
@@ -1215,6 +1248,10 @@ enterImageURL=Indicar URL de imagen...
enterVideoURL=Indicar URL de vídeo...
enterSponsorImageURL=Indicar URL de imagen de patrocinador...
enterRaceName=Indicar nombre de carrera...
serverError=Se ha producido un error al intentar contactar con el servidor. Compruebe la conexión de red e inténtelo de nuevo.
remoteProcedureCall=Llamada de procedimiento remoto
serverReplies=Servidor responde
errorCommunicatingWithServer=Error al comunicar con el servidor
userManagement=Gestión de usuarios
regattaStructureImport=Importación de la estructura de regata
filteredBy=Filtrado por
@@ -1242,6 +1279,7 @@ noFleetsDefined=Ninguna flota definida
successfullyCreatedRegattas=Regatas creadas con éxito
errorTryingToRegisterRacesForTracking=Error al intentar registrar carreras {0} para rastreo: {1}. Compruebe sintaxis URI en directo/grabada.
errorDeterminingPolarAvailability=Error al determinar la disponibilidad de datos polares / VPP para la carrera {0}: {1}
error=Error
fileStorage=Almacenamiento de archivos
active=Activo
scoringSchemeHighPointEssOverallDescription=Calificación en puntos. El ganador de una prueba obtiene 10 puntos; el segundo, 9 puntos, etc. Si hay un empate en la serie de Extreme Sailing, el empate se resuelve a favor del competidor que ha ganado más pruebas. Si aún persiste el empate, se utiliza el resultado de la última prueba.
@@ -1284,6 +1322,7 @@ showCompetitorFullNameColumn=Nombre completo del competidor
alwaysShowCompetitorNationalityColumn=Siempre mostrar la nacionalidad del competidor
alwaysShowCompetitorNationalityColumnTooltip=Muestra ambos, las banderas de país así como las imágenes de competidor, si están disponibles.
loadingDimensionValues=Cargando valores de dimensión
runningQuery=Ejecutando consulta
inviteBuoyTenders=Invitar a balizadores
orMultipleEmails=o varios correos electrónicos separados por una coma
courseOverGroundTrueDegreesTooltip=Regata sobre el fondo (Course Over Ground) en grados
@@ -1291,6 +1330,11 @@ courseOverGroundTrueDegrees=COG
distanceIncludingGateStartInMeters=Distancia (con inicio de puerta de salida)
distanceTraveledIncludingGateStartTooltip=Distancia recorrida desde el inicio hasta el final del tramo\o hasta la fecha y hora actual si no se ha acabado el tramo.\nSi el tramo incluye un inicio de puerta de salida, la distancia desde el extremo hasta la posición inicial se incluye\n para que puedan compararse los competidores aunque hayan empezado en tiempos diferentes.
raceDistanceTraveledIncludingGateStartTooltip=Distancia recorrida desde el inicio hasta el final de la carrera\o hasta la fecha y hora actual si no se ha acabado la carrera. Para el inicio de la puerta de salida, la distancia desde el extremo hasta la posición inicial se incluye\n para que puedan compararse los competidores aunque hayan empezado en tiempos diferentes.
results=Resultados
groupName=Nombre de grupo
valueAscending=Valor (ascendente)
valueDescending=Valor (descendente)
sortBy=Ordenado por
dashboardHeader=Dashboard
dashboardNoWindBotAvailableHeader=Wind Bot no está disponible
dashboardNoWindBotAvailableMessage=Para obtener los datos de viento en directo a partir de unidades de medida de viento, asegúrese de que Wind Bot está activado y contectado con SAP Sailing Analytics.
@@ -1326,12 +1370,16 @@ dashboardRCBoat=Barco RC
fixedMarkPassing=(fijado)
suppressedMarkPassing=(suprimido)
windUp=Viento al norte (mostrar viento de la parte superior del mapa)
filterBy=Filtrar por
currentFilterSelection=Seleccion de filtro actual
notCapableOfGeneratingACodeForIdentifier=No sé generar un código para este identificador.
serverUrl=URL del servidor
rotatedFromTrueNorth=Ha rotado {0} grados desde el norte real.
clickToToggleWindUp=Golpe/clic para alternar entre visualización mapa viento al norte y norte arriba
clickToToggleWindStreamlets=Golpe/clic para mostrar u ocultar corrientes de viento
startLineToFirstMarkTriangle=Inicio a la primera marca ({0} m)
dataMiningComponentsHaveBeenUpdated=Los componentes de minería de datos se han actualizado
dataMiningComponentsNeedReloadDialogMessage=Pulse Recargar para volver a cargar los componentes ahora. De este modo, se descartarán los datos visualizados en ese momento y se ejecutará una consulta por defecto.\nHaga clic en «Cerrar» para no hacer nada. La minería de datos no funcionará correctamente hasta que se hayan vuelto a cargar los componentes.
noDataForEvent=Todavía no hay datos para el evento.
countriesCount={0,number} países
countriesCount[one]={0,number} país
@@ -1429,7 +1477,15 @@ noFinishedRaces=Todavía no ha finalizado ninguna carrera
racesOverview=Resumen de carreras
listFormatLabel=Formato de lista
competitionFormatLabel=Formato de competición
empty=Vacío
runAQuery=Realice una consulta
latestRegattaStandings=Últimas posiciones de la regata
plainText=Texto sin formato
columnChart=Gráfico de columnas
columnChartWithErrorBars=Gráfico de columnas con barras de error
choosePresentation=Seleccionar presentación
cantDisplayDataOfType=No se pueden mostrar datos del tipo {0}
shownDecimals=Decimales mostrados
openFullscreenView=Abrir vista de pantalla completa
closeFullscreenView=Cerrar vista de pantalla completa
videosCount={0,number} vídeos
@@ -1439,8 +1495,15 @@ photosCount[one]={0,number} foto
eventsHaveTakenPlace=Han tenido lugar {0} eventos
eventsHaveTakenPlace[one]=Ha tenido lugar un evento
raceOffice=Oficina de carrera
analyze=Analizar
dataMiningSettings=Opciones de minería de datos
multiResultsPresenter=Presentador de resultados múltiples
plainResultsPresenter=Presentador de resultados simples
resultsChart=Gráfico de resultados
tabbedResultsPresenter=Presentador de resultados por pestañas
polarResultsPresenter=Presentador de resultados de coordenadas polares
maneuverSpeedDetailsResultsPresenter=Presentador de resultados detallados de velocidad de maniobra
dataMiningRetrieval=Recuperación de datos
actionWatch=Observar
actionAnalyze=Analizar
denoteAllRacesForRaceLogTrackingShorctut=Acceso directo para indicar todas las carreras para un rastreo de registro de carrera
@@ -1456,8 +1519,24 @@ defaultName=Por defecto
exampleTextForName=Su nombre aparece como:
flightsCount={0,number} flights
flightsCount[one]={0,number} flight
viewQueryDefinition=Ver definición de consulta
queryDefinitionViewer=Visor de definición de consulta
groupAverageAscending=Promedio de grupo (ascendente)
groupAverageDescending=Promedio de grupo (descendente)
groupMedianAscending=Mediana de grupo (ascendente)
groupMedianDescending=Mediana de grupo (descendente)
resultsFoundForSearch={0,number} resultados encontrados para ''''{1}''''
resultsFoundForSearch[one]={0,number} resultado encontrado para ''''{1}''''
runPredefinedQuery=Ejecutar consulta predefinida
selectPredefinedQuery=Seleccionar consulta predefinida
predefinedQueryRunner=Programa de ejecución de consulta predefinida
developerOptions=Opciones de desarrollador
copyToClipboard=Copiar a portapapeles
code=Código
useClassGetName=Utilizar Class.getName() para nombres de tipo
useClassGetNameTooltip=Más resistente frente a modificaciones en la base de código, pero el fragmento de código se puede utilizar solamente en el ámbito donde estén disponibles las clases.
useStringLiterals=Utilizar literales de cadena para los nombres de tipo
useStringLiteralsTooltip=El fragmento de código puede utilizarse en todas las ubicaciones, pero se romperá si se modifica la base de código.
errorLoadingDataWithTryAgain=Error al cargar los datos. Inténtelo de nuevo más tarde.
addGalleryPhoto=Añadir foto de galería
addStageImage=Añadir imagen de etapa
@@ -1477,6 +1556,7 @@ warningForDisabledCompetitors=Los siguientes competidores no se pueden registrar
competitorToolTipMessage={0} ya ha sido asignado a la flota {2} en la carrera {3} y, por consiguiente, no se puede asignar a la flota {1} de la misma carrera
addMarkToRegatta=Añadir marca a regata
selectALeaderboardGroup=Seleccione un grupo de tablas de clasificación...
pleaseSelect=Seleccione
requiresValidRegatta=Esta página requiere una regata, una columna de carreras y un nombre de flota válidos para identificar la regata que se desea mostrar.
couldNotObtainRace=No se ha podido obtener la regata con el nombre {1} para la flota {2} para una regata con el nombre {0}: {3}
errorTryingToCreateEmbeddedMap=Error al intentar crear el mapa incrustado: {0}
@@ -1756,9 +1836,30 @@ eventRegattaHeaderLegendGpsNo=No hay datos de rastreo
eventRegattaHeaderLegendWindNo=No hay datos de viento
eventRegattaHeaderLegendVideoNo=No hay transmisiones de vídeo
eventRegattaHeaderLegendAudioNo=No hay transmisiones de audio
angleInDegree=Ángulo en grado
angleInRadian=Ángulo en radián
centralAngleInRadian=Ángulo central en radián
centralAngleInDegree=Ángulo central en grado
kilometers=Kilómetros
meters=Metros
nauticalMiles=Millas náuticas
seaMiles=Millas marinas
geographicalMiles=Millas geográficas
days=Días
hours=Horas
minutes=Minutos
seconds=Segundos
milliseconds=Milisegundos
floatNumber=Flotador
integer=Entero
appendResult=Resultado de estructura append
sampleColor=Muestra de color
sharedSettingsLink=Enlace con opciones
leaderboardPage=Página de clasificación
makeDefault=Establecer como predeterminado
makeDefaultInProgress=En curso...
settingsSavedMessage=Sus opciones actuales se han definido correctamente como estándar
settingsSaveErrorMessage=Se ha producido un error durante la definición de sus opciones como estándar
showLiveNow=Mostrar "En directo ahora"
useOnlyOneOfStartTimeInferenceAndControlTrackingFromStartAndFinishTimes=Utilice solo una "Inferencia de hora de inicio" y "Control de rastreo de horas de inicio y de fin"
unknownLeaderboardType=Tipo de tabla de clasificación {0} desconocido
@@ -1770,13 +1871,17 @@ raceRankShort=Posición de carrera
showRaceRankColumn=Mostrar posición de carrera
estimatedDistance=Distancia estimada
estimatedTime=Hora estimada
nothingUpcoming=Actualmente no existen más carreras planificadas
nothingUpcoming=No existen más carreras que comiencen pronto
noUpcomingRaceDataAvailable=Sin datos disponibles de próxima carrera
reallyRemoveSeries=¿Desea realmente eliminar la serie "{0}"? Nota: todos los logs de las columnas de carrera anexas también se eliminarán de forma permanente.
settingsId=ID de opciones
documentSettingsId=ID de opciones de documento
settingsForId=Opciones para ID ''''{0}''''
userProfileSettingsTabDescription=Las opciones del usuario se generan mediante los diálogos de opciones que se encuentran en varios puntos de la página. Esta vista muestra todas sus opciones agrupadas de una manera técnica para los usuarios expertos. Tenga en cuenta que las entradas eliminadas no se pueden restablecer, por lo que tenga precaución al utilizarlas.
resetToDefault=Reinicializar a valores por defecto
resetToDefaultInProgress=Reinicializando...
settingsRemoved=Opciones por defecto restablecidas
settingsRemovedError=No se han podido restablecer las opciones por defecto
userSettingsFilter=Filtro de opciones
requiresRegattaRaceAndLeaderboard=Esta página requiere un nombre de regata, un nombre de carrera y un nombre de tabla de clasificación válidos.
couldNotFindRaceInRegatta=No se ha podido obtener la carrera con el nombre {0} para la regata con el nombre {1}
@@ -1808,6 +1913,7 @@ errorFetchingDimensionData=Error al obtener los valores de dimensión de {0} : {
errorFetchingStatistics=Error al obtener las estadísticas disponibles desde el servidor: {0}
errorFetchingAggregators=Error al obtener los agregadores disponibles desde el servidor: {0}
errorLoadingDataRetrieverChainDefinitions=Error al recuperar las DataRetrieverChainDefinitions disponibles: {0}
errorFetchingComponentsChangedTimepoint=Error al obtener la fecha modificada de los componentes a partir del servidor: {0}
errorRunningQuery=Error al ejecutar la consulta: {0}
errorReadingWindFixes=Error al leer las correcciones de viento {0}
errorAddingWindFixForRace=Error al añadir una corrección de viento para la carrera {0}: {1}
@@ -1881,6 +1987,11 @@ minimumRideHeightInMetersTooltip=La altura de marcha mínima en metros requerida
minimumDurationBetweenAdjacentFoilingSegmentsInSeconds=Duración mínima entre apéndice(s) de foil
minimumDurationBetweenAdjacentFoilingSegmentsInSecondsTooltip=Si no está en blanco y el tiempo entre dos apéndices de foil adyacentes es inferior, aquellos apéndices de foil adyacentes se fusionarán en uno solo.
needToProvideValidMinimumRideHeight=Requiere proporcionar un valor de altura de marcha mínimo válido en metros.
dataMiningErrorMargins=Márgenes de error
elements={0} elementos
chooseDifferentDimensionTitle=Seleccione una dimensión diferente
chooseDifferentDimensionMessage=Seleccione una dimensión diferente para agrupar resultados
pleaseSelectADimension=Seleccione una dimensión
currentPortDaggerboardRake=Inclinación de la orza de babor
currentPortDaggerboardRakeTooltip=La inclinación actual de la orza de babor
currentStbdDaggerboardRake=Inclinación de la orza de estribor
@@ -9,10 +9,12 @@ trackedBefore=Historique des manifestations suivies
general=Généralités
listRaces=Lister courses
listRegattas=Lister régates
numberPairResultsPresenter=Concentration points mesure
wind=Vent
maneuverType=Manœuvre
windPanelLabel=Ceci est le panneau des mesures du vent, vide pour l''instant.
refresh=Actualiser
remove=Supprimer
removeNumber=Supprimer ({0})
windSource=Source du vent
dampeningInterval=Intervalle d''atténuation
@@ -51,6 +53,7 @@ trackedRaceConnectedToSelectedRaceName=Course suivie liée au nom de course sél
linkToColumn=Lier à la colonne
unlink=Annuler Lier
leaderboardName=Nom du palmarès
cancel=Annuler
pleaseEnterAName=Saisissez un nom.
pleaseEnterABoatClass=Saisissez une catégorie de bateau.
discardRacesFromHowManyStartedRacesOn=Éliminez une course de plus en commençant au nombre de courses déjà lancées.
@@ -62,6 +65,7 @@ startingFromNumberOfRaces=Début au nombre de courses
renameLeaderboard=Renommer palmarès
addColumnToLeaderboard=Ajouter colonne à palmarès
pleaseEnterNameForNewRaceColumn=Saisissez un nom pour la nouvelle colonne de course.
ok=OK
medalRace=Course médaillée
renameRace=Renommer course
openSelectedLeaderboard=Ouvrir le palmarès sélectionné
@@ -85,6 +89,7 @@ sapSailingAnalytics=Sailing Analytics
leaderboard=Palmarès
leaderboards=Palmarès
leaderboardSettings=Options du palmarès
settings=Options
selectAtLeastOneLegDetail=Sélectionnez au moins un détail de portion de parcours.
currentSpeedOverGroundInKnots=Vf
currentSpeedOverGroundInKnotsTooltip=La vitesse fond actuelle.
@@ -168,6 +173,7 @@ tacks=Virements
jibes=Changements d''amure
penaltyCircles=Tours de pénalité
medalRaceIsNull=Valeur de course à la médaille non autorisée
configuration=Configuration
maneuverTypes=Manœuvres
chooseChart=Sélectionner graphique
distanceTraveled=Distance parcourue
@@ -185,11 +191,13 @@ secondsPerNauticalMileUnit=s/NM
metersUnit=m
millimetersUnit=mm
degreesUnit=°
close=Fermer
compareCompetitors=Comparer concurrents
description=Description
sailNumber=Numéro de voile
country=Pays
no3LetterCodes=Codes CIO à trois lettres introuvables
add=Ajouter
delete=Supprimer
showCharts=Afficher graphiques
raceWithThisNameAlreadyExists=Une course de ce nom existe déjà.
@@ -261,6 +269,7 @@ printHint=Imprime la version appliquée
blockedApplyButton=Le nombre de concurrents inscrits ne correspond pas au nombre de concurrents de la liste d''appariement.
multiplierInfo=Multipliez les flights et créez-les les uns après les autres pour obtenir une compétition avec le moins de bateaux possible.
noPairingListAvailable=La fonction d''impression est uniquement disponible lorsqu''une liste d''appariement a déjà été appliquée aux journaux de course des palmarès sélectionnés.
settingsForComponent=Options pour {0}
noEventsFound=Aucune manifestation trouvée
noEventSelected=Aucune manifestation sélectionnée
noLeaderboardsFound=Aucun palmarès trouvé
@@ -298,6 +307,8 @@ leaderboardGroup=Groupe de palmarès
pleaseEnterNonEmptyDescription=Saisissez une description (ne pas laisser vide).
groupWithThisNameAlreadyExists=Un groupe de palmarès de ce nom existe déjà.
detailsOfLeaderboardGroup=Détails du groupe de palmarès
edit=Modifier
save=Enregistrer
abort=Abandonner
noLeaderboardGroupWithNameFound=Aucun groupe de palmarès ayant pour nom {0} n''a été trouvé.
overview=Synthèse
@@ -332,6 +343,7 @@ degreesShort=deg
untracked=Non suivi
delayForLiveMode=Décalage pour mode en direct
notAvailable=Non disponible
details=Détails
noGroupSelected=Aucun groupe sélectionné
combinedWindSourceTypeName=Combiné
legMiddleWindSourceTypeName=Milieu de la portion de parcours
@@ -413,6 +425,7 @@ simulateAsLiveRace=Simulation de course en direct
simulateWithOffset=Décalage avant le départ (en minutes) :
boatClassDoesNotMatchSelectedRegatta=Les courses sélectionnées contiennent des catégories de bateaux qui ne sont pas identiques à la catégorie de bateau "{0}" de la régate sélectionnée. Aucune course ne sera chargée.
regattaExistForSelectedBoatClass=Il existe au moins une régate pour les catégories de bateaux sélectionnées. Voulez-vous vraiment créer une (des) régate(s) pour cette (ces) course(s) ?
reload=Recharger
addRegatta=Ajouter régate...
importRegattas=Importer régates...
exchangeName=Nom d''échange
@@ -634,6 +647,7 @@ totalNetPointsColumnTooltip=Total net des points d''un concurrent dans la régat
windData=Données de vent
gpsData=Données GPS
status=Statut
noDataFound=Aucune donnée trouvée
displayName=Afficher nom
histogram=Histogramme
numberOfDataPoints=Nombre de points de données
@@ -881,9 +895,12 @@ legType=Type de portion de parcours
sailID=Numéro de voile
seriesLeaderboard=Palmarès de la série
regattaLeaderboards=Palmarès de la régate
clearSelection=Réinitialiser sélection
running=En cours d''exécution
runAsSubstantive=Exécuter
done=Terminé
lastFinished=Fin de dernière exécution
run=Exécuter
times=durées
dataAmount=Volume de données
averageCleanedServerTime=∅ Durée de nettoyage du serveur
@@ -907,8 +924,12 @@ selectSheet=Sélectionner fiche
cleanedServerTime=Durée de nettoyage du serveur
overallTime=Durée globale
cleanedOverallTime=Durée globale de nettoyage
dataMiningResult=Résultat d''exploration de données
groupBy=Regrouper par
statisticToCalculate=Calculer statistiques
queryResultsChartSubtitle={0} entrées de données analysées en {1} secondes
noQuerySelected=Aucune requête sélectionnée
runAutomatically=Exécuter automatiquement
windImport_Upload=Charger
windImport_Title=Importer vent à partir de Expedition
windImport_BoatId=N° du bateau :
@@ -938,9 +959,14 @@ raceTimeTooltip=Durée de navigation totale dans cette course, chronométrée à
raceTimeDownwindTooltip=Durée totale de navigation vent arrière dans cette course
raceTimeReachingTooltip=Durée totale de navigation jusqu''à l''arrivée dans cette course
raceTimeUpwindTooltip=Durée totale de navigation dans le lit du vent dans cette course
noStatisticSelectedError=Aucune statistique à calculer sélectionnée
noCustomGrouperScriptTextError=Script de regroupement vide
noDimensionToGroupBySelectedError=Aucune dimension sélectionnée pour le regroupement
noGrouperSelectedError=Aucun type de regroupement sélectionné
noDataRetrieverChainDefinitonSelectedError=Aucun récupérateur de données sélectionné
queryNotValidBecause=Aucune requête possible dû à
dataMining=Exploration de données
errorRunningDataMiningQuery=Une erreur s''est produite lors de l''exécution de la requête.
hideToolbar=Masquer barre d''outils
showSeriesLeaderboards=Afficher palmarès de la série
showOverallLeaderboard=Afficher palmarès général
@@ -963,6 +989,7 @@ id=ID
allowReload=Autoriser rechargement
compress=Comprimer
compressTooltip=Utiliser seulement si l''instance de serveur d''exportation \ns''exécute au moins avec le commit 0fbf6071dea125bec4a56dee55d61c99def4a62e.
queryRunner=Outil d''exécution de requêtes
rerunQueryAfterRefresh=Exécuter la requête de nouveau après l''actualisation
refreshIntervalMustntBeEmpty=L''intervalle d''actualisation ne doit pas être vide.
selectionTables=Tables de sélection
@@ -1047,7 +1074,12 @@ TWATooltip=L''angle entre la direction du concurrent et le vent.
TWA=Angle du vent réel
showBoatClassChartsLabel=Vous pouvez également afficher le diagramme global pour les catégories de bateau disponibles.
showDiagram=Afficher diagramme
runAutomaticallyTooltip=Exécutez la requête automatiquement, par exemple après avoir modifié les statistiques ou le regroupement.
rerunQueryAfterRefreshTooltip=Réexécute la requête après l''actualisation des tables.
queryDefinitionProvider=Fournisseur de définitions de requêtes
statisticProvider=Fournisseur de statistiques
calculateThe=Calculer le/la
groupingProvider=Fournisseur de regroupements
releaseNotes=Historique de versions et nouveautés
hasSplitFleetContiguousScoring=Les flottes divisées ont obtenu des scores contigus.
addRaceLogTracker=Ajouter tracker de journal de course
@@ -1205,6 +1237,7 @@ showAll=Afficher tout
raceVisibilityColumn=Visibilité
enterCarryValueFor=Saisissez les points accumulés par le concurrent {0}.
advanced=Avancé
basedOn=basé sur
retrieveWith=Récupérer avec
mappingDetails=Détails du mappage
deviceMappingQrCodeExplanation=Si vous utilisez l''application de suivi, vous pouvez également ajouter le mappage de l''appareil en sélectionnant un concurrent/une marque, en définissant des heures de départ et d''arrivée et en scannant ce code QR.
@@ -1215,6 +1248,10 @@ enterImageURL=Saisissez l''URL de l''image...
enterVideoURL=Saisissez l''URL de la vidéo...
enterSponsorImageURL=Saisissez l''URL de l''image du sponsor...
enterRaceName=Saisissez le nom du parcours...
serverError=Une erreur s''est produite lors de la tentative de contact du serveur. Vérifiez la connexion réseau et réessayez.
remoteProcedureCall=Procédure d''appel distante
serverReplies=Réponses du serveur
errorCommunicatingWithServer=Erreur lors de la communication avec le serveur
userManagement=Gestion des utilisateurs
regattaStructureImport=Importation de la structure de la régate
filteredBy=filtré par
@@ -1242,6 +1279,7 @@ noFleetsDefined=Aucune flotte définie
successfullyCreatedRegattas=Création des régates réussie
errorTryingToRegisterRacesForTracking=Erreur lors de la tentative d''enregistrement des courses {0} pour le suivi : {1}. Vérifiez la syntaxe de l''URL stockée/du direct.
errorDeterminingPolarAvailability=Erreur lors de la détermination de la disponibilité des données polaires/VPP pour la course {0} : {1}
error=Erreur
fileStorage=Stockage du fichier
active=Actif
scoringSchemeHighPointEssOverallDescription=Score en points. Le vainqueur d''un Act totalise 10 points, le 2e - 9 points, etc. En cas d''égalité au classement général des Extreme Sailing Series, la victoire est accordée au concurrent ayant remporté le plus d''Act. Si l''égalité persiste, le résultat obtenu au dernier Act sera utilisé.
@@ -1284,6 +1322,7 @@ showCompetitorFullNameColumn=Nom complet du concurrent
alwaysShowCompetitorNationalityColumn=Afficher toujours la nationalité du concurrent
alwaysShowCompetitorNationalityColumnTooltip=Si disponibles, afficher les deux : le drapeau national ainsi que l''image du concurrent
loadingDimensionValues=Chargement des valeurs de dimension
runningQuery=Requête en cours
inviteBuoyTenders=Inviter navire baliseur
orMultipleEmails=ou plusieurs adresses e-mails séparées par des virgules
courseOverGroundTrueDegreesTooltip=Route fond vraie en degrés
@@ -1291,6 +1330,11 @@ courseOverGroundTrueDegrees=Route fond
distanceIncludingGateStartInMeters=Distance (si départ au lièvre)
distanceTraveledIncludingGateStartTooltip=La distance naviguée du départ de la portion de parcours jusqu''à sa fin\nou jusqu''à l''heure actuelle (si la portion de parcours n''est pas terminée).\nSi la portion de parcours inclut un départ au lièvre, la distance de la bouée de ligne jusqu''à la position de départ est incluse \npour permettre de comparer les concurrents même si leur départ ne s''est pas fait à la même heure.
raceDistanceTraveledIncludingGateStartTooltip=La distance naviguée du départ de la course jusqu''à sa fin\nou jusqu''à l''heure actuelle (si la course n''est pas terminée).\nEn cas de départ au lièvre, la distance de la bouée de ligne jusqu''à la position de départ est incluse \npour permettre de comparer les concurrents même si leur départ ne s''est pas fait à la même heure.
results=Résultats
groupName=Nom du groupe
valueAscending=Valeur (ascendant)
valueDescending=Valeur (descendant)
sortBy=Trier par
dashboardHeader=Tableau de bord
dashboardNoWindBotAvailableHeader=Le bot du vent n''est pas disponible.
dashboardNoWindBotAvailableMessage=Pour pouvoir recevoir des données de vent depuis des unités de mesure du vent, assurez-vous que le bot du vent est allumé et connecté à SAP Sailing Analytics.
@@ -1326,12 +1370,16 @@ dashboardRCBoat=Bateau du comité de course
fixedMarkPassing=(fixé)
suppressedMarkPassing=(supprimé)
windUp=Orienté par rapport au sens du vent (le vent vient du haut de la carte)
filterBy=Filtrer par
currentFilterSelection=Sélection du filtre actuel
notCapableOfGeneratingACodeForIdentifier=Je ne suis pas capable de générer un code pour cet identifiant.
serverUrl=URL du serveur
rotatedFromTrueNorth=Pivoté de {0} degrés à partir du vrai Nord.
clickToToggleWindUp=Touchez/Cliquez pour basculer entre l''affichage orienté nord et l''affichage par rapport au sens du vent
clickToToggleWindStreamlets=Touchez/cliquez pour afficher ou masquer les couloirs de vent.
startLineToFirstMarkTriangle=Distance entre le départ et la première marque ({0} m)
dataMiningComponentsHaveBeenUpdated=Les composants d''exploration de données ont été mis à jour.
dataMiningComponentsNeedReloadDialogMessage=Cliquez sur Recharger pour recharger les composants maintenant. Les données actuellement affichées seront ignorées et une requête par défaut sera exécutée.n\Cliquez sur Fermer pour ne rien faire. L''exploration de données ne fonctionnera pas correctement tant que les composants n''auront pas été rechargés.
noDataForEvent=Il n''y a pas encore de données pour cette manifestation.
countriesCount={0,number} pays
countriesCount[one]={0,number} pays
@@ -1429,7 +1477,15 @@ noFinishedRaces=Aucune course terminée pour l''instant.
racesOverview=Synthèse des courses
listFormatLabel=Format de liste
competitionFormatLabel=Format de compétition
empty=Vide
runAQuery=Exécuter une requête
latestRegattaStandings=Classement de régate le plus récent
plainText=Texte brut
columnChart=Diagramme à colonnes
columnChartWithErrorBars=Diagramme à colonnes avec barres d''erreur
choosePresentation=Sélectionner la présentation
cantDisplayDataOfType=Affichage des données du type {0} impossible
shownDecimals=Nombre de décimales
openFullscreenView=Ouvrir le mode Plein écran
closeFullscreenView=Fermer le mode Plein écran
videosCount={0,number} vidéos
@@ -1439,8 +1495,15 @@ photosCount[one]={0,number} photo
eventsHaveTakenPlace={0} manifestations ont eu lieu.
eventsHaveTakenPlace[one]=Une manifestation a eu lieu.
raceOffice=Bureau de course
analyze=Analyser
dataMiningSettings=Options de l''exploration de données
multiResultsPresenter=Visualiseur de résultats multiples
plainResultsPresenter=Visualiseur de résultats bruts
resultsChart=Graphique des résultats
tabbedResultsPresenter=Visualiseur de résultats avec onglets
polarResultsPresenter=Visualiseur de résultats polaires
maneuverSpeedDetailsResultsPresenter=Visualiseur des résultats : détails sur la vitesse lors de la manœuvre
dataMiningRetrieval=Récupération de données
actionWatch=Regarder
actionAnalyze=Analyser
denoteAllRacesForRaceLogTrackingShorctut=Raccourci pour marquer toutes les courses pour le suivi par journaux de course
@@ -1456,8 +1519,24 @@ defaultName=Par défaut
exampleTextForName=Votre nom apparaît de la manière suivante :
flightsCount={0,number} départs de deux équipages
flightsCount[one]={0,number} départ de deux équipages
viewQueryDefinition=Afficher la définition de la requête
queryDefinitionViewer=Visualiseur de définitions de requête
groupAverageAscending=Moyenne du groupe (ascendant)
groupAverageDescending=Moyenne du groupe (descendant)
groupMedianAscending=Médiane du groupe (ascendant)
groupMedianDescending=Médiane du groupe (descendant)
resultsFoundForSearch={0,number} résultats trouvés pour "{1}"
resultsFoundForSearch[one]={0,number} résultat trouvé pour "{1}"
runPredefinedQuery=Exécuter requête prédéfinie
selectPredefinedQuery=Sélectionner requête prédéfinie
predefinedQueryRunner=Outil d''exécution de requêtes prédéfinies
developerOptions=Options développeur
copyToClipboard=Copier dans le presse-papiers
code=Code
useClassGetName=Utilisez Class.getName() pour les noms des types.
useClassGetNameTooltip=Plus stable face aux modifications dans la base de code, mais le fichier de script peut uniquement être utilisé dans l''étendue où les classes sont disponibles.
useStringLiterals=Utiliser littéraux de chaîne pour les noms de types
useStringLiteralsTooltip=Le fichier de script peut être utilisé partout, mais sera corrompu si la base de code change.
errorLoadingDataWithTryAgain=Erreur lors du chargement des données. Nouvel essai dans quelques minutes.
addGalleryPhoto=Ajouter photo de la galerie
addStageImage=Ajouter image d''étape
@@ -1477,6 +1556,7 @@ warningForDisabledCompetitors=Les concurrents suivants ne peuvent pas être insc
competitorToolTipMessage={0} a déjà été affecté à la flotte {2} dans la course {3} et ne peut donc pas être affecté à la flotte {1} dans la même course.
addMarkToRegatta=Ajouter marque à la régate
selectALeaderboardGroup=Sélectionner groupe de palmarès…
pleaseSelect=Sélectionnez
requiresValidRegatta=Pour identifier la course à afficher, cette page nécessite une régate valide, une colonne de course et un nom de flotte.
couldNotObtainRace=Impossible de trouver une course ayant le nom {1} pour la flotte {2} pour une régate ayant le nom {0} : {3}
errorTryingToCreateEmbeddedMap=Erreur lors de la tentative de création de la carte intégrée : {0}
@@ -1756,9 +1836,30 @@ eventRegattaHeaderLegendGpsNo=Aucune donnée de suivi
eventRegattaHeaderLegendWindNo=Aucune donnée de vent
eventRegattaHeaderLegendVideoNo=Aucun flux vidéo
eventRegattaHeaderLegendAudioNo=Aucun flux audio
angleInDegree=Angle en degrés
angleInRadian=Angle en radians
centralAngleInRadian=Angle au centre en radians
centralAngleInDegree=Angle au centre en degrés
kilometers=Kilomètres
meters=Mètres
nauticalMiles=Milles nautiques
seaMiles=Milles marins
geographicalMiles=Milles géographiques
days=Jours
hours=Heures
minutes=Minutes
seconds=Secondes
milliseconds=Millisecondes
floatNumber=Flottant
integer=Entier
appendResult=Ajouter résultat
sampleColor=Échantillon de couleur
sharedSettingsLink=Lier aux options
leaderboardPage=Page du palmarès
makeDefault=Définir par défaut
makeDefaultInProgress=En cours...
settingsSavedMessage=Vos options actuelles ont correctement été définies comme options par défaut.
settingsSaveErrorMessage=Une erreur s''est produite lors de la définition de vos options comme options par défaut.
showLiveNow=Afficher "En direct"
useOnlyOneOfStartTimeInferenceAndControlTrackingFromStartAndFinishTimes=Utilisez "Interférence temporelle de départ" ou bien "Contrôler suivi à partir des heures de départ et d''arrivée", mais pas les deux.
unknownLeaderboardType=Type de palmarès {0} inconnu
@@ -1770,13 +1871,17 @@ raceRankShort=Place dans la course
showRaceRankColumn=Afficher place dans la course
estimatedDistance=Distance estimée
estimatedTime=Temps estimé
nothingUpcoming=Il n''existe actuellement aucune autre course planifiée.
nothingUpcoming=Il n''existe aucune autre course dont le départ est proche.
noUpcomingRaceDataAvailable=Aucune donnée concernant la prochaine course n''est disponible.
reallyRemoveSeries=Voulez-vous vraiment supprimer la série "{0}" ? Note : tous les journaux de la course seront également supprimés de manière permanente pour cette course.
settingsId=ID d''options
documentSettingsId=ID d''options du document
settingsForId=Options pour l''ID "{0}"
userProfileSettingsTabDescription=Les options utilisateur sont générées dans des boîtes de dialogues pour options que vous trouverez à de nombreux endroits sur la page. Cette vue montre toutes vos options regroupées pour les mettre techniquement à disposition des utilisateurs de référence. Soyez prudent : les entrées supprimées ne peuvent pas être restaurées.
resetToDefault=Réinitialiser sur les valeurs par défaut
resetToDefaultInProgress=Réinitialisation en cours...
settingsRemoved=Options par défaut restaurées
settingsRemovedError=Impossible de restaurer les options par défaut
userSettingsFilter=Filtre d''options
requiresRegattaRaceAndLeaderboard=Cette page requiert un nom de régate, un nom de course et un nom de palmarès valides.
couldNotFindRaceInRegatta=Impossible de trouver une course nommée {0} pour une régate nommée {1}.
@@ -1808,6 +1913,7 @@ errorFetchingDimensionData=Erreur lors de l''accès aux valeurs de dimension de
errorFetchingStatistics=Erreur lors de l''accès aux statistiques disponibles du serveur : {0}
errorFetchingAggregators=Erreur lors de l''accès aux agrégateurs disponibles du serveur : {0}
errorLoadingDataRetrieverChainDefinitions=Erreur lors de la récupération des définitions DataRetrieverChainDefinitions disponibles : {0}
errorFetchingComponentsChangedTimepoint=Erreur lors de la récupération de l''heure modifiée du composant du serveur : {0}
errorRunningQuery=Erreur lors de l''exécution de la requête : {0}
errorReadingWindFixes=Erreur lors de la lecture des points vent {0}
errorAddingWindFixForRace=Erreur lors de l''ajout d''un point vent pour la course {0} : {1}
@@ -1881,6 +1987,11 @@ minimumRideHeightInMetersTooltip=Hauteur de planing minimale requise en mètres
minimumDurationBetweenAdjacentFoilingSegmentsInSeconds=Durée minimum (s) entre deux tronçons en planing adjacents
minimumDurationBetweenAdjacentFoilingSegmentsInSecondsTooltip=Si cette valeur est renseignée et que la durée entre deux tronçons de planing adjacents est inférieure à celle-ci, ces tronçons de planing adjacents seront combinés en un seul.
needToProvideValidMinimumRideHeight=Vous devez fournir une valeur de hauteur de planing minimale valide en mètres.
dataMiningErrorMargins=Marges d''erreur
elements={0} éléments
chooseDifferentDimensionTitle=Sélectionnez une dimension différente.
chooseDifferentDimensionMessage=Sélectionnez une dimension différente pour regrouper les résultats.
pleaseSelectADimension=Sélectionnez une dimension.
currentPortDaggerboardRake=Inclinaison de la dérive bâbord
currentPortDaggerboardRakeTooltip=Inclinaison actuelle de la dérive bâbord
currentStbdDaggerboardRake=Inclinaison de la dérive tribord
@@ -9,10 +9,12 @@ trackedBefore=追跡イベントの履歴
general=一般
listRaces=レース一覧
listRegattas=レガッタ一覧
numberPairResultsPresenter=散布図
wind=風
maneuverType=マニューバー
windPanelLabel=これは風パネルであり、今のところ完全に空となっています。
refresh=リフレッシュ
remove=削除
removeNumber=削除 ({0})
windSource=風源
dampeningInterval=制動間隔
@@ -51,6 +53,7 @@ trackedRaceConnectedToSelectedRaceName=選択されたレース名に結び付
linkToColumn=列にリンク
unlink=リンク解除
leaderboardName=リーダーボード名
cancel=取消
pleaseEnterAName=名称を入力してください
pleaseEnterABoatClass=艇種を入力してください
discardRacesFromHowManyStartedRacesOn=レース除外 (スタート済レースから)
@@ -62,6 +65,7 @@ startingFromNumberOfRaces=レース数から開始
renameLeaderboard=リーダーボード名称変更
addColumnToLeaderboard=リーダーボードに列を追加
pleaseEnterNameForNewRaceColumn=新規レース列の名称を入力してください
ok=OK
medalRace=メダルレース
renameRace=レース名称変更
openSelectedLeaderboard=選択したリーダーボードを開く
@@ -85,6 +89,7 @@ sapSailingAnalytics=Sailing Analytics
leaderboard=リーダーボード
leaderboards=リーダーボード
leaderboardSettings=リーダーボード設定
settings=設定
selectAtLeastOneLegDetail=レグ詳細を少なくとも 1 つ選択
currentSpeedOverGroundInKnots=SOG
currentSpeedOverGroundInKnotsTooltip=現在の対地速力です。
@@ -168,6 +173,7 @@ tacks=タック
jibes=ジャイブ
penaltyCircles=ペナルティーサークル
medalRaceIsNull=メダルレース値は不可
configuration=設定
maneuverTypes=マニューバー
chooseChart=チャートの選択
distanceTraveled=移動した距離
@@ -185,11 +191,13 @@ secondsPerNauticalMileUnit=s/NM
metersUnit=m
millimetersUnit=mm
degreesUnit=°
close=閉じる
compareCompetitors=競技者比較
description=内容説明
sailNumber=セールナンバー
country=国
no3LetterCodes=IOC 3 文字コードを検索できませんせした。
add=追加
delete=削除
showCharts=チャート表示
raceWithThisNameAlreadyExists=その名称のレースはすでに登録されています。
@@ -261,6 +269,7 @@ printHint=適用バージョンを印刷
blockedApplyButton=登録されている競技者数が対戦表にある競技者数と同じでありません
multiplierInfo=複数のフライトを艇変更がより少なく競技が可能となるよう互いに隣り合わせに作成
noPairingListAvailable=印刷機能は選択したリーダーボードレースログに対戦表がすでに適用されている場合にのみ利用が可能です。
settingsForComponent={0} の設定
noEventsFound=イベントが見つかりませんでした
noEventSelected=イベントが選択されていません
noLeaderboardsFound=リーダーボードが見つかりませんでした
@@ -298,6 +307,8 @@ leaderboardGroup=リーダーボードグループ
pleaseEnterNonEmptyDescription=空でない説明を入力してください
groupWithThisNameAlreadyExists=この名称のリーダーボードグループはすでに登録されています。
detailsOfLeaderboardGroup=リーダーボードグループの詳細
edit=編集
save=保存
abort=中止
noLeaderboardGroupWithNameFound={0} という名称のリーダーボードグループは見つかりませんでした
overview=概要
@@ -332,6 +343,7 @@ degreesShort=度
untracked=未追跡
delayForLiveMode=ライブモードの遅延:
notAvailable=利用不可
details=詳細
noGroupSelected=グループ未選択
combinedWindSourceTypeName=複合
legMiddleWindSourceTypeName=レグの中間
@@ -413,6 +425,7 @@ simulateAsLiveRace=ライブレースとしてシミュレート
simulateWithOffset=スタート前のオフセット (分):
boatClassDoesNotMatchSelectedRegatta=選択したレースに、選択したレガッタの艇種 ''{0}'' と同じでない艇種が含まれています。レースはロードされません。
regattaExistForSelectedBoatClass=選択した艇種に対して少なくとも 1 つのレガッタがあります。このレースに対してレガッタを初期登録しますか。
reload=リロード
addRegatta=レガッタ追加...
importRegattas=レガッタのインポート...
exchangeName=エクスチェンジ名
@@ -634,6 +647,7 @@ totalNetPointsColumnTooltip=レガッタにおける競技者の総合得点を
windData=風データ
gpsData=GPS データ
status=ステータス
noDataFound=データが見つかりませんでした
displayName=名称表示
histogram=ヒストグラム
numberOfDataPoints=データポイント数
@@ -881,9 +895,12 @@ legType=レグタイプ
sailID=セールナンバー
seriesLeaderboard=シリーズリーダーボード
regattaLeaderboards=レガッタリーダーボード
clearSelection=選択のクリア
running=実行中
runAsSubstantive=実行
done=実行済
lastFinished=最終フィニッシュ
run=実行
times=回
dataAmount=データ量
averageCleanedServerTime=∅ サーバ時間のクリア
@@ -907,8 +924,12 @@ selectSheet=シート選択
cleanedServerTime=サーバ時間のクリア
overallTime=全体時間
cleanedOverallTime=全体時間のクリア
dataMiningResult=データマイニング結果
groupBy=グループキー
statisticToCalculate=統計の計算
queryResultsChartSubtitle={0} データエントリを {1} 秒で処理済
noQuerySelected=クエリ未選択
runAutomatically=自動的に実行
windImport_Upload=アップロード
windImport_Title=Expedition から風をインポート
windImport_BoatId=艇 ID:
@@ -938,9 +959,14 @@ raceTimeTooltip=競技者がスタート変針点を通過したときに計測
raceTimeDownwindTooltip=このレースでダウンウィンドで移動した合計時間
raceTimeReachingTooltip=このレースでリーチングで移動した合計時間
raceTimeUpwindTooltip=このレースでアップウィンドで移動した合計時間
noStatisticSelectedError=計算する統計が選択されていません
noCustomGrouperScriptTextError=分類スクリプトが空です
noDimensionToGroupBySelectedError=グループ別にする次元が選択されていません
noGrouperSelectedError=分類タイプが選択されていません
noDataRetrieverChainDefinitonSelectedError=データリトリーバが選択されていません
queryNotValidBecause=クエリが可能でありません。理由:
dataMining=データマイニング
errorRunningDataMiningQuery=クエリ実行でエラーが発生しました
hideToolbar=ツールバー非表示
showSeriesLeaderboards=シリーズリーダーボード表示
showOverallLeaderboard=全体リーダーボード表示
@@ -963,6 +989,7 @@ id=ID
allowReload=リロード許可
compress=圧縮
compressTooltip=エクスポートサーバインスタンスが少なくとも\nコミット 0fbf6071dea125bec4a56dee55d61c99def4a62e で実行中の場合にのみ使用してください。
queryRunner=クエリランナー
rerunQueryAfterRefresh=リフレッシュ後にクエリを再実行
refreshIntervalMustntBeEmpty=リフレッシュ間隔は空であってはなりません
selectionTables=選択テーブル
@@ -1047,7 +1074,12 @@ TWATooltip=競技者の方向と風の間のアングル
TWA=真の風角度
showBoatClassChartsLabel=利用可能な艇種の全体図も表示することができます。
showDiagram=ダイアグラム表示
runAutomaticallyTooltip=統計やグルーピングなどを変更した後にクエリを自動的に実行します。
rerunQueryAfterRefreshTooltip=テーブルがリフレッシュされた後にクエリを再実行します。
queryDefinitionProvider=クエリ定義プロバイダ
statisticProvider=統計プロバイダ
calculateThe=計算:
groupingProvider=グルーピングプロバイダ
releaseNotes=新規およびリリース履歴
hasSplitFleetContiguousScoring=連続的に得点するフリートの分割
addRaceLogTracker=RaceLog トラッカー追加
@@ -1205,6 +1237,7 @@ showAll=全表示
raceVisibilityColumn=可視性
enterCarryValueFor=競技者 {0} の持ち越し得点を入力
advanced=予選通過
basedOn=基準
retrieveWith=検索キー
mappingDetails=マッピング詳細
deviceMappingQrCodeExplanation=追跡アプリを使用している場合は、競技者/マークを選択し、開始時刻と終了時刻を設定してから、この QRCode をスキャンすることによってデバイスマッピングも追加することができます。
@@ -1215,6 +1248,10 @@ enterImageURL=画像 URL を入力...
enterVideoURL=動画 URL を入力...
enterSponsorImageURL=スポンサー画像 URL を入力...
enterRaceName=レース名を入力...
serverError=サーバにアクセスしようとしてエラーが発生しました。ネットワーク接続を確認して再試行してください。
remoteProcedureCall=リモートプロシージャコール
serverReplies=サーバ応答
errorCommunicatingWithServer=サーバとの通信でエラー発生
userManagement=ユーザ管理
regattaStructureImport=レガッタ構成のインポート
filteredBy=フィルタキー
@@ -1242,6 +1279,7 @@ noFleetsDefined=フリートが定義されていません。
successfullyCreatedRegattas=レガッタが登録されました
errorTryingToRegisterRacesForTracking=追跡するレース {0} を登録しようとしてエラーが発生: {1}。ライブ/格納 URI 構文をチェックしてください。
errorDeterminingPolarAvailability=レース {0} のポーラー/VPP データの利用可能性の決定でエラー発生: {1}
error=エラー
fileStorage=ファイルストレージ
active=有効
scoringSchemeHighPointEssOverallDescription=得点数によるスコアです。アクトの勝者が 10 点、2 位が 9 点などと得点します。Extreme Sailing シリーズ全体で同点となった場合は、より多くのアクトで勝者となった競技者を上位とします。それでも同じ場合には、最終アクトの結果を用います。
@@ -1284,6 +1322,7 @@ showCompetitorFullNameColumn=競技者氏名
alwaysShowCompetitorNationalityColumn=競技者国籍を常に表示
alwaysShowCompetitorNationalityColumnTooltip=国旗と競技者画像 (利用可能な場合) の両方を表示
loadingDimensionValues=次元値ロード中
runningQuery=クエリ実行中
inviteBuoyTenders=ブイ入札の招待
orMultipleEmails=または複数の電子メールをカンマで区切り
courseOverGroundTrueDegreesTooltip=真の対地方位角度 (度)
@@ -1291,6 +1330,11 @@ courseOverGroundTrueDegrees=COG
distanceIncludingGateStartInMeters=距離 (ゲートスタートでの)
distanceTraveledIncludingGateStartTooltip=レグ始点からレグ終点まで、またはレグをフィニッシュ\nしていない場合は現時点までに移動した距離です。\nレグにゲートスタートが含まれる場合は、異なる時刻にスタートしたときでも\n競技者を比較するためにピンエンドからスタート位置までの距離が含まれます。
raceDistanceTraveledIncludingGateStartTooltip=レース開始からレース終了まで、またはレースがフィニッシュ\nしていない場合は現時点までに移動した距離です。ゲートスタートの場合は、異なる時刻にスタートしたときでも\n競技者を比較するためにピンエンドからスタート位置までの距離が含まれます。
results=結果
groupName=グループ名
valueAscending=値 (昇順)
valueDescending=値 (降順)
sortBy=ソートキー
dashboardHeader=ダッシュボード
dashboardNoWindBotAvailableHeader=ウィンドボットは利用できません。
dashboardNoWindBotAvailableMessage=風計測ユニットからライブ風データを受信するには、ウィンドボットがオンになっていて、SAP Sailing Analytics に接続されていることを確認してください。
@@ -1326,12 +1370,16 @@ dashboardRCBoat=RC 艇
fixedMarkPassing=(固定)
suppressedMarkPassing=(非表示)
windUp=ウィンドアップ (マップの最上部から風を表示)
filterBy=フィルタキー
currentFilterSelection=現在のフィルタ選択
notCapableOfGeneratingACodeForIdentifier=この ID のコードを生成することができません。
serverUrl=サーバ URL
rotatedFromTrueNorth=真北から {0} 度回転しました。
clickToToggleWindUp=タップ/クリックして、風上が上のマップと北が上のマップとで表示を切り替えます
clickToToggleWindStreamlets=タップ/クリックして風細流を表示または非表示にします
startLineToFirstMarkTriangle=スタートから第一マークまで ({0}m)
dataMiningComponentsHaveBeenUpdated=データマイニングコンポーネントが更新されました
dataMiningComponentsNeedReloadDialogMessage=リロードをクリックして、コンポーネントをリロードします。これにより、現在表示されているデータが破棄され、デフォルトクエリが実行されます。\n何も行わない場合は閉じるをクリックします。データマイニングは、コンポーネントがリロードされるまでは正しく機能しません。
noDataForEvent=このイベントにまだデータが何もありません。
countriesCount={0,number} カ国
countriesCount[one]={0,number} カ国
@@ -1429,8 +1477,15 @@ noFinishedRaces=フィニッシュしたレースがまだありません。
racesOverview=レース概要
listFormatLabel=レース一覧
competitionFormatLabel=競技日
empty=空
runAQuery=クエリを実行
latestRegattaStandings=レガッタ最新順位表
plainText=プレーンテキスト
columnChart=縦棒グラフ
columnChartWithErrorBars=縦棒グラフ (エラーバーあり)
choosePresentation=プレゼンテーション選択
cantDisplayDataOfType={0} タイプのデータは表示できません。
shownDecimals=小数点表示
openFullscreenView=全画面ビューを開く
closeFullscreenView=全画面ビューを閉じる
videosCount={0,number} 動画
@@ -1440,8 +1495,15 @@ photosCount[one]={0,number} 写真
eventsHaveTakenPlace={0} イベントが行われました
eventsHaveTakenPlace[one]=1 つのイベントが行われました
raceOffice=レース事務所
analyze=分析
dataMiningSettings=データマイニング設定
multiResultsPresenter=複数結果表示
plainResultsPresenter=プレーン結果表示ツール
resultsChart=結果チャート
tabbedResultsPresenter=タブ結果表示ツール
polarResultsPresenter=ポーラー結果表示ツール
maneuverSpeedDetailsResultsPresenter=マニューバー速度詳細結果表示ツール
dataMiningRetrieval=データ取得
actionWatch=視聴
actionAnalyze=分析
denoteAllRacesForRaceLogTrackingShorctut=レースログ追跡の全レース表示へのショートカット
@@ -1457,8 +1519,24 @@ defaultName=デフォルト
exampleTextForName=名前は次のようになります:
flightsCount={0,number} フライト
flightsCount[one]={0,number} フライト
viewQueryDefinition=クエリ定義の表示
queryDefinitionViewer=クエリ定義ビューア
groupAverageAscending=グループ平均 (昇順)
groupAverageDescending=グループ平均 (降順)
groupMedianAscending=グループ中央値 (昇順)
groupMedianDescending=グループ中央値 (降順)
resultsFoundForSearch={0,number} 結果が ''{1}’ に見つかりました
resultsFoundForSearch[one]={0,number} 結果が ''{1}’ に見つかりました
runPredefinedQuery=事前定義クエリを実行
selectPredefinedQuery=事前定義クエリを選択
predefinedQueryRunner=事前定義クエリランナー
developerOptions=開発者オプション
copyToClipboard=クリップボードにコピー
code=コード
useClassGetName=タイプ名に class.getName() を使用
useClassGetNameTooltip=コードベースでの変更に対してより堅牢ですが、コードスニペットはクラスが利用できる範囲でのみ使用できます。
useStringLiterals=タイプ名に文字列リテラルを使用
useStringLiteralsTooltip=このコードスニペットはどこでも使用できますが、コードベースが変更される場合は中断します。
errorLoadingDataWithTryAgain=データのロードでエラーが発生しました。しばらくしてから再試行してください。
addGalleryPhoto=ギャラリーフォト追加
addStageImage=ステージ画像追加
@@ -1478,6 +1556,7 @@ warningForDisabledCompetitors=次の競技者はこのレースに登録する
competitorToolTipMessage={0} はすでにレース {3} のフリート {2} に割り当てられており、そのため同一レース内でフリート {1} に割り当てることはできません
addMarkToRegatta=マークをレガッタに追加
selectALeaderboardGroup=リーダーボードグループを選択...
pleaseSelect=選択:
requiresValidRegatta=このページには、表示するレースを識別するために有効なレガッタ、レース列、およびフリート名が必要です。
couldNotObtainRace=名称 {0} のレガッタに対してフリート {2} の名称 {1} でレースが取得できませんでした: {3}
errorTryingToCreateEmbeddedMap=埋込マップを登録しようとしてエラーが発生: {0}
@@ -1757,9 +1836,30 @@ eventRegattaHeaderLegendGpsNo=航跡データなし
eventRegattaHeaderLegendWindNo=風向風速データなし
eventRegattaHeaderLegendVideoNo=動画ストリームなし
eventRegattaHeaderLegendAudioNo=音声ストリームなし
angleInDegree=角度 (度)
angleInRadian=角度 (ラジアン)
centralAngleInRadian=中心角 (度)
centralAngleInDegree=中心角 (ラジアン)
kilometers=キロメートル
meters=メートル
nauticalMiles=海里
seaMiles=海里
geographicalMiles=地理マイル
days=日
hours=時間
minutes=分
seconds=秒
milliseconds=ミリ秒
floatNumber=浮動小数点型
integer=整数
appendResult=結果を追加
sampleColor=色サンプル
sharedSettingsLink=設定にリンク
leaderboardPage=リーダーボードページ
makeDefault=デフォルトを設定
makeDefaultInProgress=実行中です...
settingsSavedMessage=現在の設定がデフォルトとして設定されました
settingsSaveErrorMessage=使用している設定をデフォルトとして設定する際にエラーが発生しました
showLiveNow="実況中" を表示
useOnlyOneOfStartTimeInferenceAndControlTrackingFromStartAndFinishTimes="推定スタート時刻" および "スタート/フィニッシュ時刻からのコントロール追跡" は 1 つだけ使用してください
unknownLeaderboardType=未知のリーダーボードタイプ {0}
@@ -1771,13 +1871,17 @@ raceRankShort=レースランク
showRaceRankColumn=レースランクを表示
estimatedDistance=推定距離
estimatedTime=推定時間
nothingUpcoming=現時点で予定されているレースはありません
nothingUpcoming=まもなく開始されるレースはありません
noUpcomingRaceDataAvailable=予定されているレースのデータはありません
reallyRemoveSeries=シリーズ ''{0}'' を削除しますか。注記: 付属しているレース列のレースログもすべて永続的に削除されます。
settingsId=設定 ID
documentSettingsId=文書設定 ID
settingsForId=ID ''{0}'' の設定
userProfileSettingsTabDescription=ユーザ設定は、このページの多くの場所にあるダイアログを設定することによって生成されます。このビューには、収集したすべての設定がパワーユーザ向けの技術的な方法で表示されます。削除したエントリは復元できないため、注意して使用してください。
resetToDefault=デフォルトに戻す
resetToDefaultInProgress=リセット中です...
settingsRemoved=デフォルト設定が復元されました
settingsRemovedError=デフォルト設定を復元できませんでした
userSettingsFilter=設定フィルタ
requiresRegattaRaceAndLeaderboard=このページには有効なレガッタ名、レース名、およびリーダーボード名が必要です。
couldNotFindRaceInRegatta=名前 {1} のレガッタに対して名前 {0} のレースが取得できませんでした
@@ -1809,6 +1913,7 @@ errorFetchingDimensionData={0} の次元値のフェッチでエラーが発生:
errorFetchingStatistics=サーバからの利用可能な統計のフェッチでエラーが発生: {0}
errorFetchingAggregators=サーバからの利用可能な集計のフェッチでエラーが発生: {0}
errorLoadingDataRetrieverChainDefinitions=利用可能な DataRetrieverChainDefinitions の取得でエラーが発生: {0}
errorFetchingComponentsChangedTimepoint=サーバからのコンポーネント変更済タイムポイントのフェッチでエラーが発生: {0}
errorRunningQuery=クエリの実行でエラーが発生: {0}
errorReadingWindFixes=風フィックス {0} の読込でエラーが発生しました
errorAddingWindFixForRace=レース {0} に対する風フィックスの追加でエラーが発生: {1}
@@ -1882,6 +1987,11 @@ minimumRideHeightInMetersTooltip=艇がフォイリング状態にあるとみ
minimumDurationBetweenAdjacentFoilingSegmentsInSeconds=隣り合ったフォイリングセグメント間の最小時間 (秒)
minimumDurationBetweenAdjacentFoilingSegmentsInSecondsTooltip=空白でなく、隣り合った 2 つのフォイリングセグメント間の時間がこの値より小さい場合、隣り合ったこれらのフォイリングセグメントは 1 つにマージされます。
needToProvideValidMinimumRideHeight=浮上高さの有効な値をメートル単位で指定する必要があります。
dataMiningErrorMargins=エラーマージン
elements={0} 要素
chooseDifferentDimensionTitle=異なる次元の選択
chooseDifferentDimensionMessage=結果をグルーピングするための異なる次元を選択してください
pleaseSelectADimension=次元を選択してください
currentPortDaggerboardRake=左舷ダガーボード傾斜角
currentPortDaggerboardRakeTooltip=現在の左舷ダガーボード傾斜角
currentStbdDaggerboardRake=右舷ダガーボード傾斜角
@@ -9,10 +9,12 @@ trackedBefore=Histórico de eventos rastreados
general=Geral
listRaces=Listar corridas
listRegattas=Listar regatas
numberPairResultsPresenter=Diagrama de dispersão
wind=Vento
maneuverType=Manobra
windPanelLabel=Este é o painel eólico que até o momento está completamente vazio.
refresh=Atualizar
remove=Remover
removeNumber=Remover ({0})
windSource=Origem do vento
dampeningInterval=Intervalo de atenuação
@@ -51,6 +53,7 @@ trackedRaceConnectedToSelectedRaceName=Corrida rastreada conectada ao nome da co
linkToColumn=Link a coluna
unlink=Eliminar link
leaderboardName=Nome do painel de classificação
cancel=Cancelar
pleaseEnterAName=Insira um nome
pleaseEnterABoatClass=Insira uma classe de barcos
discardRacesFromHowManyStartedRacesOn=Descartar mais um corrida a partir de quantas corridas iniciadas
@@ -62,6 +65,7 @@ startingFromNumberOfRaces=A partir de quantas corridas
renameLeaderboard=Renomear painel de classificação
addColumnToLeaderboard=Adicionar coluna ao painel de classificação
pleaseEnterNameForNewRaceColumn=Insira um nome para a coluna da corrida nova
ok=OK
medalRace=Corrida para medalha
renameRace=Renomear corrida
openSelectedLeaderboard=Abrir painel de classificação selecionado
@@ -85,6 +89,7 @@ sapSailingAnalytics=Sailing Analytics
leaderboard=Painel de classificação
leaderboards=Painéis de classificação
leaderboardSettings=Configurações do painel de classificação
settings=Configurações
selectAtLeastOneLegDetail=Selecionar pelo menos um detalhe da perna
currentSpeedOverGroundInKnots=SOG
currentSpeedOverGroundInKnotsTooltip=A velocidade no fundo atual.
@@ -168,6 +173,7 @@ tacks=Cambadas
jibes=Jaibes
penaltyCircles=Voltas de punição
medalRaceIsNull=Valor de corrida para medalha não permitido
configuration=Configuração
maneuverTypes=Manobras
chooseChart=Selecionar diagrama
distanceTraveled=Distância navegada
@@ -185,11 +191,13 @@ secondsPerNauticalMileUnit=s/NM
metersUnit=m
millimetersUnit=mm
degreesUnit=°
close=Encerrar
compareCompetitors=Comparar competidores
description=Descrição
sailNumber=Número da vela
country=País
no3LetterCodes=Impossível encontrar os códigos de 3 letras do COI.
add=Adicionar
delete=Eliminar
showCharts=Visualizar diagramas
raceWithThisNameAlreadyExists=Já existe uma corrida com esse nome.
@@ -261,6 +269,7 @@ printHint=Imprime a versão aplicada
blockedApplyButton=Os competidores registrados são diferentes dos competidores da lista de pares!
multiplierInfo=Multiplica os voos e cria-os uns junto aos outros de modo que seja possível uma competição com menos mudanças de barco.
noPairingListAvailable=A função de impressão só está disponível caso já tenha sido aplicada uma lista de pares aos registros de corridas dos painéis de classificação selecionados.
settingsForComponent=Configurações para {0}
noEventsFound=Nenhum evento encontrado
noEventSelected=Nenhum evento selecionado
noLeaderboardsFound=Nenhum painel de classificação encontrado
@@ -298,6 +307,8 @@ leaderboardGroup=Grupo de painéis de classificação
pleaseEnterNonEmptyDescription=Insira uma descrição não vazia
groupWithThisNameAlreadyExists=Já existe um grupo de painéis de classificação com este nome.
detailsOfLeaderboardGroup=Detalhes do grupo de painéis de classificação
edit=Processar
save=Gravar
abort=Cancelar
noLeaderboardGroupWithNameFound=Não foi encontrado um grupo de painéis de classificação com o nome {0}
overview=Síntese
@@ -332,6 +343,7 @@ degreesShort=graus
untracked=Não rastreado
delayForLiveMode=Atraso para modo ao vivo:
notAvailable=Não disponível
details=Detalhes
noGroupSelected=Nenhum grupo selecionado
combinedWindSourceTypeName=Combinado
legMiddleWindSourceTypeName=Meio da perna
@@ -413,6 +425,7 @@ simulateAsLiveRace=Simular como corrida ao vivo
simulateWithOffset=Deslocamento antes da partida em minutos:
boatClassDoesNotMatchSelectedRegatta=As corridas selecionadas contêm classes de barcos que não são as mesmas da classe de barcos ''{0}'' da regata selecionada. Não será carregada nenhuma corrida.
regattaExistForSelectedBoatClass=Existe pelo menos uma regata para as classes de barcos selecionadas. Criar regatas padrão para essas corridas?
reload=Recarregar
addRegatta=Adicionar regata...
importRegattas=Importar regatas...
exchangeName=Trocar nome
@@ -634,6 +647,7 @@ totalNetPointsColumnTooltip=O total de pontos líquidos de um competidor na rega
windData=Dados do vento
gpsData=Dados do GPS
status=Status
noDataFound=Não foram encontrados dados
displayName=Nome de exibição
histogram=Histograma
numberOfDataPoints=Número de pontos de dados
@@ -881,9 +895,12 @@ legType=Tipo de perna
sailID=Número da vela
seriesLeaderboard=Painel de classificação da série
regattaLeaderboards=Painéis de classificação de regata
clearSelection=Anular seleção
running=Em competição
runAsSubstantive=Competir
done=Concluído
lastFinished=Último a concluir
run=Competir
times=vezes
dataAmount=Quantidade de dados
averageCleanedServerTime=∅ tempo de servidor anulado
@@ -907,8 +924,12 @@ selectSheet=Selecionar folha
cleanedServerTime=Tempo de servidor anulado
overallTime=Tempo geral
cleanedOverallTime=Tempo geral anulado
dataMiningResult=Resultado de data mining
groupBy=Agrupar por
statisticToCalculate=Calcular estatística
queryResultsChartSubtitle=Percorreu {0} entradas de dados em {1} segundos
noQuerySelected=Nenhuma consulta selecionada
runAutomatically=Executar automaticamente
windImport_Upload=Carregar
windImport_Title=Importar vento de Expedition
windImport_BoatId=ID do barco:
@@ -938,9 +959,14 @@ raceTimeTooltip=Tempo total navegado nesta corrida, começando a contagem quando
raceTimeDownwindTooltip=Tempo total navegado a sotavento nesta corrida
raceTimeReachingTooltip=Tempo total navegado a través nesta corrida
raceTimeUpwindTooltip=Tempo total navegado a barlavento nesta corrida
noStatisticSelectedError=Não foi selecionada uma estatística para calcular
noCustomGrouperScriptTextError=O script do sistema de agrupamento está vazio
noDimensionToGroupBySelectedError=Nenhuma dimensão pela qual efetuar o agrupamento selecionada
noGrouperSelectedError=Nenhum tipo de sistema de agrupamento selecionado
noDataRetrieverChainDefinitonSelectedError=Nenhum recuperador de dados selecionado
queryNotValidBecause=Nenhuma consulta possível, pois
dataMining=Data mining
errorRunningDataMiningQuery=Ocorreu um erro ao executar a consulta
hideToolbar=Ocultar barra de ferramentas
showSeriesLeaderboards=Visualizar painéis de classificação da série
showOverallLeaderboard=Visualizar painel de classificação geral
@@ -963,6 +989,7 @@ id=ID
allowReload=Permitir recarregamento
compress=Comprimir
compressTooltip=Utilizar somente se a instância do servidor de exportação estiver sendo executada pelo menos\ncom o commit 0fbf6071dea125bec4a56dee55d61c99def4a62e.
queryRunner=Executor de consulta
rerunQueryAfterRefresh=Executar consulta novamente após atualização
refreshIntervalMustntBeEmpty=O intervalo de atualização não deve estar em branco
selectionTables=Tabelas de seleção
@@ -1047,7 +1074,12 @@ TWATooltip=O ângulo entre a direção dos competidores e o vento
TWA=Ângulo do vento verdadeiro
showBoatClassChartsLabel=Você também pode ver o diagrama geral para as classes de barcos disponíveis.
showDiagram=Visualizar diagrama
runAutomaticallyTooltip=Execute a consulta automaticamente, após modificar, por exemplo, a estatística ou o agrupamento.
rerunQueryAfterRefreshTooltip=Executa novamente a consulta após a atualização das tabelas.
queryDefinitionProvider=Fornecedor da definição da consulta
statisticProvider=Fornecedor da estatística
calculateThe=Calcular
groupingProvider=Fornecedor do agrupamento
releaseNotes=Novidades e histórico de releases
hasSplitFleetContiguousScoring=Flotilhas divididas com pontuação contínua
addRaceLogTracker=Adicionar rastreador RaceLog
@@ -1205,6 +1237,7 @@ showAll=Visualizar tudo
raceVisibilityColumn=Visibilidade
enterCarryValueFor=Inserir pontos transferidos para competidor {0}
advanced=Avançado
basedOn=com base em
retrieveWith=Recuperar com
mappingDetails=Detalhes de mapeamento
deviceMappingQrCodeExplanation=Se você estiver utilizando o app de rastreamento, você também pode adicionar o mapeamento do dispositivo selecionando um competidor/marca, definindo as horas de partida e chegada e digitalizando depois este código QR.
@@ -1215,6 +1248,10 @@ enterImageURL=Inserir URL de imagem...
enterVideoURL=Inserir URL de vídeo...
enterSponsorImageURL=Inserir URL de imagem de patrocinador...
enterRaceName=Inserir nome da corrida...
serverError=Ocorreu um erro ao tentar contatar o servidor. Verifique sua conexão à rede e tente novamente.
remoteProcedureCall=Chamada de procedimento remoto
serverReplies=Respostas do servidor
errorCommunicatingWithServer=Erro ao comunicar com o servidor
userManagement=Administração de usuários
regattaStructureImport=Importação de estrutura da regata
filteredBy=filtrado por
@@ -1242,6 +1279,7 @@ noFleetsDefined=Nenhuma flotilha definida.
successfullyCreatedRegattas=Regatas criadas com êxito
errorTryingToRegisterRacesForTracking=Erro ao tentar registrar corridas {0} para rastreamento: {1}. Verificar sintaxe de URI ao vivo/armazenado.
errorDeterminingPolarAvailability=Erro ao determinar disponibilidade de dados de carta polar/VPP para corrida {0}: {1}
error=Erro
fileStorage=Armazenamento de arquivos
active=Ativo
scoringSchemeHighPointEssOverallDescription=Pontuação em pontos. O vencedor de uma etapa pontua 10 pontos, o 2º - 9 pontos, .... O desempate na pontuação geral da Extreme Sailing Series é efetuado a favor do competidor com o maior número de vitórias em etapas. Se isso não efetuar o desempate, será utilizado o resultado na última etapa.
@@ -1284,6 +1322,7 @@ showCompetitorFullNameColumn=Nome completo do competidor
alwaysShowCompetitorNationalityColumn=Exibir sempre a nacionalidade do competidor
alwaysShowCompetitorNationalityColumnTooltip=Exibir ambos, bandeiras de nacionalidade e imagens do competidor, se disponíveis
loadingDimensionValues=Carregando valores de dimensão
runningQuery=Executando consulta
inviteBuoyTenders=Convidar navios-balizadores
orMultipleEmails=ou vários e-mails separados por vírgula
courseOverGroundTrueDegreesTooltip=Percurso verdadeiro no fundo em graus
@@ -1291,6 +1330,11 @@ courseOverGroundTrueDegrees=COG
distanceIncludingGateStartInMeters=Distância (com início do portão)
distanceTraveledIncludingGateStartTooltip=A distância navegada desde o início até o fim da perna\nou até a data/hora atual, se a perna não estiver concluída.\nSe a perna incluir o início de um portão, a distância desde o fim da marcação até a posição inicial é incluída\npara ser possível comparar os competidores mesmo quando começam em horas diferentes.
raceDistanceTraveledIncludingGateStartTooltip=A distância navegada desde o início até o fim da corrida\nou até a data/hora atual, se a corrida não estiver concluída.\nPara o início de um portão, a distância desde o fim da marcação até a posição inicial é incluída\npara ser possível comparar os competidores mesmo quando começam em horas diferentes.
results=Resultados
groupName=Nome do grupo
valueAscending=Valor (crescente)
valueDescending=Valor (decrescente)
sortBy=Ordenar por
dashboardHeader=Painel
dashboardNoWindBotAvailableHeader=O Wind Bot não está disponível.
dashboardNoWindBotAvailableMessage=Para receber dados do vento em tempo real de unidades de medida do vento, certifique-se de que o Wind Bot está ativado e conectado ao SAP Sailing Analytics.
@@ -1326,12 +1370,16 @@ dashboardRCBoat=Barco de rádio-controle
fixedMarkPassing=(fixo)
suppressedMarkPassing=(suprimido)
windUp=Orientação pelo vento (visualizar vento no topo do mapa)
filterBy=Filtrar por
currentFilterSelection=Seleção de filtro atual
notCapableOfGeneratingACodeForIdentifier=Não é possível gerar um código para este identificador.
serverUrl=URL de servidor
rotatedFromTrueNorth=Efetuou a rotação de {0} graus desde o norte verdadeiro.
clickToToggleWindUp=Tocar/clicar para comutar entre exibição do mapa com orientação pelo vento e pelo norte
clickToToggleWindStreamlets=Tocar/clicar para visualizar ou ocultar os cursos do vento
startLineToFirstMarkTriangle=Partida para primeira marca ({0}m)
dataMiningComponentsHaveBeenUpdated=Os componentes de data mining foram atualizados
dataMiningComponentsNeedReloadDialogMessage=Clicar em Recarregar para recarregar os componentes agora. Isto irá descartar os dados exibidos atualmente e executar uma consulta padrão.\nClicar em Fechar para não efetuar nada. O data mining não irá funcionar corretamente até ser efetuado o recarregamento dos componentes.
noDataForEvent=Ainda não existem dados para o evento.
countriesCount={0,number} países
countriesCount[one]={0,number} país
@@ -1429,7 +1477,15 @@ noFinishedRaces=Ainda não existem corridas concluídas.
racesOverview=Síntese de corridas
listFormatLabel=Formato de lista
competitionFormatLabel=Formato da competição
empty=Vazio
runAQuery=Executar uma consulta
latestRegattaStandings=Posições da última regata
plainText=Texto simples
columnChart=Diagrama de colunas
columnChartWithErrorBars=Diagrama de colunas com barras de erros
choosePresentation=Selecionar apresentação
cantDisplayDataOfType=Não é possível exibir dados do tipo {0}
shownDecimals=Decimais exibidos
openFullscreenView=Abrir visão de tela inteira
closeFullscreenView=Fechar visão de tela inteira
videosCount={0,number} vídeos
@@ -1439,8 +1495,15 @@ photosCount[one]={0,number} foto
eventsHaveTakenPlace=Foram realizados {0} eventos
eventsHaveTakenPlace[one]=Foi realizado um evento
raceOffice=Secretaria do evento
analyze=Analisar
dataMiningSettings=Configurações de data mining
multiResultsPresenter=Apresentador de vários resultados
plainResultsPresenter=Apresentador de resultados simples
resultsChart=Diagrama de resultados
tabbedResultsPresenter=Apresentador de resultados por fichas
polarResultsPresenter=Apresentador de resultados da carta polar
maneuverSpeedDetailsResultsPresenter=Apresentador de resultados detalhados da velocidade da manobra
dataMiningRetrieval=Obtenção de dados
actionWatch=Ver
actionAnalyze=Analisar
denoteAllRacesForRaceLogTrackingShorctut=Atalho para denotar todas as corridas para rastreamento do registro de corridas
@@ -1456,8 +1519,24 @@ defaultName=Padrão
exampleTextForName=Seu nome é parecido com:
flightsCount={0,number} voos
flightsCount[one]={0,number} voo
viewQueryDefinition=Ver definição da consulta
queryDefinitionViewer=Visualizador de definição da consulta
groupAverageAscending=Média do grupo (crescente)
groupAverageDescending=Média do grupo (decrescente)
groupMedianAscending=Mediana do grupo (crescente)
groupMedianDescending=Mediana do grupo (decrescente)
resultsFoundForSearch={0,number} resultados encontrados para ''{1}''
resultsFoundForSearch[one]={0,number} resultado encontrado para ''{1}''
runPredefinedQuery=Executar consulta predefinida
selectPredefinedQuery=Selecionar consulta predefinida
predefinedQueryRunner=Executor de consulta predefinida
developerOptions=Opções do desenvolvedor
copyToClipboard=Copiar para o clipboard
code=Código
useClassGetName=Utilizar Class.getName() para nomes de tipo
useClassGetNameTooltip=Mais robusto em relação às modificações na base do código, mas o trecho do código só pode ser utilizado no âmbito em que as classes estão disponíveis.
useStringLiterals=Utilizar literais de cadeia para nomes de tipo
useStringLiteralsTooltip=O trecho do código pode ser utilizado em qualquer local, mas será quebrado se a base do código for modificada.
errorLoadingDataWithTryAgain=Erro ao carregar dados. Tentar novamente dentro de momentos.
addGalleryPhoto=Adicionar foto da galeria
addStageImage=Adicionar imagem da etapa
@@ -1477,6 +1556,7 @@ warningForDisabledCompetitors=Os competidores seguintes não podem ser registrad
competitorToolTipMessage={0} já foi atribuído à flotilha {2} na corrida {3} e por isso não pode ser atribuído à flotilha {1} na mesma corrida
addMarkToRegatta=Adicionar marca à regata
selectALeaderboardGroup=Selecionar um grupo de painéis de classificação...
pleaseSelect=Selecione
requiresValidRegatta=Esta página requer uma regata válida, a coluna da corrida e o nome da flotilha para identificar a corrida a ser exibida.
couldNotObtainRace=Não foi possível obter uma corrida com o nome {1} para a flotilha {2} para uma regata com o nome {0}: {3}
errorTryingToCreateEmbeddedMap=Erro ao tentar criar o mapa integrado: {0}
@@ -1756,9 +1836,30 @@ eventRegattaHeaderLegendGpsNo=Sem dados de rastreamento
eventRegattaHeaderLegendWindNo=Sem dados de vento
eventRegattaHeaderLegendVideoNo=Sem fluxos de vídeo
eventRegattaHeaderLegendAudioNo=Sem fluxos de áudio
angleInDegree=Ângulo em graus
angleInRadian=Ângulo em radianos
centralAngleInRadian=Ângulo central em radianos
centralAngleInDegree=Ângulo central em graus
kilometers=Quilômetros
meters=Metros
nauticalMiles=Milhas náuticas
seaMiles=Milhas marítimas
geographicalMiles=Milhas geográficas
days=Dias
hours=Horas
minutes=Minutos
seconds=Segundos
milliseconds=Milissegundos
floatNumber=Margem
integer=Número inteiro
appendResult=Anexar resultado
sampleColor=Amostra de cor
sharedSettingsLink=Link com configurações
leaderboardPage=Página do painel de classificação
makeDefault=Definir como padrão
makeDefaultInProgress=Em andamento...
settingsSavedMessage=Suas configurações atuais foram definidas com êxito como padrão
settingsSaveErrorMessage=Ocorreu um erro ao definir suas configurações como padrão
showLiveNow=Exibir "Ao vivo agora"
useOnlyOneOfStartTimeInferenceAndControlTrackingFromStartAndFinishTimes=Utilizar só um de "Inferência da hora de partida" e "Rastreamento de controle das horas de partida e chegada"
unknownLeaderboardType=Tipo de painel de classificação desconhecido {0}
@@ -1770,13 +1871,17 @@ raceRankShort=Posição na corrida
showRaceRankColumn=Exibir posição na corrida
estimatedDistance=Distância estimada
estimatedTime=Tempo estimado
nothingUpcoming=Atualmente não existem mais corridas planejadas
nothingUpcoming=Não existem mais corridas com início em breve
noUpcomingRaceDataAvailable=Sem dados da próxima corrida disponíveis
reallyRemoveSeries=Você quer realmente remover a série ''{0}''? Nota: todos os registros da corrida para a coluna da corrida anexada também serão removidos definitivamente!
settingsId=ID de configurações
documentSettingsId=ID de configuração do documento
settingsForId=Configurações para ID ''{0}''
userProfileSettingsTabDescription=As configurações dos usuários são geradas por diálogos de configurações que podem ser encontrados em vários locais da página. Esta visão exibe todas as suas configurações coletadas de uma forma técnica para usuários avançados. Tenha em atenção que as entradas removidas não podem ser restauradas, por isso utilize-as com cuidado.
resetToDefault=Reinicializar para padrão
resetToDefaultInProgress=Na reinicialização...
settingsRemoved=Configurações padrão restauradas
settingsRemovedError=Não foi possível restaurar configurações padrão
userSettingsFilter=Filtro de configurações
requiresRegattaRaceAndLeaderboard=Esta página necessita de um nome de regata, um nome de corrida e um nome de painel de classificação válidos.
couldNotFindRaceInRegatta=Não foi possível obter uma corrida com o nome {0} para uma regata com o nome {1}
@@ -1808,6 +1913,7 @@ errorFetchingDimensionData=Erro ao chamar os valores de dimensão de {0}: {1}
errorFetchingStatistics=Erro ao chamar as estatísticas disponíveis do servidor: {0}
errorFetchingAggregators=Erro ao chamar os agregadores disponíveis do servidor: {0}
errorLoadingDataRetrieverChainDefinitions=Erro ao recuperar as definições da cadeia do recuperador de dados disponíveis: {0}
errorFetchingComponentsChangedTimepoint=Erro ao chamar data/hora modificada de componentes do servidor: {0}
errorRunningQuery=Erro ao executar consulta: {0}
errorReadingWindFixes=Erro ao ler pontos fixos de vento {0}
errorAddingWindFixForRace=Erro ao adicionar um ponto fixo de vento para corrida {0}: {1}
@@ -1881,6 +1987,11 @@ minimumRideHeightInMetersTooltip=A altura mínima de flutuação em metros neces
minimumDurationBetweenAdjacentFoilingSegmentsInSeconds=Duração mínima entre segmentos adjacentes de navegação com hidrofólio (s)
minimumDurationBetweenAdjacentFoilingSegmentsInSecondsTooltip=Se não estiver em branco e o tempo entre dois segmentos adjacentes de navegação com hidrofólio for inferior a este, esses segmentos adjacentes de navegação com hidrofólio serão consolidados em um.
needToProvideValidMinimumRideHeight=Você precisa fornecer um valor válido da altura mínima de flutuação em metros.
dataMiningErrorMargins=Margens de erro
elements={0} elementos
chooseDifferentDimensionTitle=Selecionar dimensão diferente
chooseDifferentDimensionMessage=Selecionar uma dimensão diferente para os resultados do agrupamento
pleaseSelectADimension=Selecione uma dimensão
currentPortDaggerboardRake=Inclinação bolina bombordo
currentPortDaggerboardRakeTooltip=A inclinação atual da bolina para bombordo
currentStbdDaggerboardRake=Inclinação bolina boreste
@@ -9,10 +9,12 @@ trackedBefore=История отслеживаемых событий
general=Общее
listRaces=Список гонок
listRegattas=Список регат
numberPairResultsPresenter=Множество точек
wind=Ветер
maneuverType=Маневр
windPanelLabel=Это панель ветров, которая пока что совсем пуста.
refresh=Обновить
remove=Удалить
removeNumber=Удалить ({0})
windSource=Источник ветра
dampeningInterval=Интервал смягчения
@@ -51,6 +53,7 @@ trackedRaceConnectedToSelectedRaceName=Отслеживаемая гонка с
linkToColumn=Связать со столбцом
unlink=Отменить связывание
leaderboardName=Название таблицы лидеров
cancel=Отмена
pleaseEnterAName=Введите название
pleaseEnterABoatClass=Введите класс лодки
discardRacesFromHowManyStartedRacesOn=Исключить еще одну гонку, начиная с числа стартов в гонках
@@ -62,6 +65,7 @@ startingFromNumberOfRaces=Начиная с числа гонок
renameLeaderboard=Переименовать таблицу лидеров
addColumnToLeaderboard=Добавить столбец в таблицу лидеров
pleaseEnterNameForNewRaceColumn=Введите название для столбца новой гонки
ok=ОК
medalRace=Гонка на медали
renameRace=Переименовать гонку
openSelectedLeaderboard=Открыть выбранную таблицу лидеров
@@ -85,7 +89,7 @@ sapSailingAnalytics=Sailing Analytics
leaderboard=Таблица лидеров
leaderboards=Таблицы лидеров
leaderboardSettings=Параметры таблицы лидеров
settingsId=Ид. настроек
settings=Параметры
selectAtLeastOneLegDetail=Выберите подробности минимум одного отрезка
currentSpeedOverGroundInKnots=SOG
currentSpeedOverGroundInKnotsTooltip=Текущая скорость относительно грунта.
@@ -169,6 +173,7 @@ tacks=Поворотов оверштаг
jibes=Поворотов фордевинд
penaltyCircles=Штрафных кругов
medalRaceIsNull=Значение гонки на медали не разрешено
configuration=Конфигурация
maneuverTypes=Маневры
chooseChart=Выберите диаграмму
distanceTraveled=Пройденная дистанция
@@ -186,11 +191,13 @@ secondsPerNauticalMileUnit=с/NM
metersUnit=м
millimetersUnit=мм
degreesUnit=°
close=Закрыть
compareCompetitors=Сравнить участников
description=Описание
sailNumber=Номер на парусе
country=Страна
no3LetterCodes=Не удалось найти 3-буквенные коды IOC.
add=Добавить
delete=Удалить
showCharts=Показать диаграммы
raceWithThisNameAlreadyExists=Гонка с таким названием уже существует.
@@ -262,6 +269,7 @@ printHint=Печать примененной версии
blockedApplyButton=Число зарегистрированных участников не равно числу участников из списка пар!
multiplierInfo=Планируйте флайты таким образом, чтобы обеспечить соревнования с минимально возможной переменой лодок
noPairingListAvailable=Функция печати доступна только после применения списка пар к журналам гонок выбранных таблиц лидеров.
settingsForComponent={0} — параметры
noEventsFound=События не найдены
noEventSelected=Не выбрано событие
noLeaderboardsFound=Таблицы лидеров не найдены
@@ -299,6 +307,8 @@ leaderboardGroup=Группа таблиц лидеров
pleaseEnterNonEmptyDescription=Введите непустое описание
groupWithThisNameAlreadyExists=Группа таблиц лидеров с таким названием уже существует.
detailsOfLeaderboardGroup=Подробности группы таблиц лидеров
edit=Изменить
save=Сохранить
abort=Прервать
noLeaderboardGroupWithNameFound=Группа таблиц лидеров с названием {0} не найдена
overview=Обзор
@@ -333,6 +343,7 @@ degreesShort=град.
untracked=Не отслеживается
delayForLiveMode=Задержка для оперативного режима:
notAvailable=Недоступно
details=Подробности
noGroupSelected=Не выбрана группа
combinedWindSourceTypeName=Объединено
legMiddleWindSourceTypeName=Середина отрезка
@@ -414,6 +425,7 @@ simulateAsLiveRace=Симулировать как текущую гонку
simulateWithOffset=Сдвиг перед стартом в минутах:
boatClassDoesNotMatchSelectedRegatta=Выбранные гонки содержат классы лодок, не совпадающие с классом лодок ''{0}'' выбранной регаты. Гонки не будут загружены.
regattaExistForSelectedBoatClass=Для выбранных классов лодок имеется минимум одна регата. Создать регаты по умолчанию для соответствующих гонок?
reload=Перезагрузить
addRegatta=Добавить регату...
importRegattas=Импортировать регаты...
exchangeName=Имя Exchange
@@ -635,6 +647,7 @@ totalNetPointsColumnTooltip=Общая чистая сумма баллов уч
windData=Данные о ветре
gpsData=Данные GPS
status=Статус
noDataFound=Данные не найдены
displayName=Отображаемое имя
histogram=Гистограмма
numberOfDataPoints=Число точек данных
@@ -882,9 +895,12 @@ legType=Тип отрезка
sailID=Номер на парусе
seriesLeaderboard=Таблица лидеров серии
regattaLeaderboards=Таблицы лидеров регаты
clearSelection=Очистить выбор
running=Выполнение
runAsSubstantive=Выполнить
done=Готово
lastFinished=Последний финиш
run=Выполнить
times=раз
dataAmount=Объем данных
averageCleanedServerTime=∅ Очищенное время сервера
@@ -908,8 +924,12 @@ selectSheet=Выбрать лист
cleanedServerTime=Очищенное время сервера
overallTime=Общее время
cleanedOverallTime=Очищенное общее время
dataMiningResult=Результат добычи данных
groupBy=Группировать по
statisticToCalculate=Рассчитать статистику
queryResultsChartSubtitle=Обработано {0} зап. данных за {1} с
noQuerySelected=Не выбран запрос
runAutomatically=Выполнить автоматически
windImport_Upload=Отправить
windImport_Title=Импортировать ветер из Expedition
windImport_BoatId=Ид. лодки:
@@ -939,9 +959,14 @@ raceTimeTooltip=Общее время хода в данной гонке, от
raceTimeDownwindTooltip=Общее время хода по ветру в данной гонке
raceTimeReachingTooltip=Общее время хода полным ветром в данной гонке
raceTimeUpwindTooltip=Общее время хода против ветра в данной гонке
noStatisticSelectedError=Не выбрана статистика для расчета
noCustomGrouperScriptTextError=Скрипт группирования пуст
noDimensionToGroupBySelectedError=Не выбрано базовое измерение для группировки
noGrouperSelectedError=Не выбран тип группирования
noDataRetrieverChainDefinitonSelectedError=Не выбрано средство извлечения данных
queryNotValidBecause=Запрос невозможен, так как
dataMining=Добыча данных
errorRunningDataMiningQuery=При выполнении запроса возникла ошибка
hideToolbar=Скрыть панель инструментов
showSeriesLeaderboards=Показать таблицы лидеров серии
showOverallLeaderboard=Показать итоговую таблицу лидеров
@@ -964,6 +989,7 @@ id=Ид.
allowReload=Разрешить перезагрузку
compress=Сжать
compressTooltip=Используйте только при выполнении экспортирующего экземпляра\nсервера с commit 0fbf6071dea125bec4a56dee55d61c99def4a62e.
queryRunner=Выполнение запроса
rerunQueryAfterRefresh=Повторить запрос после обновления
refreshIntervalMustntBeEmpty=Интервал обновления не должен быть пустым
selectionTables=Таблица выбора
@@ -1048,7 +1074,12 @@ TWATooltip=Угол между направлением участников и
TWA=Угол истинного ветра
showBoatClassChartsLabel=Также можно просмотреть общую диаграмму для доступных классов лодок.
showDiagram=Показать диаграмму
runAutomaticallyTooltip=Автоматически выполнять запрос после изменения, например, статистики или группирования.
rerunQueryAfterRefreshTooltip=Повторно выполняет запрос после обновления таблиц.
queryDefinitionProvider=Поставщик определения запроса
statisticProvider=Поставщик статистики
calculateThe=Рассчитать
groupingProvider=Поставщик группирования
releaseNotes=Новости и история выпусков
hasSplitFleetContiguousScoring=Разделенные флоты получили сходные оценки
addRaceLogTracker=Добавить средство отслеживания журнала гонки
@@ -1206,6 +1237,7 @@ showAll=Показать все
raceVisibilityColumn=Видимость
enterCarryValueFor=Введите перенесенные баллы для участника {0}
advanced=Дополнительно
basedOn=на базе
retrieveWith=Получить с помощью
mappingDetails=Подробности сопоставления
deviceMappingQrCodeExplanation=Если используется приложение отслеживания, можно добавить также сопоставление устройства, выбрав участника/отметку, установив интервал времени, а затем отсканировав этот QR-код.
@@ -1216,6 +1248,10 @@ enterImageURL=Ввести URL-адрес изображения...
enterVideoURL=Ввести URL-адрес видео...
enterSponsorImageURL=Ввести URL-адрес изображения спонсора...
enterRaceName=Ввести название гонки...
serverError=При попытке обратиться к серверу возникла ошибка. Проверьте подключение к сети и повторите попытку.
remoteProcedureCall=Удаленный вызов процедуры
serverReplies=Ответы сервера
errorCommunicatingWithServer=Ошибка связи с сервером
userManagement=Управление пользователями
regattaStructureImport=Импорт структуры регаты
filteredBy=отфильтровано по
@@ -1243,6 +1279,7 @@ noFleetsDefined=Не определены флоты.
successfullyCreatedRegattas=Регаты успешно созданы
errorTryingToRegisterRacesForTracking=Ошибка при попытке зарегистрировать гонки {0} для отслеживания: {1}. проверьте синтаксис URI оперативных/хранимых данных.
errorDeterminingPolarAvailability=Ошибка при определении доступности полярных/VPP данных для гонки {0}: {1}
error=Ошибка
fileStorage=Хранилище файлов
active=Активно
scoringSchemeHighPointEssOverallDescription=Оценка в баллах. Победитель в акте получает 10 баллов, 2-й — 9 баллов, .... Любое равенство в общей оценке Extreme Sailing Series разрешается в пользу участника с наибольшим числом побед в актах. В случае равенства числа побед для разрешения используется последний акт.
@@ -1285,6 +1322,7 @@ showCompetitorFullNameColumn=Полное имя участника
alwaysShowCompetitorNationalityColumn=Всегда показывать государственную принадлежность участника
alwaysShowCompetitorNationalityColumnTooltip=Показывать и флаги государств, и изображения участников (при наличии)
loadingDimensionValues=Загрузка значений измерения
runningQuery=Выполнение запроса
inviteBuoyTenders=Пригласить лоцманов
orMultipleEmails=или несколько адресов эл. почты через запятую
courseOverGroundTrueDegreesTooltip=Истинный курс относительно грунта в градусах
@@ -1292,6 +1330,11 @@ courseOverGroundTrueDegrees=COG
distanceIncludingGateStartInMeters=Дистанция (при старте через ворота)
distanceTraveledIncludingGateStartTooltip=Дистанция, пройденная от начала отрезка до конца\nили до текущего момента времени, если отрезок не завершен.\nЕсли отрезок включает старт через ворота, дистанция от отметки до стартовой позиции включается,\nчтобы обеспечить сравнение участников даже при старте в разное время.
raceDistanceTraveledIncludingGateStartTooltip=Дистанция, пройденная от начала гонки до конца\nили до текущего момента времени, если гонка не завершена.\nДля старта через ворота включается дистанция от привязки до стартовой позиции,\nчтобы обеспечить сравнение участников даже при старте в разное время.
results=Результаты
groupName=Название группы
valueAscending=Значение (по возрастанию)
valueDescending=Значение (по убыванию)
sortBy=Сортировать по
dashboardHeader=Панель
dashboardNoWindBotAvailableHeader=WindBot недоступен.
dashboardNoWindBotAvailableMessage=Чтобы получать оперативные данные от устройств измерения ветра, убедитесь, что WindBot включен и подключен к SAP Sailing Analytics.
@@ -1327,12 +1370,16 @@ dashboardRCBoat=Лодка ГК
fixedMarkPassing=(фиксировано)
suppressedMarkPassing=(подавляется)
windUp=На ветер (показать ветер сверху карты)
filterBy=Фильтровать по
currentFilterSelection=Текущий выбор фильтра
notCapableOfGeneratingACodeForIdentifier=Я не могу сгенерировать код для этого идентификатора.
serverUrl=URL-адрес сервера
rotatedFromTrueNorth=Повернуто на {0} град. от истинного севера.
clickToToggleWindUp=Коснитесь/щелкните для переключения между отображением карты с ветром или севером вверху
clickToToggleWindStreamlets=Коснитесь/щелкните для отображения или скрытия потоков ветра
startLineToFirstMarkTriangle=От старта до первой отметки ({0} м)
dataMiningComponentsHaveBeenUpdated=Компоненты добычи данных обновлены.
dataMiningComponentsNeedReloadDialogMessage=Щелкните ''Перезагрузить'', чтобы перезагрузить компоненты сейчас. Текущее отображение данных будет сброшено с выполнением запроса по умолчанию. Добыча данных не будет работать правильно до перезагрузки компонентов.
noDataForEvent=Данных для данного события еще нет.
countriesCount={0,number} стран
countriesCount[one]={0,number} страна
@@ -1430,7 +1477,15 @@ noFinishedRaces=Завершенных гонок еще нет
racesOverview=Обзор гонок
listFormatLabel=Формат списка
competitionFormatLabel=Формат соревнования
empty=Пусто
runAQuery=Выполнить запрос
latestRegattaStandings=Позиции в последней регате
plainText=Простой текст
columnChart=Столбчатая диаграмма
columnChartWithErrorBars=Столбчатая диаграмма с планками погрешностей
choosePresentation=Выберите представление
cantDisplayDataOfType=Невозможно отобразить данные типа {0}
shownDecimals=Отображаемые десятичные разряды
openFullscreenView=Открыть полноэкранный режим
closeFullscreenView=Закрыть полноэкранный режим
videosCount={0,number} видео
@@ -1440,8 +1495,15 @@ photosCount[one]={0,number} фото
eventsHaveTakenPlace=Имело место {0} событий
eventsHaveTakenPlace[one]=Имело место одно событие
raceOffice=Служба гонки
analyze=Анализировать
dataMiningSettings=Параметры добычи данных
multiResultsPresenter=Презентатор множества результатов
plainResultsPresenter=Презентатор простых результатов
resultsChart=Диаграмма результатов
tabbedResultsPresenter=Презентатор результатов со вкладками
polarResultsPresenter=Полярный презентатор результатов
maneuverSpeedDetailsResultsPresenter=Демонстратор результатов детализации скорости маневра
dataMiningRetrieval=Извлечение данных
actionWatch=Смотреть
actionAnalyze=Анализировать
denoteAllRacesForRaceLogTrackingShorctut=Ярлык для отмены отслеживания журналов всех гонок
@@ -1457,8 +1519,24 @@ defaultName=По умолчанию
exampleTextForName=Выше имя выглядит так:
flightsCount={0,number} полетов
flightsCount[one]={0,number} полет
viewQueryDefinition=Просмотреть определение запроса
queryDefinitionViewer=Средство просмотра определения запроса
groupAverageAscending=Среднее группы (по возрастанию)
groupAverageDescending=Среднее группы (по убыванию)
groupMedianAscending=Медиана группы (по возрастанию)
groupMedianDescending=Медиана группы (по убыванию)
resultsFoundForSearch=Найдено {0,number} результатов для ''{1}''
resultsFoundForSearch[one]=Найден {0,number} результат для ''{1}''
runPredefinedQuery=Выполнить готовый запрос
selectPredefinedQuery=Выбрать готовый запрос
predefinedQueryRunner=Средство выполнения готовых запросов
developerOptions=Параметры разработчика
copyToClipboard=Копировать в буфер обмена
code=Код
useClassGetName=Использовать Class.getName() для имен типов
useClassGetNameTooltip=Более надежно по сравнению с изменениями в основании кода, но фрагмент кода может быть использован только в области с доступными классами.
useStringLiterals=Использовать строковые литералы для имен типов
useStringLiteralsTooltip=Фрагмент кода может использоваться где угодно, но будет нарушен в случае изменения основания кода.
errorLoadingDataWithTryAgain=Ошибка при загрузке данных. Повтор попытки через несколько секунд.
addGalleryPhoto=Добавить фото галереи
addStageImage=Добавить изображение этапа
@@ -1478,6 +1556,7 @@ warningForDisabledCompetitors=Регистрация следующих учас
competitorToolTipMessage={0} уже присвоен флоту {2} в гонке {3} и поэтому не может быть присвоен флоту {1} в той же самой гонке
addMarkToRegatta=Добавить отметку к регате
selectALeaderboardGroup=Выбрать группу таблиц лидеров...
pleaseSelect=Выберите
requiresValidRegatta=Эта страница определяет гонку для отображения по допустимым значениям регаты, столбца гонки и названия флота.
couldNotObtainRace=Не удалось получить гонку с названием {1} для флота {2} для регаты с названием {0}: {3}
errorTryingToCreateEmbeddedMap=Ошибка при попытке создать внедренную карту: {0}
@@ -1757,9 +1836,30 @@ eventRegattaHeaderLegendGpsNo=Нет данных отслеживания
eventRegattaHeaderLegendWindNo=Нет данных о ветре
eventRegattaHeaderLegendVideoNo=Нет видеопотоков
eventRegattaHeaderLegendAudioNo=Нет аудиопотоков
angleInDegree=Угол в градусах
angleInRadian=Угол в радианах
centralAngleInRadian=Центральный угол в градусах
centralAngleInDegree=Центральный угол в радианах
kilometers=Километры
meters=Метры
nauticalMiles=Морские мили
seaMiles=Морские мили
geographicalMiles=Географические мили
days=Дни
hours=Часы
minutes=Минуты
seconds=Секунды
milliseconds=Миллисекунды
floatNumber=Плавающее
integer=Целое
appendResult=Добавить результат
sampleColor=Образец цвета
sharedSettingsLink=Связать с настройками
leaderboardPage=Страница таблицы лидеров
makeDefault=Использовать по умолчанию
makeDefaultInProgress=Выполняется...
settingsSavedMessage=Текущие настройки успешно заданы для использования по умолчанию
settingsSaveErrorMessage=При задании настроек для использования по умолчанию возникла ошибка
showLiveNow=Показать "Оперативные данные"
useOnlyOneOfStartTimeInferenceAndControlTrackingFromStartAndFinishTimes=Использовать только один из параметров "Вывод о времени старта" и "Контролировать отслеживание от времени старта и финиша"
unknownLeaderboardType=Неизвестный тип таблицы лидеров {0}
@@ -1771,12 +1871,17 @@ raceRankShort=Ранг гонки
showRaceRankColumn=Показать ранг гонки
estimatedDistance=Оценка расстояния
estimatedTime=Оценка времени
nothingUpcoming=Дальнейших запланированных гонок сейчас нет
nothingUpcoming=Нет других гонок, стартующих скоро
noUpcomingRaceDataAvailable=Данные предстоящей гонки недоступны
reallyRemoveSeries=Действительно удалить серии ''{0}''? Примечание: все журналы для вложенных столбцов гонки также будут окончательно удалены!
settingsId=Ид. настроек
documentSettingsId=Ид. настроек документа
settingsForId=Настройки для ид. ''{0}''
userProfileSettingsTabDescription=Пользовательские настройки генерируются диалогами настроек, расположенными во многих местах страницы. Здесь отображено техническое представление всех собранных настроек для ключевых пользователей. Соблюдайте осторожность, так как восстановить удаленные записи невозможно.
resetToDefault=Восстановить настройки по умолчанию
resetToDefaultInProgress=Выполняется сброс...
settingsRemoved=Восстановлены настройки по умолчанию
settingsRemovedError=Не удалось восстановить настройки по умолчанию
userSettingsFilter=Фильтр настроек
requiresRegattaRaceAndLeaderboard=Для этой страницы требуются действительные названия регаты, гонки и таблицы лидеров.
couldNotFindRaceInRegatta=Не удалось получить гонку с названием {0} для регаты с названием {1}
@@ -1808,6 +1913,7 @@ errorFetchingDimensionData=Ошибка при вызове значений и
errorFetchingStatistics=Ошибка при вызове доступной статистики с сервера: {0}
errorFetchingAggregators=Ошибка при вызове доступных агрегаторов с сервера: {0}
errorLoadingDataRetrieverChainDefinitions=Ошибка при вызове доступных определений цепочек извлечения данных: {0}
errorFetchingComponentsChangedTimepoint=Ошибка при вызове отметки времени изменения компонентов с сервера: {0}
errorRunningQuery=Ошибка при выполнении запроса: {0}
errorReadingWindFixes=Ошибка при считывании замеров ветра {0}
errorAddingWindFixForRace=Ошибка при добавлении замера ветра для гонки {0}: {1}
@@ -1881,6 +1987,11 @@ minimumRideHeightInMetersTooltip=Минимальная высота просв
minimumDurationBetweenAdjacentFoilingSegmentsInSeconds=Минимальная продолжительность между двумя сегментами в крыльевом режиме (сек)
minimumDurationBetweenAdjacentFoilingSegmentsInSecondsTooltip=Если поле не является пустым, и время между двумя смежными сегментами в крыльевом режиме не превышает указанное значение, смежные сегменты в крыльевом режиме считаются одним сегментом.
needToProvideValidMinimumRideHeight=Укажите действительное значение минимальной высоты просвета в метрах.
dataMiningErrorMargins=Пределы погрешности
elements={0} элем.
chooseDifferentDimensionTitle=Выберите другое измерение
chooseDifferentDimensionMessage=Выберите другое измерение для группирования результатов
pleaseSelectADimension=Выберите измерение
currentPortDaggerboardRake=Скос киля на левый борт
currentPortDaggerboardRakeTooltip=Текущий скос выдвижного киля на левый борт
currentStbdDaggerboardRake=Скос киля на правый борт
@@ -9,10 +9,12 @@ trackedBefore=已跟踪活动的历史记录
general=常规
listRaces=比赛轮次清单
listRegattas=比赛清单
numberPairResultsPresenter=散点图
wind=风力
maneuverType=操作
windPanelLabel=这是风力面板,目前完全空白。
refresh=刷新
remove=移除
removeNumber=移除 ({0})
windSource=风源
dampeningInterval=阻尼间隔
@@ -51,6 +53,7 @@ trackedRaceConnectedToSelectedRaceName=跟踪的比赛轮次已连接到所选
linkToColumn=链接到列
unlink=取消链接
leaderboardName=积分榜名称
cancel=取消
pleaseEnterAName=请输入名称
pleaseEnterABoatClass=请输入船只级别
discardRacesFromHowManyStartedRacesOn=从已开始的比赛轮次数开始再放弃一个比赛轮次
@@ -62,6 +65,7 @@ startingFromNumberOfRaces=从比赛轮次数开始
renameLeaderboard=重命名积分榜
addColumnToLeaderboard=向积分榜添加列
pleaseEnterNameForNewRaceColumn=请输入新比赛轮次列的名称
ok=确定
medalRace=奖牌轮
renameRace=重命名比赛轮次
openSelectedLeaderboard=打开选择的积分榜
@@ -85,6 +89,7 @@ sapSailingAnalytics=Sailing Analytics
leaderboard=积分榜
leaderboards=积分榜
leaderboardSettings=积分榜设置
settings=设置
selectAtLeastOneLegDetail=至少选择一个航段详情
currentSpeedOverGroundInKnots=SOG
currentSpeedOverGroundInKnotsTooltip=当前实际速度。
@@ -168,6 +173,7 @@ tacks=迎风转向
jibes=顺风转向
penaltyCircles=惩罚转圈
medalRaceIsNull=不允许奖牌轮值
configuration=配置
maneuverTypes=操作
chooseChart=选择记录
distanceTraveled=航行距离
@@ -185,11 +191,13 @@ secondsPerNauticalMileUnit=s/NM
metersUnit=m
millimetersUnit=mm
degreesUnit=°
close=关闭
compareCompetitors=比较参赛队
description=描述
sailNumber=帆号
country=国家/地区
no3LetterCodes=无法找到 IOC 3 个字母的代码。
add=添加
delete=删除
showCharts=显示记录
raceWithThisNameAlreadyExists=具有此名称的比赛轮次已存在。
@@ -261,6 +269,7 @@ printHint=打印应用的版本
blockedApplyButton=注册的参赛队不等于配对清单中的参赛队!
multiplierInfo=多个航程,彼此相邻,这样就可以减少船只更换情况进行比赛
noPairingListAvailable=打印功能仅在配对清单可应用于选择的积分榜比赛轮次日志时可用。
settingsForComponent={0}设置
noEventsFound=未找到活动
noEventSelected=未选择活动
noLeaderboardsFound=未找到积分榜
@@ -298,6 +307,8 @@ leaderboardGroup=积分榜组
pleaseEnterNonEmptyDescription=请输入非空描述
groupWithThisNameAlreadyExists=具有此名称的积分榜组已存在。
detailsOfLeaderboardGroup=积分榜组详情
edit=编辑
save=保存
abort=中止
noLeaderboardGroupWithNameFound=未找到名称为{0}的积分榜组
overview=总览
@@ -332,6 +343,7 @@ degreesShort=deg
untracked=取消跟踪
delayForLiveMode=实况模式延迟:
notAvailable=不可用
details=详情
noGroupSelected=未选择分组
combinedWindSourceTypeName=组合
legMiddleWindSourceTypeName=航段中部
@@ -413,6 +425,7 @@ simulateAsLiveRace=模拟实况比赛轮次
simulateWithOffset=起航前的偏移(分钟):
boatClassDoesNotMatchSelectedRegatta=所选的比赛轮次包含不同于所选比赛船只级别 "{0}" 的船只级别。将不加载比赛轮次。
regattaExistForSelectedBoatClass=所选船只级别至少有一场比赛。是否确定为这些比赛轮次创建默认比赛?
reload=重新加载
addRegatta=添加比赛...
importRegattas=导入比赛...
exchangeName=交换机名称
@@ -634,6 +647,7 @@ totalNetPointsColumnTooltip=参赛队在比赛中的总净分。\n按名次(
windData=风力数据
gpsData=GPS 数据
status=状态
noDataFound=未找到数据
displayName=显示名称
histogram=直方图
numberOfDataPoints=数据点数
@@ -881,9 +895,12 @@ legType=航段形式
sailID=帆号
seriesLeaderboard=系列积分榜
regattaLeaderboards=比赛积分榜
clearSelection=清除选择
running=运行
runAsSubstantive=运行
done=完成
lastFinished=最后完成
run=运行
times=次数
dataAmount=数据量
averageCleanedServerTime=∅ 清理服务器时间
@@ -907,8 +924,12 @@ selectSheet=选择工作表
cleanedServerTime=清理服务器时间
overallTime=总时间
cleanedOverallTime=清理总时间
dataMiningResult=数据挖掘结果
groupBy=分组方式
statisticToCalculate=计算统计
queryResultsChartSubtitle={1}秒内处理{0}个数据条目
noQuerySelected=没有查询选择
runAutomatically=自动运行
windImport_Upload=上传
windImport_Title=从导航图导入风力
windImport_BoatId=船只编号:
@@ -938,9 +959,14 @@ raceTimeTooltip=参赛队在本比赛轮次中越过开始航路点\n(不是
raceTimeDownwindTooltip=本轮次比赛顺风航行的总时间
raceTimeReachingTooltip=本轮次比赛横风航行的总时间
raceTimeUpwindTooltip=本轮次比赛迎风航行的总时间
noStatisticSelectedError=未选择待计算的统计
noCustomGrouperScriptTextError=群集器脚本为空
noDimensionToGroupBySelectedError=未选择分组方式尺寸
noGrouperSelectedError=未选择群集器类型
noDataRetrieverChainDefinitonSelectedError=未选择数据检索器
queryNotValidBecause=无法查询,原因:
dataMining=数据挖掘
errorRunningDataMiningQuery=运行查询期间出错
hideToolbar=隐藏工具栏
showSeriesLeaderboards=显示系列积分榜
showOverallLeaderboard=显示总积分榜
@@ -963,6 +989,7 @@ id=编号
allowReload=允许重新加载
compress=压缩
compressTooltip=仅在导出服务器实例至少通过\n任务 0fbf6071dea125bec4a56dee55d61c99def4a62e 运行时使用。
queryRunner=查询执行器
rerunQueryAfterRefresh=在刷新后重新运行查询
refreshIntervalMustntBeEmpty=刷新间隔不得为空
selectionTables=选择表
@@ -1047,7 +1074,12 @@ TWATooltip=赛队航行的方向和风的夹角
TWA=实际风向角
showBoatClassChartsLabel=还可以查看可用船只级别的总直直方图。
showDiagram=显示直方图
runAutomaticallyTooltip=在更改统计或分组后,自动运行查询。
rerunQueryAfterRefreshTooltip=在刷新表后,重新运行查询。
queryDefinitionProvider=查询定义提供方
statisticProvider=统计提供方
calculateThe=计算
groupingProvider=分组提供方
releaseNotes=消息和版本历史
hasSplitFleetContiguousScoring=区分连续得分的船队
addRaceLogTracker=添加比赛轮次日志跟踪器
@@ -1205,6 +1237,7 @@ showAll=显示全部
raceVisibilityColumn=可见性
enterCarryValueFor=输入参赛队{0}的得分
advanced=高级
basedOn=基于
retrieveWith=检索依据
mappingDetails=映射详情
deviceMappingQrCodeExplanation=如果使用跟踪应用,可以通过选择参赛队/标志、设置开始和结束时间,然后扫描此二维码添加设备映射。
@@ -1215,6 +1248,10 @@ enterImageURL=输入图像 URL...
enterVideoURL=输入视频 URL...
enterSponsorImageURL=输入赞助商图像 URL...
enterRaceName=输入比赛轮次名称...
serverError=尝试联系服务器时出错。请检查网络连接,并重试。
remoteProcedureCall=远程过程调用
serverReplies=服务器应答
errorCommunicatingWithServer=与服务器通信时发生错误
userManagement=用户管理
regattaStructureImport=比赛结构导入
filteredBy=筛选方式
@@ -1242,6 +1279,7 @@ noFleetsDefined=未定义船队。
successfullyCreatedRegattas=已成功创建比赛
errorTryingToRegisterRacesForTracking=尝试注册比赛轮次{0}用于跟踪出错: {1}。检查实况/存储的 URI 语法。
errorDeterminingPolarAvailability=确定比赛轮次{0}的极坐标/VPP 数据的可用性出错: {1}
error=错误
fileStorage=文件存储
active=已激活
scoringSchemeHighPointEssOverallDescription=得分。 分站赛获胜者得 10 分、第 2 名 9 分、.... 在总体极限帆船系列赛中如有平局,以获得最多分站赛名次的参赛队取得胜利。 如果仍有平局,就以最后一个分站赛的名次打破平局。
@@ -1284,6 +1322,7 @@ showCompetitorFullNameColumn=参赛队全名
alwaysShowCompetitorNationalityColumn=始终显示参赛队国籍
alwaysShowCompetitorNationalityColumnTooltip=如果可用,显示两者:国籍旗帜和参赛队图像
loadingDimensionValues=正在加载尺寸值
runningQuery=运行查询
inviteBuoyTenders=邀请浮标供应船
orMultipleEmails=或使用逗号隔开的多个电子邮件
courseOverGroundTrueDegreesTooltip=实在对地航向角度
@@ -1291,6 +1330,11 @@ courseOverGroundTrueDegrees=对地航向
distanceIncludingGateStartInMeters=距离(起航门标)
distanceTraveledIncludingGateStartTooltip=如果航段没有结束,从航段起点到终点\n或当前时间点航行的距离。\n如果航段包括起航门标,则包括尾销到起航位置的距离,\n这样,即便在不同时间起航,也可以比较参赛队。
raceDistanceTraveledIncludingGateStartTooltip=如果比赛轮次没有结束,从比赛轮次开始到结束\n或当前时间点航行的距离。对于起航门标,包括尾销到起航位置的距离,\n这样,即便在不同时间起航,也可以比较参赛队。
results=结果
groupName=分组名称
valueAscending=值(递增)
valueDescending=值(递减)
sortBy=排序方式
dashboardHeader=仪表盘
dashboardNoWindBotAvailableHeader=风力机器人程序不可用。
dashboardNoWindBotAvailableMessage=要从风力测量装置接收实况风力数据,请确保开启风力机器人程序,并与 SAP Sailing Analytics 相连。
@@ -1326,12 +1370,16 @@ dashboardRCBoat=RC 船只
fixedMarkPassing=(固定)
suppressedMarkPassing=(禁止)
windUp=风向向上(从地图的顶部显示风力)
filterBy=筛选方式
currentFilterSelection=当前筛选器选择
notCapableOfGeneratingACodeForIdentifier=无法为此标识符生成代码。
serverUrl=服务器 URL
rotatedFromTrueNorth=自真北方向旋转{0}度。
clickToToggleWindUp=点按/点击在风向向上和北向上地图显示之间切换
clickToToggleWindStreamlets=点按/点击显示或隐藏风流
startLineToFirstMarkTriangle=开始经过第一个标志 ({0}m)
dataMiningComponentsHaveBeenUpdated=数据挖掘组件已更新
dataMiningComponentsNeedReloadDialogMessage=点击“重新加载”,立即重新加载组件。这将放弃当前显示的数据,并运行默认查询。\n点击“关闭”不执行任何操作。在重新加载组件前,数据挖掘不能正常工作。
noDataForEvent=活动暂无任何数据。
countriesCount={0,number} 个国家/地区
countriesCount[one]={0,number} 个国家/地区
@@ -1429,7 +1477,15 @@ noFinishedRaces=没有结束的比赛轮次
racesOverview=比赛轮次总览
listFormatLabel=清单格式
competitionFormatLabel=赛制
empty=空
runAQuery=运行查询
latestRegattaStandings=最新比赛排名
plainText=纯文本
columnChart=柱状图
columnChartWithErrorBars=含误差线的柱状图
choosePresentation=选择介绍
cantDisplayDataOfType=无法显示类型为{0}的数据
shownDecimals=显示小数
openFullscreenView=打开全屏视图
closeFullscreenView=关闭全屏视图
videosCount={0,number} 个视频
@@ -1439,8 +1495,15 @@ photosCount[one]={0,number} 张照片
eventsHaveTakenPlace={0}个活动已举行
eventsHaveTakenPlace[one]=已举行一场活动
raceOffice=竞赛办公室
analyze=分析
dataMiningSettings=数据挖掘设置
multiResultsPresenter=多结果展示区
plainResultsPresenter=纯结果展示区
resultsChart=结果记录
tabbedResultsPresenter=选项卡式结果展示区
polarResultsPresenter=极坐标结果展示区
maneuverSpeedDetailsResultsPresenter=操作速度详细结果展示区
dataMiningRetrieval=数据检索
actionWatch=观看
actionAnalyze=分析
denoteAllRacesForRaceLogTrackingShorctut=为比赛轮次日志跟踪描述所有比赛轮次的快捷方式
@@ -1456,8 +1519,24 @@ defaultName=默认值
exampleTextForName=名称如下所示:
flightsCount={0,number} 个航程
flightsCount[one]={0,number} 个航程
viewQueryDefinition=查看查询定义
queryDefinitionViewer=查询定义查看器
groupAverageAscending=分组平均值(递增)
groupAverageDescending=分组平均值(递减)
groupMedianAscending=分组中值(递增)
groupMedianDescending=分组中值(递减)
resultsFoundForSearch=找到 "{1}" 的 {0,number} 个结果
resultsFoundForSearch[one]=找到 "{1}" 的 {0,number} 个结果
runPredefinedQuery=运行预定义的查询
selectPredefinedQuery=选择预定义的查询
predefinedQueryRunner=预定义的查询执行器
developerOptions=开发人员选项
copyToClipboard=复制到剪贴板
code=代码
useClassGetName=将 Class.getName() 用于类型名称
useClassGetNameTooltip=更灵活应对代码库的更改,但是代码片段只能在级别可用的范围内使用。
useStringLiterals=将字符串文本用于类型名称
useStringLiteralsTooltip=代码片段可在任意位置使用,当如果基本代码更改,其将中断。
errorLoadingDataWithTryAgain=加载数据出错。请稍后重试。
addGalleryPhoto=添加图库照片
addStageImage=添加阶段图像
@@ -1477,6 +1556,7 @@ warningForDisabledCompetitors=以下参赛队无法注册此比赛轮次:{0}
competitorToolTipMessage={0}已分配到比赛轮次{3}中的船队{2},因此,无法分配到同一比赛轮次中的船队{1}
addMarkToRegatta=向比赛添加标志
selectALeaderboardGroup=选择积分榜组...
pleaseSelect=请选择
requiresValidRegatta=此页面需要有效的比赛、比赛轮次列和船队名称,才能识别显示的比赛轮次。
couldNotObtainRace=无法为名称为{0}的比赛获取船队{2}名称为{1}的比赛轮次: {3}
errorTryingToCreateEmbeddedMap=尝试创建嵌入式地图出错: {0}
@@ -1756,9 +1836,30 @@ eventRegattaHeaderLegendGpsNo=无跟踪数据
eventRegattaHeaderLegendWindNo=无风力数据
eventRegattaHeaderLegendVideoNo=无视频流
eventRegattaHeaderLegendAudioNo=无音频流
angleInDegree=角度(度)
angleInRadian=角度(弧度)
centralAngleInRadian=圆心角(弧度)
centralAngleInDegree=圆心角(度)
kilometers=千米
meters=米
nauticalMiles=海里
seaMiles=海里
geographicalMiles=地理英里
days=天
hours=小时
minutes=分钟
seconds=秒
milliseconds=毫秒
floatNumber=浮点数
integer=整数
appendResult=附加结果
sampleColor=颜色样本
sharedSettingsLink=链接与设置
leaderboardPage=积分榜页面
makeDefault=设为默认值
makeDefaultInProgress=正在进行...
settingsSavedMessage=当前设置已成功设为默认设置
settingsSaveErrorMessage=将设置设为默认设置时发生错误
showLiveNow=显示“现在直播”
useOnlyOneOfStartTimeInferenceAndControlTrackingFromStartAndFinishTimes=仅使用“开始时间推断”和“从开始和结束时间控制跟踪”中的其中一个
unknownLeaderboardType=积分榜类型{0}未知
@@ -1770,13 +1871,17 @@ raceRankShort=比赛轮次名次
showRaceRankColumn=显示比赛轮次名次
estimatedDistance=预计距离
estimatedTime=预计时间
nothingUpcoming=目前还没有进一步的计划比赛轮次
nothingUpcoming=没有即将开始的其他比赛轮次
noUpcomingRaceDataAvailable=没有可用的即将进行的比赛轮次数据
reallyRemoveSeries=是否确定移除系列赛 "{0}"?注意:随附比赛轮次列的所有比赛轮次日志也将永久移除!
settingsId=设置编号
documentSettingsId=文档设置编号
settingsForId=编号 ''''{0}'''' 的设置
userProfileSettingsTabDescription=用户设置由可在页面多个位置找到的设置对话生成。此视图以技术方式为高级用户显示收集的所有设置。请注意,移除的条目无法恢复,请谨慎使用。
resetToDefault=重置为默认值
resetToDefaultInProgress=正在重置...
settingsRemoved=默认设置已恢复
settingsRemovedError=无法恢复默认设置
userSettingsFilter=设置筛选器
requiresRegattaRaceAndLeaderboard=此页面需要有效的比赛名称、比赛轮次名称和积分榜名称。
couldNotFindRaceInRegatta=无法为名称为{1}的比赛获取名称为{0}的比赛轮次
@@ -1808,6 +1913,7 @@ errorFetchingDimensionData=获取{0}的维度值出错:{1}
errorFetchingStatistics=从服务器获取可用统计出错:{0}
errorFetchingAggregators=从服务器获取可用聚合器出错:{0}
errorLoadingDataRetrieverChainDefinitions=检索可用 DataRetrieverChainDefinitions 出错:{0}
errorFetchingComponentsChangedTimepoint=从服务器获取组件更改的时间点出错:{0}
errorRunningQuery=运行查询出错:{0}
errorReadingWindFixes=读取风力修复{0}出错
errorAddingWindFixForRace=添加比赛轮次{0}的风力修复出错:{1}
@@ -1881,6 +1987,11 @@ minimumRideHeightInMetersTooltip=将船只视为处于水翼腾空状态所需
minimumDurationBetweenAdjacentFoilingSegmentsInSeconds=相邻水翼腾空段之间的最短持续时间 (s)
minimumDurationBetweenAdjacentFoilingSegmentsInSecondsTooltip=如果不为空,并且两个相邻水翼腾空段之间的时间短于此值,会将这些相邻的水翼腾空段合并成一个。
needToProvideValidMinimumRideHeight=您需要提供有效的最小行驶高度值(米)。
dataMiningErrorMargins=误差容限
elements={0}元素
chooseDifferentDimensionTitle=选择不同的维度
chooseDifferentDimensionMessage=为分组结果选择不同的维度
pleaseSelectADimension=请选择维度
currentPortDaggerboardRake=左舷活动披水板倾斜度
currentPortDaggerboardRakeTooltip=当前左舷活动披水板倾斜度
currentStbdDaggerboardRake=右舷活动披水板倾斜度
@@ -44,7 +44,8 @@ public class BoatClassVectorGraphicsResolver {
BoatClassMasterdata.A_CAT, BoatClassMasterdata.TORNADO, BoatClassMasterdata.FLYING_PHANTOM);
BoatClassVectorGraphics keelBoatWithGennaker = new KeelBoatWithGennakerVectorGraphics(BoatClassMasterdata.J70,
BoatClassMasterdata.B_ONE, BoatClassMasterdata.J80, BoatClassMasterdata.LASER_SB3, BoatClassMasterdata.LONGTZE,
BoatClassMasterdata.RS_FEVA, BoatClassMasterdata.RS_TERA, BoatClassMasterdata.RS100, BoatClassMasterdata.TP52);
BoatClassMasterdata.RS_FEVA, BoatClassMasterdata.RS_TERA, BoatClassMasterdata.RS100, BoatClassMasterdata.TP52,
BoatClassMasterdata.CLUB_SWAN_50);
BoatClassVectorGraphics dinghyWithSpinnaker = new DinghyWithSpinnakerVectorGraphics(BoatClassMasterdata._420,
BoatClassMasterdata._470, BoatClassMasterdata._5O5, BoatClassMasterdata.CADET, BoatClassMasterdata.FLYING_DUTCHMAN,
BoatClassMasterdata.FOLKBOAT, BoatClassMasterdata.DYAS, BoatClassMasterdata.DRAGON_INT,
@@ -24,7 +24,7 @@ public class ManeuverTableLifecycle implements ComponentLifecycle<ManeuverTableS
@Override
public String getLocalizedShortName() {
return stringMessages.wind();
return stringMessages.maneuverTable();
}
@Override
@@ -13,11 +13,10 @@ public class ManeuverTableSettings extends AbstractGenericSerializableSettings {
private EnumSetSetting<ManeuverType> selectedManeuverTypes;
private Iterable<ManeuverType> defaultTypes = Arrays.asList(ManeuverType.values());
@Override
protected void addChildSettings() {
selectedManeuverTypes = new EnumSetSetting<>("selectedManeuverTypes", this, defaultTypes,
selectedManeuverTypes = new EnumSetSetting<>("selectedManeuverTypes", this,
Arrays.asList(ManeuverType.TACK, ManeuverType.JIBE, ManeuverType.PENALTY_CIRCLE),
ManeuverType::valueOf);
}
@@ -25,9 +24,6 @@ public class ManeuverTableSettings extends AbstractGenericSerializableSettings {
* The default settings
*/
public ManeuverTableSettings() {
selectedManeuverTypes.addValue(ManeuverType.TACK);
selectedManeuverTypes.addValue(ManeuverType.JIBE);
selectedManeuverTypes.addValue(ManeuverType.PENALTY_CIRCLE);
}
public ManeuverTableSettings(Set<ManeuverType> selectedManeuverTypes) {
@@ -78,7 +78,6 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
queryDefinitionProviderWithControls = new QueryDefinitionProviderWithControls(null, null, session,
dataMiningService, DataMiningEntryPoint.this, settingsControl, settingsManager,
resultsPresenter);
queryDefinitionProviderWithControls.getEntryWidget().addStyleName("dataMiningPanel");
selectionDockPanel.add(queryDefinitionProviderWithControls.getEntryWidget());
queryRunner = new SimpleQueryRunner(null, null, session, dataMiningService, DataMiningEntryPoint.this,
queryDefinitionProviderWithControls, resultsPresenter);
@@ -89,7 +88,7 @@ public class DataMiningEntryPoint extends AbstractSailingEntryPoint {
* automatic execution of queries. Re-enable this, when this functionality is desired again.
*/
// settingsControl.addSettingsComponent(queryRunner);
SplitLayoutPanel splitPanel = new SplitLayoutPanel(15);
SplitLayoutPanel splitPanel = new SplitLayoutPanel(10);
splitPanel.addSouth(resultsPresenter.getEntryWidget(), 350);
splitPanel.add(selectionDockPanel);
return splitPanel;
@@ -86,20 +86,16 @@ public class NumberPairResultsPresenter extends AbstractSailingResultsPresenter<
protected void internalShowResults(QueryResultDTO<?> res) {
result = res;
createAndAddSeriesToChart();
for (Entry<GroupKey, ?> resultEntry : result.getResults().entrySet()) {
@SuppressWarnings("unchecked")
PairWithStats<Number> value = (PairWithStats<Number>) resultEntry.getValue();
if(value.getIndividualPairs() != null) {
for(Pair<Number, Number> pair : value.getIndividualPairs()) {
if (value.getIndividualPairs() != null) {
for (Pair<Number, Number> pair : value.getIndividualPairs()) {
createAndAddPoint(resultEntry.getKey(), pair.getA(), pair.getB());
}
}
else {
} else {
createAndAddPoint(resultEntry.getKey(), value.getAverage().getA(), value.getAverage().getB());
}
}
chart.getXAxis().setAxisTitleText(result.getResultSignifier());
}
@@ -7,28 +7,28 @@ import com.sap.sailing.gwt.ui.polarmining.PolarResultsPresenter;
import com.sap.sailing.polars.datamining.shared.PolarAggregation;
import com.sap.sailing.polars.datamining.shared.PolarBackendData;
import com.sap.sse.datamining.shared.data.PairWithStats;
import com.sap.sse.datamining.ui.client.presentation.AbstractTabbedResultsPresenter;
import com.sap.sse.datamining.ui.client.presentation.TabbedResultsPresenter;
import com.sap.sse.datamining.ui.client.presentation.ResultsChart.DrillDownCallback;
import com.sap.sse.gwt.client.shared.components.Component;
import com.sap.sse.gwt.client.shared.settings.ComponentContext;
public class TabbedSailingResultsPresenter extends AbstractTabbedResultsPresenter {
public class TabbedSailingResultsPresenter extends TabbedResultsPresenter {
public TabbedSailingResultsPresenter(Component<?> parent, ComponentContext<?> context,
DrillDownCallback drillDownCallback, StringMessages stringMessages) {
super(parent, context, drillDownCallback);
registerResultPresenter(PolarAggregation.class,
registerResultsPresenter(PolarAggregation.class,
new PolarResultsPresenter(TabbedSailingResultsPresenter.this, getComponentContext(), stringMessages));
registerResultPresenter(PolarBackendData.class, new PolarBackendResultsPresenter(
registerResultsPresenter(PolarBackendData.class, new PolarBackendResultsPresenter(
TabbedSailingResultsPresenter.this, getComponentContext(), stringMessages));
registerResultPresenter(ManeuverSpeedDetailsAggregation.class, new ManeuverSpeedDetailsResultsPresenter(
registerResultsPresenter(ManeuverSpeedDetailsAggregation.class, new ManeuverSpeedDetailsResultsPresenter(
TabbedSailingResultsPresenter.this, getComponentContext(), stringMessages));
registerResultPresenter(PairWithStats.class, new NumberPairResultsPresenter(TabbedSailingResultsPresenter.this,
registerResultsPresenter(PairWithStats.class, new NumberPairResultsPresenter(TabbedSailingResultsPresenter.this,
getComponentContext(), stringMessages));
}
}
@@ -777,7 +777,7 @@ public abstract class LeaderboardPanel<LS extends LeaderboardSettings> extends A
protected abstract void setDefaultRaceColumnSelection(LS settings);
private void setValuesWithReferenceOrder(Iterable<DetailType> valuesToSet, List<DetailType> referenceOrder,
private void setValuesWithReferenceOrder(Iterable<DetailType> valuesToSet, Collection<DetailType> referenceOrder,
List<DetailType> collectionToSetValuesTo) {
collectionToSetValuesTo.clear();
collectionToSetValuesTo.addAll(referenceOrder);
@@ -935,11 +935,9 @@ public abstract class LeaderboardPanel<LS extends LeaderboardSettings> extends A
*/
private class BoatInfoColumn<T> extends LeaderboardSortableColumnWithMinMax<T, String> {
private final BoatFetcher<T> boatFetcher;
private final CompetitorFetcher<T> competitorFetcher;
public BoatInfoColumn(CompetitorFetcher<T> competitorFetcher, BoatFetcher<T> boatFetcher, LeaderBoardStyle style) {
public BoatInfoColumn(BoatFetcher<T> boatFetcher, LeaderBoardStyle style) {
super(new TextCell(), SortingOrder.ASCENDING, LeaderboardPanel.this);
this.competitorFetcher = competitorFetcher;
this.boatFetcher = boatFetcher;
// This style is adding to avoid contained images CSS property "max-width: 100%", which could cause
// an overflow to the next column (see https://bugzilla.sapsailing.com/bugzilla/show_bug.cgi?id=3537)
@@ -955,12 +953,7 @@ public abstract class LeaderboardPanel<LS extends LeaderboardSettings> extends A
@Override
public void render(Context context, T object, SafeHtmlBuilder sb) {
BoatDTO boat = boatFetcher.getBoat(object);
CompetitorDTO competitor = competitorFetcher.getCompetitor(object);
boolean boatColorShown = renderBoatColorIfNecessary(competitor, sb);
sb.appendEscaped(getShortInfo(boat));
if (boatColorShown) {
sb.appendHtmlConstant("</div>");
}
}
private String getShortInfo(BoatDTO boat) {
@@ -3184,9 +3177,8 @@ public abstract class LeaderboardPanel<LS extends LeaderboardSettings> extends A
if (getLeaderboardTable().getColumnCount() <= columnIndexWhereToInsertTheNextColumn
|| !(getLeaderboardTable()
.getColumn(columnIndexWhereToInsertTheNextColumn) instanceof LeaderboardPanel.BoatInfoColumn)) {
CompetitorFetcher<LeaderboardRowDTO> competitorFetcher = (LeaderboardRowDTO row) -> row.competitor;
BoatFetcher<LeaderboardRowDTO> boatFetcher = (LeaderboardRowDTO row) -> row.boat;
BoatInfoColumn<LeaderboardRowDTO> boatInfoColumn = new BoatInfoColumn<LeaderboardRowDTO>(competitorFetcher, boatFetcher, style);
BoatInfoColumn<LeaderboardRowDTO> boatInfoColumn = new BoatInfoColumn<LeaderboardRowDTO>(boatFetcher, style);
insertColumn(columnIndexWhereToInsertTheNextColumn, boatInfoColumn);
}
columnIndexWhereToInsertTheNextColumn++;
@@ -596,7 +596,6 @@ public class RaceBoardPanel
@Override
public void updatedLeaderboard(LeaderboardDTO leaderboard) {
leaderboardAndMapViewer.setLeftComponentWidth(leaderboardPanel.getContentPanel().getOffsetWidth());
if (editMarkPassingPanel != null) {
editMarkPassingPanel.setLeaderboard(leaderboard);
}
@@ -76,8 +76,6 @@ public class SideBySideComponentViewer implements UserStatusEventHandler {
private LayoutPanel mainPanel;
private TouchSplitLayoutPanel splitLayoutPanel;
private int savedSplitPosition = -1;
private boolean layoutForLeftComponentForcedOnce = false;
public SideBySideComponentViewer(final Component<?> leftComponentP, final Component<?> rightComponentP,
final MediaPlayerManagerComponent mediaPlayerManagerComponent, List<Component<?>> components,
@@ -132,18 +130,7 @@ public class SideBySideComponentViewer implements UserStatusEventHandler {
this.leftScrollPanel = new ScrollPanel();
this.leftScrollPanel.add(leftComponentP.getEntryWidget());
this.leftScrollPanel.setTitle(leftComponentP.getEntryWidget().getTitle());
this.mainPanel = new LayoutPanel() {
@Override
public void onResize() {
int leftWidth = leftScrollPanel.getOffsetWidth();
// The left scroll panel is potentially resized to ensure it is not too wide when the screen gets narrower,
// e.g. when resizing browser window or changing mobile device orientation. An offset of 40px is used, so
// the panels size slider and its toggle button is always accessable if it is open.
savedSplitPosition = Math.min(leftWidth > 0 ? leftWidth : savedSplitPosition, Window.getClientWidth() - 40);
splitLayoutPanel.setWidgetSize(leftScrollPanel, savedSplitPosition);
super.onResize();
}
};
this.mainPanel = new LayoutPanel();
this.mainPanel.setSize("100%", "100%");
this.mainPanel.getElement().getStyle().setMarginTop(-12, Unit.PX);
this.mainPanel.setStyleName("SideBySideComponentViewer-MainPanel");
@@ -154,8 +141,7 @@ public class SideBySideComponentViewer implements UserStatusEventHandler {
initializeComponents();
// initialize the leaderboard component
savedSplitPosition = MIN_LEADERBOARD_WIDTH;
splitLayoutPanel.insert(leftScrollPanel, leftComponent, Direction.WEST, savedSplitPosition);
splitLayoutPanel.insert(leftScrollPanel, leftComponent, Direction.WEST, MIN_LEADERBOARD_WIDTH);
// create a panel that will contain the horizontal toggle buttons
ResizableAbsolutePanel panelForMapAndHorizontalToggleButtons = new ResizableAbsolutePanel();
@@ -256,15 +242,12 @@ public class SideBySideComponentViewer implements UserStatusEventHandler {
if (!leftComponent.isVisible() && rightComponent.isVisible()) {
// the leaderboard is not visible, but the map is
if (isWidgetInSplitPanel(leftScrollPanel)) {
if (leftScrollPanel.getOffsetWidth() > 0) {
savedSplitPosition = Math.min(savedSplitPosition, leftScrollPanel.getOffsetWidth());
}
splitLayoutPanel.setWidgetVisibility(leftScrollPanel, leftComponent, /* hidden */true,
savedSplitPosition);
MIN_LEADERBOARD_WIDTH);
}
} else if (leftComponent.isVisible() && rightComponent.isVisible()) {
// the leaderboard and the map are visible
splitLayoutPanel.setWidgetVisibility(leftScrollPanel, leftComponent, /* hidden */false, savedSplitPosition);
splitLayoutPanel.setWidgetVisibility(leftScrollPanel, leftComponent, /* hidden */false, MIN_LEADERBOARD_WIDTH);
} else if (!leftComponent.isVisible() && !rightComponent.isVisible()) {
}
@@ -293,16 +276,6 @@ public class SideBySideComponentViewer implements UserStatusEventHandler {
return "";
}
public void setLeftComponentWidth(int width) {
// TODO: The information provided by width is wrong
// need to find a way to get the correct information
if (!layoutForLeftComponentForcedOnce) {
savedSplitPosition = MIN_LEADERBOARD_WIDTH;
forceLayout();
}
layoutForLeftComponentForcedOnce = true;
}
@Override
public void onUserStatusChange(UserDTO user, boolean preAuthenticated) {
final Splitter markPassingsSplitter = splitLayoutPanel.getAssociatedSplitter(markPassingsPanel);
@@ -364,4 +337,8 @@ public class SideBySideComponentViewer implements UserStatusEventHandler {
leftScrollPanelSplitter.getToggleButton().setVisible(visible);
}
}
public ScrollPanel getLeftScrollPanel() {
return leftScrollPanel;
}
}
@@ -809,16 +809,18 @@ public class TouchSplitLayoutPanel extends DockLayoutPanel {
* </p>
*
* @param hidden set this to true if the panel should be hidden
* @param size the size of the panel. Always provide the visible size even when hidden is true.
* @param initialSize the size of the panel. only required to be valid if not hidden.
*/
public void setWidgetVisibility(Widget widget, Component<?> associatedComponentToWidget,
final boolean hidden, final int size) {
final boolean hidden, final int initialSize) {
super.setWidgetHidden(widget, hidden);
final Splitter splitter = getAssociatedSplitter(widget);
if (splitter != null) {
LayoutData layoutData = (LayoutData) widget.getLayoutData();
if (hidden) {
layoutData.oldSize = layoutData.size;
if(layoutData.size > 0) {
layoutData.oldSize = layoutData.size;
}
widget.setVisible(false);
if (associatedComponentToWidget != null) {
if (associatedComponentToWidget.isVisible()) {
@@ -833,7 +835,16 @@ public class TouchSplitLayoutPanel extends DockLayoutPanel {
associatedComponentToWidget.setVisible(true);
}
}
splitter.setAssociatedWidgetSize((layoutData.oldSize > 0 ? layoutData.oldSize : size), /* defer */false);
if (layoutData.size <= 0) {
//it is not yet sized
if(layoutData.oldSize > 0) {
//and we have a stored old size it had before minimizing it
splitter.setAssociatedWidgetSize(layoutData.oldSize, /* defer */false);
} else {
//and we do not have any size yet, so use the default size
splitter.setAssociatedWidgetSize(initialSize, /* defer */false);
}
}
splitter.setDraggerVisible(!hidden);
splitter.setVisible(!hidden);
splitter.getToggleButton().removeStyleDependentName("Closed");
@@ -5904,10 +5904,14 @@ public class SailingServiceImpl extends ProxiedRemoteServiceServlet implements S
Util.addAll(competitorToBoatMappingsRegistered.keySet(), competitorsToUnregister);
for (final Entry<CompetitorType, Boat> e : competitorToBoatMappingsRegistered.entrySet()) {
CompetitorType competitor = e.getKey();
if (competitorToBoatMappingsToRegister.get(competitor) == e.getValue()) {
// User wants to map competitor to boat, and that mapping already exists; neither add nor remove this registration but leave as is:
competitorToBoatMappingsToRegister.remove(competitor);
competitorsToUnregister.remove(competitor);
if (competitorToBoatMappingsToRegister.containsKey(competitor)) { // is competitor to be registered?
final Boat boatOfCompetitorToRegister = competitorToBoatMappingsToRegister.get(competitor);
final Boat boatOfRegisteredCompetitor = e.getValue();
if (boatOfCompetitorToRegister == boatOfRegisteredCompetitor) {
// User wants to map competitor to boat, and that mapping already exists; neither add nor remove this registration but leave as is:
competitorToBoatMappingsToRegister.remove(competitor);
competitorsToUnregister.remove(competitor);
}
}
}
return competitorsToUnregister;
@@ -266,18 +266,20 @@ public class WindStreamletsRaceboardOverlay extends MovingCanvasOverlay {
// confidences
for (Entry<WindSource, WindTrackInfoDTO> e : result.windTrackInfoByWindSource.entrySet()) {
WindTrackInfoDTO windTrackForSource = windInfoForRace.windTrackInfoByWindSource.get(e.getKey());
final WindTrackInfoDTO resultWindTrackInfoDTO = result.windTrackInfoByWindSource.get(e.getKey());
windTrackForSource.resolutionOutsideOfWhichNoFixWillBeReturned = resultWindTrackInfoDTO.resolutionOutsideOfWhichNoFixWillBeReturned;
if (windTrackForSource.windFixes == null) {
windTrackForSource.windFixes = resultWindTrackInfoDTO.windFixes;
} else {
windTrackForSource.windFixes.addAll(resultWindTrackInfoDTO.windFixes);
}
if (resultWindTrackInfoDTO.maxWindConfidence > windTrackForSource.maxWindConfidence) {
windTrackForSource.maxWindConfidence = resultWindTrackInfoDTO.maxWindConfidence;
}
if (resultWindTrackInfoDTO.minWindConfidence < windTrackForSource.minWindConfidence) {
windTrackForSource.minWindConfidence = resultWindTrackInfoDTO.minWindConfidence;
if (windTrackForSource != null) {
final WindTrackInfoDTO resultWindTrackInfoDTO = result.windTrackInfoByWindSource.get(e.getKey());
windTrackForSource.resolutionOutsideOfWhichNoFixWillBeReturned = resultWindTrackInfoDTO.resolutionOutsideOfWhichNoFixWillBeReturned;
if (windTrackForSource.windFixes == null) {
windTrackForSource.windFixes = resultWindTrackInfoDTO.windFixes;
} else {
windTrackForSource.windFixes.addAll(resultWindTrackInfoDTO.windFixes);
}
if (resultWindTrackInfoDTO.maxWindConfidence > windTrackForSource.maxWindConfidence) {
windTrackForSource.maxWindConfidence = resultWindTrackInfoDTO.maxWindConfidence;
}
if (resultWindTrackInfoDTO.minWindConfidence < windTrackForSource.minWindConfidence) {
windTrackForSource.minWindConfidence = resultWindTrackInfoDTO.minWindConfidence;
}
}
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="src" path="src"/>
<classpathentry kind="src" path="test"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
<classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
<classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
<classpathentry kind="output" path="bin"/>
</classpath>
@@ -0,0 +1,39 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>com.sap.sse.datamining.ui.test</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.ManifestBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.pde.SchemaBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.gwtplugins.gdt.eclipse.core.webAppProjectValidator</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>com.gwtplugins.gwt.eclipse.core.gwtProjectValidator</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.pde.PluginNature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>com.gwtplugins.gwt.eclipse.core.gwtNature</nature>
</natures>
</projectDescription>
@@ -0,0 +1,4 @@
eclipse.preferences.version=1
jarsExcludedFromWebInfLib=
warSrcDir=
warSrcDirIsOutput=true
@@ -0,0 +1,2 @@
eclipse.preferences.version=1
entryPointModules=
@@ -0,0 +1,7 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8
@@ -0,0 +1,3 @@
eclipse.preferences.version=1
pluginProject.extensions=false
resolve.requirebundle=false
@@ -0,0 +1,15 @@
Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: Test
Bundle-SymbolicName: com.sap.sse.datamining.ui.test
Bundle-Version: 1.0.0.qualifier
Bundle-Vendor: SAP
Automatic-Module-Name: com.sap.sse.datamining.ui.test
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
Require-Bundle: org.junit,
com.google.gwt.user;bundle-version="2.8.2",
com.sap.sse.datamining.ui,
com.sap.sse.gwt;bundle-version="1.0.0",
slf4j.api;bundle-version="1.6.4",
com.sap.sse.common,
com.sap.sse.datamining.shared
@@ -0,0 +1,5 @@
source.. = src/,\
test/
output.. = bin/
bin.includes = META-INF/,\
.
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
When updating your version of GWT, you should also update this DTD reference,
so that your app can take advantage of the latest GWT module capabilities.
-->
<!DOCTYPE module PUBLIC "-//Google Inc.//DTD Google Web Toolkit 2.8.2//EN"
"http://gwtproject.org/doctype/2.8.2/gwt-module.dtd">
<module rename-to='testssedataminingui'>
<!-- Inherit the core Web Toolkit stuff. -->
<inherits name='com.google.gwt.user.User'/>
<!-- Other module inherits -->
<inherits name='com.sap.sse.datamining.SSEDataMining'/>
<!-- Specify the paths for translatable code -->
<source path='client'/>
<!-- allow Super Dev Mode -->
<add-linker name="xsiframe"/>
</module>

Some files were not shown because too many files have changed in this diff Show More