forked from loafle/openapi-generator-original
Update swift samples (#738)
* update all swift samples * fix method name starting with number literal * better handling of operationId starting with number * update swift 4 samples
This commit is contained in:
committed by
William Cheng
parent
2044c36398
commit
fcfd8ea76e
+6
@@ -454,6 +454,12 @@ public class Swift3Codegen extends DefaultCodegen implements CodegenConfig {
|
||||
return newOperationId;
|
||||
}
|
||||
|
||||
// operationId starts with a number
|
||||
if (operationId.matches("^\\d.*")) {
|
||||
LOGGER.warn(operationId + " (starting with a number) cannot be used as method name. Renamed to " + camelize(sanitizeName("call_" + operationId), true));
|
||||
operationId = camelize(sanitizeName("call_" + operationId), true);
|
||||
}
|
||||
|
||||
return operationId;
|
||||
}
|
||||
|
||||
|
||||
+7
@@ -559,6 +559,13 @@ public class Swift4Codegen extends DefaultCodegen implements CodegenConfig {
|
||||
return newOperationId;
|
||||
}
|
||||
|
||||
// operationId starts with a number
|
||||
if (operationId.matches("^\\d.*")) {
|
||||
LOGGER.warn(operationId + " (starting with a number) cannot be used as method name. Renamed to " + camelize(sanitizeName("call_" + operationId), true));
|
||||
operationId = camelize(sanitizeName("call_" + operationId), true);
|
||||
}
|
||||
|
||||
|
||||
return operationId;
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -450,6 +450,12 @@ public class SwiftClientCodegen extends DefaultCodegen implements CodegenConfig
|
||||
return newOperationId;
|
||||
}
|
||||
|
||||
// operationId starts with a number
|
||||
if (operationId.matches("^\\d.*")) {
|
||||
LOGGER.warn(operationId + " (starting with a number) cannot be used as method name. Renamed to " + camelize(sanitizeName("call_" + operationId), true));
|
||||
operationId = camelize(sanitizeName("call_" + operationId), true);
|
||||
}
|
||||
|
||||
return operationId;
|
||||
}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
3.0.1-SNAPSHOT
|
||||
3.2.0-SNAPSHOT
|
||||
+4
-4
@@ -239,8 +239,8 @@ open class FakeAPI: APIBase {
|
||||
* enum for parameter enumHeaderStringArray
|
||||
*/
|
||||
public enum EnumHeaderStringArray_testEnumParameters: String {
|
||||
case greaterThan = ">"
|
||||
case dollar = "$"
|
||||
case greaterThan = "">""
|
||||
case dollar = ""$""
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,8 +256,8 @@ open class FakeAPI: APIBase {
|
||||
* enum for parameter enumQueryStringArray
|
||||
*/
|
||||
public enum EnumQueryStringArray_testEnumParameters: String {
|
||||
case greaterThan = ">"
|
||||
case dollar = "$"
|
||||
case greaterThan = "">""
|
||||
case dollar = ""$""
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
@@ -25,6 +25,7 @@ open class FakeClassnameTags123API: APIBase {
|
||||
/**
|
||||
To test class name in snake case
|
||||
- PATCH /fake_classname_test
|
||||
- To test class name in snake case
|
||||
- API Key:
|
||||
- type: apiKey api_key_query (QUERY)
|
||||
- name: api_key_query
|
||||
|
||||
+3
-3
@@ -89,9 +89,9 @@ open class PetAPI: APIBase {
|
||||
* enum for parameter status
|
||||
*/
|
||||
public enum Status_findPetsByStatus: String {
|
||||
case available = "available"
|
||||
case pending = "pending"
|
||||
case sold = "sold"
|
||||
case available = ""available""
|
||||
case pending = ""pending""
|
||||
case sold = ""sold""
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -15,8 +15,8 @@ open class EnumArrays: JSONEncodable {
|
||||
case dollar = "$"
|
||||
}
|
||||
public enum ArrayEnum: String {
|
||||
case fish = "fish"
|
||||
case crab = "crab"
|
||||
case fish = ""fish""
|
||||
case crab = ""crab""
|
||||
}
|
||||
public var justSymbol: JustSymbol?
|
||||
public var arrayEnum: [ArrayEnum]?
|
||||
|
||||
+2
-2
@@ -11,8 +11,8 @@ import Foundation
|
||||
open class MapTest: JSONEncodable {
|
||||
|
||||
public enum MapOfEnumString: String {
|
||||
case upper = "UPPER"
|
||||
case lower = "lower"
|
||||
case upper = ""UPPER""
|
||||
case lower = ""lower""
|
||||
}
|
||||
public var mapMapOfString: [String:[String:String]]?
|
||||
public var mapOfEnumString: [String:String]?
|
||||
|
||||
@@ -6,14 +6,18 @@ PODS:
|
||||
DEPENDENCIES:
|
||||
- PetstoreClient (from `../`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/cocoapods/specs.git:
|
||||
- Alamofire
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
PetstoreClient:
|
||||
:path: ../
|
||||
:path: "../"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: f28cdffd29de33a7bfa022cbd63ae95a27fae140
|
||||
PetstoreClient: bbb95cd0adc059bbdbe541b384f8294f4e241226
|
||||
PetstoreClient: a9f241d378687facad5c691a1747b21f64b405fa
|
||||
|
||||
PODFILE CHECKSUM: 417049e9ed0e4680602b34d838294778389bd418
|
||||
|
||||
COCOAPODS: 1.3.1
|
||||
COCOAPODS: 1.5.3
|
||||
|
||||
+4
-3
@@ -2,16 +2,17 @@
|
||||
"name": "PetstoreClient",
|
||||
"platforms": {
|
||||
"ios": "9.0",
|
||||
"osx": "10.11"
|
||||
"osx": "10.11",
|
||||
"tvos": "9.0"
|
||||
},
|
||||
"version": "0.0.1",
|
||||
"source": {
|
||||
"git": "git@github.com:swagger-api/swagger-mustache.git",
|
||||
"git": "git@github.com:openapitools/openapi-generator.git",
|
||||
"tag": "v1.0.0"
|
||||
},
|
||||
"authors": "",
|
||||
"license": "Proprietary",
|
||||
"homepage": "https://github.com/swagger-api/swagger-codegen",
|
||||
"homepage": "https://github.com/openapitools/openapi-generator",
|
||||
"summary": "PetstoreClient",
|
||||
"source_files": "PetstoreClient/Classes/**/*.swift",
|
||||
"dependencies": {
|
||||
|
||||
+7
-3
@@ -6,14 +6,18 @@ PODS:
|
||||
DEPENDENCIES:
|
||||
- PetstoreClient (from `../`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/cocoapods/specs.git:
|
||||
- Alamofire
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
PetstoreClient:
|
||||
:path: ../
|
||||
:path: "../"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: f28cdffd29de33a7bfa022cbd63ae95a27fae140
|
||||
PetstoreClient: bbb95cd0adc059bbdbe541b384f8294f4e241226
|
||||
PetstoreClient: a9f241d378687facad5c691a1747b21f64b405fa
|
||||
|
||||
PODFILE CHECKSUM: 417049e9ed0e4680602b34d838294778389bd418
|
||||
|
||||
COCOAPODS: 1.3.1
|
||||
COCOAPODS: 1.5.3
|
||||
|
||||
Generated
+628
-608
File diff suppressed because it is too large
Load Diff
+3
-4
@@ -1,9 +1,8 @@
|
||||
CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/Alamofire
|
||||
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Alamofire
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PODS_TARGET_SRCROOT = ${PODS_ROOT}/Alamofire
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
|
||||
+4
-5
@@ -1,10 +1,9 @@
|
||||
CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/PetstoreClient
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire"
|
||||
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
|
||||
+49
-8
@@ -1,15 +1,28 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
|
||||
# If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
|
||||
# frameworks to, so exit 0 (signalling the script phase was successful).
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
|
||||
COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
|
||||
SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
|
||||
|
||||
# Used as a return value for each invocation of `strip_invalid_archs` function.
|
||||
STRIP_BINARY_RETVAL=0
|
||||
|
||||
# This protects against multiple targets copying the same framework dependency at the same time. The solution
|
||||
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
|
||||
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
|
||||
|
||||
# Copies and strips a vendored framework
|
||||
install_framework()
|
||||
{
|
||||
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
|
||||
@@ -58,21 +71,40 @@ install_framework()
|
||||
fi
|
||||
}
|
||||
|
||||
# Copies the dSYM of a vendored framework
|
||||
# Copies and strips a vendored dSYM
|
||||
install_dsym() {
|
||||
local source="$1"
|
||||
if [ -r "$source" ]; then
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\""
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}"
|
||||
# Copy the dSYM into a the targets temp dir.
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
|
||||
|
||||
local basename
|
||||
basename="$(basename -s .framework.dSYM "$source")"
|
||||
binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
|
||||
|
||||
# Strip invalid architectures so "fat" simulator / device frameworks work on device
|
||||
if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then
|
||||
strip_invalid_archs "$binary"
|
||||
fi
|
||||
|
||||
if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
|
||||
# Move the stripped file into its final destination.
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
|
||||
else
|
||||
# The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
|
||||
touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Signs a framework with the provided identity
|
||||
code_sign_if_enabled() {
|
||||
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
|
||||
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
|
||||
# Use the current code_sign_identitiy
|
||||
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
|
||||
local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'"
|
||||
local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
|
||||
|
||||
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
|
||||
code_sign_cmd="$code_sign_cmd &"
|
||||
@@ -85,10 +117,18 @@ code_sign_if_enabled() {
|
||||
# Strip invalid architectures
|
||||
strip_invalid_archs() {
|
||||
binary="$1"
|
||||
# Get architectures for current file
|
||||
archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
|
||||
# Get architectures for current target binary
|
||||
binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
|
||||
# Intersect them with the architectures we are building for
|
||||
intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
|
||||
# If there are no archs supported by this binary then warn the user
|
||||
if [[ -z "$intersected_archs" ]]; then
|
||||
echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
|
||||
STRIP_BINARY_RETVAL=0
|
||||
return
|
||||
fi
|
||||
stripped=""
|
||||
for arch in $archs; do
|
||||
for arch in $binary_archs; do
|
||||
if ! [[ "${ARCHS}" == *"$arch"* ]]; then
|
||||
# Strip non-valid architectures in-place
|
||||
lipo -remove "$arch" -output "$binary" "$binary" || exit 1
|
||||
@@ -98,6 +138,7 @@ strip_invalid_archs() {
|
||||
if [[ "$stripped" ]]; then
|
||||
echo "Stripped $binary of architectures:$stripped"
|
||||
fi
|
||||
STRIP_BINARY_RETVAL=1
|
||||
}
|
||||
|
||||
|
||||
|
||||
+15
-3
@@ -1,5 +1,13 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then
|
||||
# If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy
|
||||
# resources to, so exit 0 (signalling the script phase was successful).
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
|
||||
@@ -12,7 +20,7 @@ XCASSET_FILES=()
|
||||
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
|
||||
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
|
||||
|
||||
case "${TARGETED_DEVICE_FAMILY}" in
|
||||
case "${TARGETED_DEVICE_FAMILY:-}" in
|
||||
1,2)
|
||||
TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
|
||||
;;
|
||||
@@ -92,7 +100,7 @@ if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
|
||||
fi
|
||||
rm -f "$RESOURCES_TO_COPY"
|
||||
|
||||
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
|
||||
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ]
|
||||
then
|
||||
# Find all other xcassets (this unfortunately includes those of path pods and other targets).
|
||||
OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
|
||||
@@ -102,5 +110,9 @@ then
|
||||
fi
|
||||
done <<<"$OTHER_XCASSETS"
|
||||
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
else
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist"
|
||||
fi
|
||||
fi
|
||||
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient/PetstoreClient.framework/Headers"
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient/PetstoreClient.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "PetstoreClient"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
||||
PODS_ROOT = ${SRCROOT}/Pods
|
||||
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient/PetstoreClient.framework/Headers"
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient/PetstoreClient.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "PetstoreClient"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
||||
PODS_ROOT = ${SRCROOT}/Pods
|
||||
|
||||
+49
-8
@@ -1,15 +1,28 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
|
||||
# If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
|
||||
# frameworks to, so exit 0 (signalling the script phase was successful).
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
|
||||
COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
|
||||
SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
|
||||
|
||||
# Used as a return value for each invocation of `strip_invalid_archs` function.
|
||||
STRIP_BINARY_RETVAL=0
|
||||
|
||||
# This protects against multiple targets copying the same framework dependency at the same time. The solution
|
||||
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
|
||||
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
|
||||
|
||||
# Copies and strips a vendored framework
|
||||
install_framework()
|
||||
{
|
||||
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
|
||||
@@ -58,21 +71,40 @@ install_framework()
|
||||
fi
|
||||
}
|
||||
|
||||
# Copies the dSYM of a vendored framework
|
||||
# Copies and strips a vendored dSYM
|
||||
install_dsym() {
|
||||
local source="$1"
|
||||
if [ -r "$source" ]; then
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\""
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}"
|
||||
# Copy the dSYM into a the targets temp dir.
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
|
||||
|
||||
local basename
|
||||
basename="$(basename -s .framework.dSYM "$source")"
|
||||
binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
|
||||
|
||||
# Strip invalid architectures so "fat" simulator / device frameworks work on device
|
||||
if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then
|
||||
strip_invalid_archs "$binary"
|
||||
fi
|
||||
|
||||
if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
|
||||
# Move the stripped file into its final destination.
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
|
||||
else
|
||||
# The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
|
||||
touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Signs a framework with the provided identity
|
||||
code_sign_if_enabled() {
|
||||
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
|
||||
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
|
||||
# Use the current code_sign_identitiy
|
||||
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
|
||||
local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'"
|
||||
local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
|
||||
|
||||
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
|
||||
code_sign_cmd="$code_sign_cmd &"
|
||||
@@ -85,10 +117,18 @@ code_sign_if_enabled() {
|
||||
# Strip invalid architectures
|
||||
strip_invalid_archs() {
|
||||
binary="$1"
|
||||
# Get architectures for current file
|
||||
archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
|
||||
# Get architectures for current target binary
|
||||
binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
|
||||
# Intersect them with the architectures we are building for
|
||||
intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
|
||||
# If there are no archs supported by this binary then warn the user
|
||||
if [[ -z "$intersected_archs" ]]; then
|
||||
echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
|
||||
STRIP_BINARY_RETVAL=0
|
||||
return
|
||||
fi
|
||||
stripped=""
|
||||
for arch in $archs; do
|
||||
for arch in $binary_archs; do
|
||||
if ! [[ "${ARCHS}" == *"$arch"* ]]; then
|
||||
# Strip non-valid architectures in-place
|
||||
lipo -remove "$arch" -output "$binary" "$binary" || exit 1
|
||||
@@ -98,6 +138,7 @@ strip_invalid_archs() {
|
||||
if [[ "$stripped" ]]; then
|
||||
echo "Stripped $binary of architectures:$stripped"
|
||||
fi
|
||||
STRIP_BINARY_RETVAL=1
|
||||
}
|
||||
|
||||
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
|
||||
|
||||
+15
-3
@@ -1,5 +1,13 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then
|
||||
# If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy
|
||||
# resources to, so exit 0 (signalling the script phase was successful).
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
|
||||
@@ -12,7 +20,7 @@ XCASSET_FILES=()
|
||||
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
|
||||
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
|
||||
|
||||
case "${TARGETED_DEVICE_FAMILY}" in
|
||||
case "${TARGETED_DEVICE_FAMILY:-}" in
|
||||
1,2)
|
||||
TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
|
||||
;;
|
||||
@@ -92,7 +100,7 @@ if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
|
||||
fi
|
||||
rm -f "$RESOURCES_TO_COPY"
|
||||
|
||||
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
|
||||
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ]
|
||||
then
|
||||
# Find all other xcassets (this unfortunately includes those of path pods and other targets).
|
||||
OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
|
||||
@@ -102,5 +110,9 @@ then
|
||||
fi
|
||||
done <<<"$OTHER_XCASSETS"
|
||||
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
else
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist"
|
||||
fi
|
||||
fi
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient/PetstoreClient.framework/Headers"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient/PetstoreClient.framework/Headers"
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
||||
PODS_ROOT = ${SRCROOT}/Pods
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient/PetstoreClient.framework/Headers"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient/PetstoreClient.framework/Headers"
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
||||
PODS_ROOT = ${SRCROOT}/Pods
|
||||
|
||||
-48
@@ -149,7 +149,6 @@
|
||||
6D4EFB8E1C692C6300B96B06 /* Frameworks */,
|
||||
6D4EFB8F1C692C6300B96B06 /* Resources */,
|
||||
4485A75250058E2D5BBDF63F /* [CP] Embed Pods Frameworks */,
|
||||
808CE4A0CE801CAC5ABF5B08 /* [CP] Copy Pods Resources */,
|
||||
3D9471620628F03313096EB2 /* 📦 Embed Pods Frameworks */,
|
||||
EEEC2B2D0497D38CEAD2DB24 /* 📦 Copy Pods Resources */,
|
||||
);
|
||||
@@ -171,8 +170,6 @@
|
||||
6D4EFBA11C692C6300B96B06 /* Sources */,
|
||||
6D4EFBA21C692C6300B96B06 /* Frameworks */,
|
||||
6D4EFBA31C692C6300B96B06 /* Resources */,
|
||||
796EAD48F1BCCDAA291CD963 /* [CP] Embed Pods Frameworks */,
|
||||
1652CB1A246A4689869E442D /* [CP] Copy Pods Resources */,
|
||||
ECE47F6BF90C3848F6E94AFF /* 📦 Embed Pods Frameworks */,
|
||||
1494090872F3F18E536E8902 /* 📦 Copy Pods Resources */,
|
||||
);
|
||||
@@ -262,21 +259,6 @@
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwaggerClientTests/Pods-SwaggerClientTests-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
1652CB1A246A4689869E442D /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwaggerClientTests/Pods-SwaggerClientTests-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
1F03F780DC2D9727E5E64BA9 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -327,21 +309,6 @@
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwaggerClient/Pods-SwaggerClient-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
796EAD48F1BCCDAA291CD963 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwaggerClientTests/Pods-SwaggerClientTests-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
79FE27B09B2DD354C831BD49 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -357,21 +324,6 @@
|
||||
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [[ $? != 0 ]] ; then\n cat << EOM\nerror: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\nEOM\n exit 1\nfi\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
808CE4A0CE801CAC5ABF5B08 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwaggerClient/Pods-SwaggerClient-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
B4DB169E5F018305D6759D34 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
|
||||
@@ -1 +1 @@
|
||||
3.0.1-SNAPSHOT
|
||||
3.2.0-SNAPSHOT
|
||||
+4
-4
@@ -239,8 +239,8 @@ open class FakeAPI: APIBase {
|
||||
* enum for parameter enumHeaderStringArray
|
||||
*/
|
||||
public enum EnumHeaderStringArray_testEnumParameters: String {
|
||||
case greaterThan = ">"
|
||||
case dollar = "$"
|
||||
case greaterThan = "">""
|
||||
case dollar = ""$""
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -256,8 +256,8 @@ open class FakeAPI: APIBase {
|
||||
* enum for parameter enumQueryStringArray
|
||||
*/
|
||||
public enum EnumQueryStringArray_testEnumParameters: String {
|
||||
case greaterThan = ">"
|
||||
case dollar = "$"
|
||||
case greaterThan = "">""
|
||||
case dollar = ""$""
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
@@ -25,6 +25,7 @@ open class FakeClassnameTags123API: APIBase {
|
||||
/**
|
||||
To test class name in snake case
|
||||
- PATCH /fake_classname_test
|
||||
- To test class name in snake case
|
||||
- API Key:
|
||||
- type: apiKey api_key_query (QUERY)
|
||||
- name: api_key_query
|
||||
|
||||
+3
-3
@@ -89,9 +89,9 @@ open class PetAPI: APIBase {
|
||||
* enum for parameter status
|
||||
*/
|
||||
public enum Status_findPetsByStatus: String {
|
||||
case available = "available"
|
||||
case pending = "pending"
|
||||
case sold = "sold"
|
||||
case available = ""available""
|
||||
case pending = ""pending""
|
||||
case sold = ""sold""
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -15,8 +15,8 @@ open class EnumArrays: JSONEncodable {
|
||||
case dollar = "$"
|
||||
}
|
||||
public enum ArrayEnum: String {
|
||||
case fish = "fish"
|
||||
case crab = "crab"
|
||||
case fish = ""fish""
|
||||
case crab = ""crab""
|
||||
}
|
||||
public var justSymbol: JustSymbol?
|
||||
public var arrayEnum: [ArrayEnum]?
|
||||
|
||||
+2
-2
@@ -11,8 +11,8 @@ import Foundation
|
||||
open class MapTest: JSONEncodable {
|
||||
|
||||
public enum MapOfEnumString: String {
|
||||
case upper = "UPPER"
|
||||
case lower = "lower"
|
||||
case upper = ""UPPER""
|
||||
case lower = ""lower""
|
||||
}
|
||||
public var mapMapOfString: [String:[String:String]]?
|
||||
public var mapOfEnumString: [String:String]?
|
||||
|
||||
+10
@@ -11,8 +11,18 @@ import Foundation
|
||||
open class OuterComposite: JSONEncodable {
|
||||
|
||||
public var myNumber: Double?
|
||||
public var myNumberNum: NSNumber? {
|
||||
get {
|
||||
return myNumber.map({ return NSNumber(value: $0) })
|
||||
}
|
||||
}
|
||||
public var myString: String?
|
||||
public var myBoolean: Bool?
|
||||
public var myBooleanNum: NSNumber? {
|
||||
get {
|
||||
return myBoolean.map({ return NSNumber(value: $0) })
|
||||
}
|
||||
}
|
||||
|
||||
public init() {}
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
3.0.1-SNAPSHOT
|
||||
3.2.0-SNAPSHOT
|
||||
+4
-4
@@ -345,8 +345,8 @@ open class FakeAPI: APIBase {
|
||||
* enum for parameter enumHeaderStringArray
|
||||
*/
|
||||
public enum EnumHeaderStringArray_testEnumParameters: String {
|
||||
case greaterThan = ">"
|
||||
case dollar = "$"
|
||||
case greaterThan = "">""
|
||||
case dollar = ""$""
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -362,8 +362,8 @@ open class FakeAPI: APIBase {
|
||||
* enum for parameter enumQueryStringArray
|
||||
*/
|
||||
public enum EnumQueryStringArray_testEnumParameters: String {
|
||||
case greaterThan = ">"
|
||||
case dollar = "$"
|
||||
case greaterThan = "">""
|
||||
case dollar = ""$""
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
@@ -42,6 +42,7 @@ open class FakeClassnameTags123API: APIBase {
|
||||
/**
|
||||
To test class name in snake case
|
||||
- PATCH /fake_classname_test
|
||||
- To test class name in snake case
|
||||
- API Key:
|
||||
- type: apiKey api_key_query (QUERY)
|
||||
- name: api_key_query
|
||||
|
||||
+3
-3
@@ -123,9 +123,9 @@ open class PetAPI: APIBase {
|
||||
* enum for parameter status
|
||||
*/
|
||||
public enum Status_findPetsByStatus: String {
|
||||
case available = "available"
|
||||
case pending = "pending"
|
||||
case sold = "sold"
|
||||
case available = ""available""
|
||||
case pending = ""pending""
|
||||
case sold = ""sold""
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -15,8 +15,8 @@ open class EnumArrays: JSONEncodable {
|
||||
case dollar = "$"
|
||||
}
|
||||
public enum ArrayEnum: String {
|
||||
case fish = "fish"
|
||||
case crab = "crab"
|
||||
case fish = ""fish""
|
||||
case crab = ""crab""
|
||||
}
|
||||
public var justSymbol: JustSymbol?
|
||||
public var arrayEnum: [ArrayEnum]?
|
||||
|
||||
+2
-2
@@ -11,8 +11,8 @@ import Foundation
|
||||
open class MapTest: JSONEncodable {
|
||||
|
||||
public enum MapOfEnumString: String {
|
||||
case upper = "UPPER"
|
||||
case lower = "lower"
|
||||
case upper = ""UPPER""
|
||||
case lower = ""lower""
|
||||
}
|
||||
public var mapMapOfString: [String:[String:String]]?
|
||||
public var mapOfEnumString: [String:String]?
|
||||
|
||||
@@ -8,15 +8,20 @@ PODS:
|
||||
DEPENDENCIES:
|
||||
- PetstoreClient (from `../`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/cocoapods/specs.git:
|
||||
- Alamofire
|
||||
- PromiseKit
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
PetstoreClient:
|
||||
:path: ../
|
||||
:path: "../"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: f28cdffd29de33a7bfa022cbd63ae95a27fae140
|
||||
PetstoreClient: 529644d7d853d985a2748d43c7d4848db0fd62bb
|
||||
PetstoreClient: b5876a16a88cce6a4fc71443a62f9892171b48e2
|
||||
PromiseKit: ecf5fe92275d57ee77c9ede858af47a162e9b97e
|
||||
|
||||
PODFILE CHECKSUM: da9f5a7ad6086f2c7abb73cf2c35cefce04a9a30
|
||||
|
||||
COCOAPODS: 1.3.1
|
||||
COCOAPODS: 1.5.3
|
||||
|
||||
+4
-3
@@ -2,16 +2,17 @@
|
||||
"name": "PetstoreClient",
|
||||
"platforms": {
|
||||
"ios": "9.0",
|
||||
"osx": "10.11"
|
||||
"osx": "10.11",
|
||||
"tvos": "9.0"
|
||||
},
|
||||
"version": "0.0.1",
|
||||
"source": {
|
||||
"git": "git@github.com:swagger-api/swagger-mustache.git",
|
||||
"git": "git@github.com:openapitools/openapi-generator.git",
|
||||
"tag": "v1.0.0"
|
||||
},
|
||||
"authors": "",
|
||||
"license": "Proprietary",
|
||||
"homepage": "https://github.com/swagger-api/swagger-codegen",
|
||||
"homepage": "https://github.com/openapitools/openapi-generator",
|
||||
"summary": "PetstoreClient",
|
||||
"source_files": "PetstoreClient/Classes/**/*.swift",
|
||||
"dependencies": {
|
||||
|
||||
+8
-3
@@ -8,15 +8,20 @@ PODS:
|
||||
DEPENDENCIES:
|
||||
- PetstoreClient (from `../`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/cocoapods/specs.git:
|
||||
- Alamofire
|
||||
- PromiseKit
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
PetstoreClient:
|
||||
:path: ../
|
||||
:path: "../"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: f28cdffd29de33a7bfa022cbd63ae95a27fae140
|
||||
PetstoreClient: 529644d7d853d985a2748d43c7d4848db0fd62bb
|
||||
PetstoreClient: b5876a16a88cce6a4fc71443a62f9892171b48e2
|
||||
PromiseKit: ecf5fe92275d57ee77c9ede858af47a162e9b97e
|
||||
|
||||
PODFILE CHECKSUM: da9f5a7ad6086f2c7abb73cf2c35cefce04a9a30
|
||||
|
||||
COCOAPODS: 1.3.1
|
||||
COCOAPODS: 1.5.3
|
||||
|
||||
Generated
+786
-771
File diff suppressed because it is too large
Load Diff
+3
-4
@@ -1,9 +1,8 @@
|
||||
CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/Alamofire
|
||||
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Alamofire
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PODS_TARGET_SRCROOT = ${PODS_ROOT}/Alamofire
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
|
||||
+4
-5
@@ -1,10 +1,9 @@
|
||||
CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/PetstoreClient
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/PromiseKit"
|
||||
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/PromiseKit"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
|
||||
+49
-8
@@ -1,15 +1,28 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
|
||||
# If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
|
||||
# frameworks to, so exit 0 (signalling the script phase was successful).
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
|
||||
COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
|
||||
SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
|
||||
|
||||
# Used as a return value for each invocation of `strip_invalid_archs` function.
|
||||
STRIP_BINARY_RETVAL=0
|
||||
|
||||
# This protects against multiple targets copying the same framework dependency at the same time. The solution
|
||||
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
|
||||
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
|
||||
|
||||
# Copies and strips a vendored framework
|
||||
install_framework()
|
||||
{
|
||||
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
|
||||
@@ -58,21 +71,40 @@ install_framework()
|
||||
fi
|
||||
}
|
||||
|
||||
# Copies the dSYM of a vendored framework
|
||||
# Copies and strips a vendored dSYM
|
||||
install_dsym() {
|
||||
local source="$1"
|
||||
if [ -r "$source" ]; then
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\""
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}"
|
||||
# Copy the dSYM into a the targets temp dir.
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
|
||||
|
||||
local basename
|
||||
basename="$(basename -s .framework.dSYM "$source")"
|
||||
binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
|
||||
|
||||
# Strip invalid architectures so "fat" simulator / device frameworks work on device
|
||||
if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then
|
||||
strip_invalid_archs "$binary"
|
||||
fi
|
||||
|
||||
if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
|
||||
# Move the stripped file into its final destination.
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
|
||||
else
|
||||
# The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
|
||||
touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Signs a framework with the provided identity
|
||||
code_sign_if_enabled() {
|
||||
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
|
||||
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
|
||||
# Use the current code_sign_identitiy
|
||||
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
|
||||
local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'"
|
||||
local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
|
||||
|
||||
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
|
||||
code_sign_cmd="$code_sign_cmd &"
|
||||
@@ -85,10 +117,18 @@ code_sign_if_enabled() {
|
||||
# Strip invalid architectures
|
||||
strip_invalid_archs() {
|
||||
binary="$1"
|
||||
# Get architectures for current file
|
||||
archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
|
||||
# Get architectures for current target binary
|
||||
binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
|
||||
# Intersect them with the architectures we are building for
|
||||
intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
|
||||
# If there are no archs supported by this binary then warn the user
|
||||
if [[ -z "$intersected_archs" ]]; then
|
||||
echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
|
||||
STRIP_BINARY_RETVAL=0
|
||||
return
|
||||
fi
|
||||
stripped=""
|
||||
for arch in $archs; do
|
||||
for arch in $binary_archs; do
|
||||
if ! [[ "${ARCHS}" == *"$arch"* ]]; then
|
||||
# Strip non-valid architectures in-place
|
||||
lipo -remove "$arch" -output "$binary" "$binary" || exit 1
|
||||
@@ -98,6 +138,7 @@ strip_invalid_archs() {
|
||||
if [[ "$stripped" ]]; then
|
||||
echo "Stripped $binary of architectures:$stripped"
|
||||
fi
|
||||
STRIP_BINARY_RETVAL=1
|
||||
}
|
||||
|
||||
|
||||
|
||||
+15
-3
@@ -1,5 +1,13 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then
|
||||
# If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy
|
||||
# resources to, so exit 0 (signalling the script phase was successful).
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
|
||||
@@ -12,7 +20,7 @@ XCASSET_FILES=()
|
||||
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
|
||||
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
|
||||
|
||||
case "${TARGETED_DEVICE_FAMILY}" in
|
||||
case "${TARGETED_DEVICE_FAMILY:-}" in
|
||||
1,2)
|
||||
TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
|
||||
;;
|
||||
@@ -92,7 +100,7 @@ if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
|
||||
fi
|
||||
rm -f "$RESOURCES_TO_COPY"
|
||||
|
||||
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
|
||||
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ]
|
||||
then
|
||||
# Find all other xcassets (this unfortunately includes those of path pods and other targets).
|
||||
OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
|
||||
@@ -102,5 +110,9 @@ then
|
||||
fi
|
||||
done <<<"$OTHER_XCASSETS"
|
||||
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
else
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist"
|
||||
fi
|
||||
fi
|
||||
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient" "$PODS_CONFIGURATION_BUILD_DIR/PromiseKit"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient" "${PODS_CONFIGURATION_BUILD_DIR}/PromiseKit"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient/PetstoreClient.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PromiseKit/PromiseKit.framework/Headers"
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient/PetstoreClient.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/PromiseKit/PromiseKit.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "PetstoreClient" -framework "PromiseKit"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
||||
PODS_ROOT = ${SRCROOT}/Pods
|
||||
|
||||
+4
-4
@@ -1,11 +1,11 @@
|
||||
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient" "$PODS_CONFIGURATION_BUILD_DIR/PromiseKit"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient" "${PODS_CONFIGURATION_BUILD_DIR}/PromiseKit"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient/PetstoreClient.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PromiseKit/PromiseKit.framework/Headers"
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient/PetstoreClient.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/PromiseKit/PromiseKit.framework/Headers"
|
||||
OTHER_LDFLAGS = $(inherited) -framework "Alamofire" -framework "PetstoreClient" -framework "PromiseKit"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
||||
PODS_ROOT = ${SRCROOT}/Pods
|
||||
|
||||
+49
-8
@@ -1,15 +1,28 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
if [ -z ${FRAMEWORKS_FOLDER_PATH+x} ]; then
|
||||
# If FRAMEWORKS_FOLDER_PATH is not set, then there's nowhere for us to copy
|
||||
# frameworks to, so exit 0 (signalling the script phase was successful).
|
||||
exit 0
|
||||
fi
|
||||
|
||||
echo "mkdir -p ${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
mkdir -p "${CONFIGURATION_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}"
|
||||
|
||||
COCOAPODS_PARALLEL_CODE_SIGN="${COCOAPODS_PARALLEL_CODE_SIGN:-false}"
|
||||
SWIFT_STDLIB_PATH="${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}"
|
||||
|
||||
# Used as a return value for each invocation of `strip_invalid_archs` function.
|
||||
STRIP_BINARY_RETVAL=0
|
||||
|
||||
# This protects against multiple targets copying the same framework dependency at the same time. The solution
|
||||
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
|
||||
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
|
||||
|
||||
# Copies and strips a vendored framework
|
||||
install_framework()
|
||||
{
|
||||
if [ -r "${BUILT_PRODUCTS_DIR}/$1" ]; then
|
||||
@@ -58,21 +71,40 @@ install_framework()
|
||||
fi
|
||||
}
|
||||
|
||||
# Copies the dSYM of a vendored framework
|
||||
# Copies and strips a vendored dSYM
|
||||
install_dsym() {
|
||||
local source="$1"
|
||||
if [ -r "$source" ]; then
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DWARF_DSYM_FOLDER_PATH}\""
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DWARF_DSYM_FOLDER_PATH}"
|
||||
# Copy the dSYM into a the targets temp dir.
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${source}\" \"${DERIVED_FILES_DIR}\""
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${source}" "${DERIVED_FILES_DIR}"
|
||||
|
||||
local basename
|
||||
basename="$(basename -s .framework.dSYM "$source")"
|
||||
binary="${DERIVED_FILES_DIR}/${basename}.framework.dSYM/Contents/Resources/DWARF/${basename}"
|
||||
|
||||
# Strip invalid architectures so "fat" simulator / device frameworks work on device
|
||||
if [[ "$(file "$binary")" == *"Mach-O dSYM companion"* ]]; then
|
||||
strip_invalid_archs "$binary"
|
||||
fi
|
||||
|
||||
if [[ $STRIP_BINARY_RETVAL == 1 ]]; then
|
||||
# Move the stripped file into its final destination.
|
||||
echo "rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter \"- CVS/\" --filter \"- .svn/\" --filter \"- .git/\" --filter \"- .hg/\" --filter \"- Headers\" --filter \"- PrivateHeaders\" --filter \"- Modules\" \"${DERIVED_FILES_DIR}/${basename}.framework.dSYM\" \"${DWARF_DSYM_FOLDER_PATH}\""
|
||||
rsync --delete -av "${RSYNC_PROTECT_TMP_FILES[@]}" --filter "- CVS/" --filter "- .svn/" --filter "- .git/" --filter "- .hg/" --filter "- Headers" --filter "- PrivateHeaders" --filter "- Modules" "${DERIVED_FILES_DIR}/${basename}.framework.dSYM" "${DWARF_DSYM_FOLDER_PATH}"
|
||||
else
|
||||
# The dSYM was not stripped at all, in this case touch a fake folder so the input/output paths from Xcode do not reexecute this script because the file is missing.
|
||||
touch "${DWARF_DSYM_FOLDER_PATH}/${basename}.framework.dSYM"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Signs a framework with the provided identity
|
||||
code_sign_if_enabled() {
|
||||
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
|
||||
if [ -n "${EXPANDED_CODE_SIGN_IDENTITY}" -a "${CODE_SIGNING_REQUIRED:-}" != "NO" -a "${CODE_SIGNING_ALLOWED}" != "NO" ]; then
|
||||
# Use the current code_sign_identitiy
|
||||
echo "Code Signing $1 with Identity ${EXPANDED_CODE_SIGN_IDENTITY_NAME}"
|
||||
local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS} --preserve-metadata=identifier,entitlements '$1'"
|
||||
local code_sign_cmd="/usr/bin/codesign --force --sign ${EXPANDED_CODE_SIGN_IDENTITY} ${OTHER_CODE_SIGN_FLAGS:-} --preserve-metadata=identifier,entitlements '$1'"
|
||||
|
||||
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
|
||||
code_sign_cmd="$code_sign_cmd &"
|
||||
@@ -85,10 +117,18 @@ code_sign_if_enabled() {
|
||||
# Strip invalid architectures
|
||||
strip_invalid_archs() {
|
||||
binary="$1"
|
||||
# Get architectures for current file
|
||||
archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | rev)"
|
||||
# Get architectures for current target binary
|
||||
binary_archs="$(lipo -info "$binary" | rev | cut -d ':' -f1 | awk '{$1=$1;print}' | rev)"
|
||||
# Intersect them with the architectures we are building for
|
||||
intersected_archs="$(echo ${ARCHS[@]} ${binary_archs[@]} | tr ' ' '\n' | sort | uniq -d)"
|
||||
# If there are no archs supported by this binary then warn the user
|
||||
if [[ -z "$intersected_archs" ]]; then
|
||||
echo "warning: [CP] Vendored binary '$binary' contains architectures ($binary_archs) none of which match the current build architectures ($ARCHS)."
|
||||
STRIP_BINARY_RETVAL=0
|
||||
return
|
||||
fi
|
||||
stripped=""
|
||||
for arch in $archs; do
|
||||
for arch in $binary_archs; do
|
||||
if ! [[ "${ARCHS}" == *"$arch"* ]]; then
|
||||
# Strip non-valid architectures in-place
|
||||
lipo -remove "$arch" -output "$binary" "$binary" || exit 1
|
||||
@@ -98,6 +138,7 @@ strip_invalid_archs() {
|
||||
if [[ "$stripped" ]]; then
|
||||
echo "Stripped $binary of architectures:$stripped"
|
||||
fi
|
||||
STRIP_BINARY_RETVAL=1
|
||||
}
|
||||
|
||||
if [ "${COCOAPODS_PARALLEL_CODE_SIGN}" == "true" ]; then
|
||||
|
||||
+15
-3
@@ -1,5 +1,13 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
set -u
|
||||
set -o pipefail
|
||||
|
||||
if [ -z ${UNLOCALIZED_RESOURCES_FOLDER_PATH+x} ]; then
|
||||
# If UNLOCALIZED_RESOURCES_FOLDER_PATH is not set, then there's nowhere for us to copy
|
||||
# resources to, so exit 0 (signalling the script phase was successful).
|
||||
exit 0
|
||||
fi
|
||||
|
||||
mkdir -p "${TARGET_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
|
||||
@@ -12,7 +20,7 @@ XCASSET_FILES=()
|
||||
# was originally proposed here: https://lists.samba.org/archive/rsync/2008-February/020158.html
|
||||
RSYNC_PROTECT_TMP_FILES=(--filter "P .*.??????")
|
||||
|
||||
case "${TARGETED_DEVICE_FAMILY}" in
|
||||
case "${TARGETED_DEVICE_FAMILY:-}" in
|
||||
1,2)
|
||||
TARGET_DEVICE_ARGS="--target-device ipad --target-device iphone"
|
||||
;;
|
||||
@@ -92,7 +100,7 @@ if [[ "${ACTION}" == "install" ]] && [[ "${SKIP_INSTALL}" == "NO" ]]; then
|
||||
fi
|
||||
rm -f "$RESOURCES_TO_COPY"
|
||||
|
||||
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "$XCASSET_FILES" ]
|
||||
if [[ -n "${WRAPPER_EXTENSION}" ]] && [ "`xcrun --find actool`" ] && [ -n "${XCASSET_FILES:-}" ]
|
||||
then
|
||||
# Find all other xcassets (this unfortunately includes those of path pods and other targets).
|
||||
OTHER_XCASSETS=$(find "$PWD" -iname "*.xcassets" -type d)
|
||||
@@ -102,5 +110,9 @@ then
|
||||
fi
|
||||
done <<<"$OTHER_XCASSETS"
|
||||
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
if [ -z ${ASSETCATALOG_COMPILER_APPICON_NAME+x} ]; then
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}"
|
||||
else
|
||||
printf "%s\0" "${XCASSET_FILES[@]}" | xargs -0 xcrun actool --output-format human-readable-text --notices --warnings --platform "${PLATFORM_NAME}" --minimum-deployment-target "${!DEPLOYMENT_TARGET_SETTING_NAME}" ${TARGET_DEVICE_ARGS} --compress-pngs --compile "${BUILT_PRODUCTS_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}" --app-icon "${ASSETCATALOG_COMPILER_APPICON_NAME}" --output-partial-info-plist "${TARGET_TEMP_DIR}/assetcatalog_generated_info_cocoapods.plist"
|
||||
fi
|
||||
fi
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient" "$PODS_CONFIGURATION_BUILD_DIR/PromiseKit"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient" "${PODS_CONFIGURATION_BUILD_DIR}/PromiseKit"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient/PetstoreClient.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PromiseKit/PromiseKit.framework/Headers"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient/PetstoreClient.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/PromiseKit/PromiseKit.framework/Headers"
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
||||
PODS_ROOT = ${SRCROOT}/Pods
|
||||
|
||||
+4
-4
@@ -1,8 +1,8 @@
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient" "$PODS_CONFIGURATION_BUILD_DIR/PromiseKit"
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient" "${PODS_CONFIGURATION_BUILD_DIR}/PromiseKit"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
LD_RUNPATH_SEARCH_PATHS = $(inherited) '@executable_path/Frameworks' '@loader_path/Frameworks'
|
||||
OTHER_CFLAGS = $(inherited) -iquote "$PODS_CONFIGURATION_BUILD_DIR/Alamofire/Alamofire.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PetstoreClient/PetstoreClient.framework/Headers" -iquote "$PODS_CONFIGURATION_BUILD_DIR/PromiseKit/PromiseKit.framework/Headers"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
OTHER_CFLAGS = $(inherited) -iquote "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient/PetstoreClient.framework/Headers" -iquote "${PODS_CONFIGURATION_BUILD_DIR}/PromiseKit/PromiseKit.framework/Headers"
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_PODFILE_DIR_PATH = ${SRCROOT}/.
|
||||
PODS_ROOT = ${SRCROOT}/Pods
|
||||
|
||||
+3
-4
@@ -1,10 +1,9 @@
|
||||
CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/PromiseKit
|
||||
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PromiseKit
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
|
||||
OTHER_LDFLAGS = -framework "Foundation"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PODS_TARGET_SRCROOT = ${PODS_ROOT}/PromiseKit
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
|
||||
-48
@@ -148,7 +148,6 @@
|
||||
6D4EFB8E1C692C6300B96B06 /* Frameworks */,
|
||||
6D4EFB8F1C692C6300B96B06 /* Resources */,
|
||||
4485A75250058E2D5BBDF63F /* [CP] Embed Pods Frameworks */,
|
||||
808CE4A0CE801CAC5ABF5B08 /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -167,8 +166,6 @@
|
||||
6D4EFBA11C692C6300B96B06 /* Sources */,
|
||||
6D4EFBA21C692C6300B96B06 /* Frameworks */,
|
||||
6D4EFBA31C692C6300B96B06 /* Resources */,
|
||||
796EAD48F1BCCDAA291CD963 /* [CP] Embed Pods Frameworks */,
|
||||
1652CB1A246A4689869E442D /* [CP] Copy Pods Resources */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
@@ -241,21 +238,6 @@
|
||||
/* End PBXResourcesBuildPhase section */
|
||||
|
||||
/* Begin PBXShellScriptBuildPhase section */
|
||||
1652CB1A246A4689869E442D /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwaggerClientTests/Pods-SwaggerClientTests-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
1F03F780DC2D9727E5E64BA9 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -296,21 +278,6 @@
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwaggerClient/Pods-SwaggerClient-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
796EAD48F1BCCDAA291CD963 /* [CP] Embed Pods Frameworks */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwaggerClientTests/Pods-SwaggerClientTests-frameworks.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
79FE27B09B2DD354C831BD49 /* [CP] Check Pods Manifest.lock */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
@@ -329,21 +296,6 @@
|
||||
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
808CE4A0CE801CAC5ABF5B08 /* [CP] Copy Pods Resources */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
name = "[CP] Copy Pods Resources";
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-SwaggerClient/Pods-SwaggerClient-resources.sh\"\n";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
|
||||
@@ -1 +1 @@
|
||||
3.0.1-SNAPSHOT
|
||||
3.2.0-SNAPSHOT
|
||||
+4
-4
@@ -357,8 +357,8 @@ open class FakeAPI: APIBase {
|
||||
* enum for parameter enumHeaderStringArray
|
||||
*/
|
||||
public enum EnumHeaderStringArray_testEnumParameters: String {
|
||||
case greaterThan = ">"
|
||||
case dollar = "$"
|
||||
case greaterThan = "">""
|
||||
case dollar = ""$""
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -374,8 +374,8 @@ open class FakeAPI: APIBase {
|
||||
* enum for parameter enumQueryStringArray
|
||||
*/
|
||||
public enum EnumQueryStringArray_testEnumParameters: String {
|
||||
case greaterThan = ">"
|
||||
case dollar = "$"
|
||||
case greaterThan = "">""
|
||||
case dollar = ""$""
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+1
@@ -44,6 +44,7 @@ open class FakeClassnameTags123API: APIBase {
|
||||
/**
|
||||
To test class name in snake case
|
||||
- PATCH /fake_classname_test
|
||||
- To test class name in snake case
|
||||
- API Key:
|
||||
- type: apiKey api_key_query (QUERY)
|
||||
- name: api_key_query
|
||||
|
||||
+3
-3
@@ -127,9 +127,9 @@ open class PetAPI: APIBase {
|
||||
* enum for parameter status
|
||||
*/
|
||||
public enum Status_findPetsByStatus: String {
|
||||
case available = "available"
|
||||
case pending = "pending"
|
||||
case sold = "sold"
|
||||
case available = ""available""
|
||||
case pending = ""pending""
|
||||
case sold = ""sold""
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+2
-2
@@ -15,8 +15,8 @@ open class EnumArrays: JSONEncodable {
|
||||
case dollar = "$"
|
||||
}
|
||||
public enum ArrayEnum: String {
|
||||
case fish = "fish"
|
||||
case crab = "crab"
|
||||
case fish = ""fish""
|
||||
case crab = ""crab""
|
||||
}
|
||||
public var justSymbol: JustSymbol?
|
||||
public var arrayEnum: [ArrayEnum]?
|
||||
|
||||
+2
-2
@@ -11,8 +11,8 @@ import Foundation
|
||||
open class MapTest: JSONEncodable {
|
||||
|
||||
public enum MapOfEnumString: String {
|
||||
case upper = "UPPER"
|
||||
case lower = "lower"
|
||||
case upper = ""UPPER""
|
||||
case lower = ""lower""
|
||||
}
|
||||
public var mapMapOfString: [String:[String:String]]?
|
||||
public var mapOfEnumString: [String:String]?
|
||||
|
||||
@@ -2,21 +2,26 @@ PODS:
|
||||
- Alamofire (4.5.0)
|
||||
- PetstoreClient (0.0.1):
|
||||
- Alamofire (~> 4.5.0)
|
||||
- RxSwift (~> 3.4.1)
|
||||
- RxSwift (3.4.1)
|
||||
- RxSwift (= 3.6.1)
|
||||
- RxSwift (3.6.1)
|
||||
|
||||
DEPENDENCIES:
|
||||
- PetstoreClient (from `../`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/cocoapods/specs.git:
|
||||
- Alamofire
|
||||
- RxSwift
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
PetstoreClient:
|
||||
:path: ../
|
||||
:path: "../"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: f28cdffd29de33a7bfa022cbd63ae95a27fae140
|
||||
PetstoreClient: 89ba1ed13b6653200cc34a2248644e7e6a142b60
|
||||
RxSwift: 656f8fbeca5bc372121a72d9ebdd3cd3bc0ffade
|
||||
PetstoreClient: 8c4d20911bfd9f88418b64c1f141c8a47ab85e60
|
||||
RxSwift: f9de85ea20cd2f7716ee5409fc13523dc638e4e4
|
||||
|
||||
PODFILE CHECKSUM: 417049e9ed0e4680602b34d838294778389bd418
|
||||
|
||||
COCOAPODS: 1.3.1
|
||||
COCOAPODS: 1.5.3
|
||||
|
||||
+5
-4
@@ -2,21 +2,22 @@
|
||||
"name": "PetstoreClient",
|
||||
"platforms": {
|
||||
"ios": "9.0",
|
||||
"osx": "10.11"
|
||||
"osx": "10.11",
|
||||
"tvos": "9.0"
|
||||
},
|
||||
"version": "0.0.1",
|
||||
"source": {
|
||||
"git": "git@github.com:swagger-api/swagger-mustache.git",
|
||||
"git": "git@github.com:openapitools/openapi-generator.git",
|
||||
"tag": "v1.0.0"
|
||||
},
|
||||
"authors": "",
|
||||
"license": "Proprietary",
|
||||
"homepage": "https://github.com/swagger-api/swagger-codegen",
|
||||
"homepage": "https://github.com/openapitools/openapi-generator",
|
||||
"summary": "PetstoreClient",
|
||||
"source_files": "PetstoreClient/Classes/**/*.swift",
|
||||
"dependencies": {
|
||||
"RxSwift": [
|
||||
"~> 3.4.1"
|
||||
"3.6.1"
|
||||
],
|
||||
"Alamofire": [
|
||||
"~> 4.5.0"
|
||||
|
||||
+11
-6
@@ -2,21 +2,26 @@ PODS:
|
||||
- Alamofire (4.5.0)
|
||||
- PetstoreClient (0.0.1):
|
||||
- Alamofire (~> 4.5.0)
|
||||
- RxSwift (~> 3.4.1)
|
||||
- RxSwift (3.4.1)
|
||||
- RxSwift (= 3.6.1)
|
||||
- RxSwift (3.6.1)
|
||||
|
||||
DEPENDENCIES:
|
||||
- PetstoreClient (from `../`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/cocoapods/specs.git:
|
||||
- Alamofire
|
||||
- RxSwift
|
||||
|
||||
EXTERNAL SOURCES:
|
||||
PetstoreClient:
|
||||
:path: ../
|
||||
:path: "../"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
Alamofire: f28cdffd29de33a7bfa022cbd63ae95a27fae140
|
||||
PetstoreClient: 89ba1ed13b6653200cc34a2248644e7e6a142b60
|
||||
RxSwift: 656f8fbeca5bc372121a72d9ebdd3cd3bc0ffade
|
||||
PetstoreClient: 8c4d20911bfd9f88418b64c1f141c8a47ab85e60
|
||||
RxSwift: f9de85ea20cd2f7716ee5409fc13523dc638e4e4
|
||||
|
||||
PODFILE CHECKSUM: 417049e9ed0e4680602b34d838294778389bd418
|
||||
|
||||
COCOAPODS: 1.3.1
|
||||
COCOAPODS: 1.5.3
|
||||
|
||||
Generated
+1384
-1369
File diff suppressed because it is too large
Load Diff
+9
-6
@@ -3,12 +3,6 @@
|
||||
|
||||
[](https://travis-ci.org/ReactiveX/RxSwift)   [](https://github.com/Carthage/Carthage) [](https://github.com/apple/swift-package-manager)
|
||||
|
||||
## About Rx
|
||||
|
||||
**:warning: This readme describes RxSwift 3.0 version that requires Swift 3.0.**
|
||||
|
||||
**:warning: If you are looking for Swift 2.3 compatible version, please take a look at RxSwift ~> 2.0 versions and [swift-2.3](https://github.com/ReactiveX/RxSwift/tree/rxswift-2.0) branch.**
|
||||
|
||||
Rx is a [generic abstraction of computation](https://youtu.be/looJcaeboBY) expressed through `Observable<Element>` interface.
|
||||
|
||||
This is a Swift version of [Rx](https://github.com/Reactive-Extensions/Rx.NET).
|
||||
@@ -110,6 +104,7 @@ searchResults
|
||||
|
||||
* Xcode 8.0
|
||||
* Swift 3.0
|
||||
* Swift 2.3 ([use `rxswift-2.0` branch](https://github.com/ReactiveX/RxSwift/tree/rxswift-2.0) instead)
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -183,6 +178,12 @@ let package = Package(
|
||||
$ swift build
|
||||
```
|
||||
|
||||
To build or test a module with RxTest dependency, set `TEST=1`. ([RxSwift >= 3.4.2](https://github.com/ReactiveX/RxSwift/releases/tag/3.4.2))
|
||||
|
||||
```bash
|
||||
$ TEST=1 swift test
|
||||
```
|
||||
|
||||
### Manually using git submodules
|
||||
|
||||
* Add RxSwift as a submodule
|
||||
@@ -199,6 +200,8 @@ $ git submodule add git@github.com:ReactiveX/RxSwift.git
|
||||
|
||||
* [http://reactivex.io/](http://reactivex.io/)
|
||||
* [Reactive Extensions GitHub (GitHub)](https://github.com/Reactive-Extensions)
|
||||
* [RxSwift RayWenderlich.com Book](https://store.raywenderlich.com/products/rxswift)
|
||||
* [Boxue.io RxSwift Online Course](https://boxueio.com/series/rxswift-101) (Chinese 🇨🇳)
|
||||
* [Erik Meijer (Wikipedia)](http://en.wikipedia.org/wiki/Erik_Meijer_%28computer_scientist%29)
|
||||
* [Expert to Expert: Brian Beckman and Erik Meijer - Inside the .NET Reactive Framework (Rx) (video)](https://youtu.be/looJcaeboBY)
|
||||
* [Reactive Programming Overview (Jafar Husain from Netflix)](https://www.youtube.com/watch?v=dwP1TNXE6fc)
|
||||
|
||||
Generated
+3
-3
@@ -13,7 +13,7 @@ let RxCompositeFailures = "RxCompositeFailures"
|
||||
public enum RxError
|
||||
: Swift.Error
|
||||
, CustomDebugStringConvertible {
|
||||
/// Unknown error occured.
|
||||
/// Unknown error occurred.
|
||||
case unknown
|
||||
/// Performing an action on disposed object.
|
||||
case disposed(object: AnyObject)
|
||||
@@ -34,11 +34,11 @@ extension RxError {
|
||||
public var debugDescription: String {
|
||||
switch self {
|
||||
case .unknown:
|
||||
return "Unknown error occured."
|
||||
return "Unknown error occurred."
|
||||
case .disposed(let object):
|
||||
return "Object `\(object)` was already disposed."
|
||||
case .overflow:
|
||||
return "Arithmetic overflow occured."
|
||||
return "Arithmetic overflow occurred."
|
||||
case .argumentOutOfRange:
|
||||
return "Argument out of range."
|
||||
case .noElements:
|
||||
|
||||
+1
-1
@@ -9,7 +9,7 @@
|
||||
/// Represents an object that immediately schedules units of work.
|
||||
public protocol ImmediateSchedulerType {
|
||||
/**
|
||||
Schedules an action to be executed immediatelly.
|
||||
Schedules an action to be executed immediately.
|
||||
|
||||
- parameter state: State passed to the action to be executed.
|
||||
- parameter action: Action to be executed.
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
/// Type that can be converted to observable sequence (`Observer<E>`).
|
||||
/// Type that can be converted to observable sequence (`Observable<E>`).
|
||||
public protocol ObservableConvertibleType {
|
||||
/// Type of elements in sequence.
|
||||
associatedtype E
|
||||
|
||||
+82
-73
@@ -22,90 +22,99 @@ extension ObservableType {
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
/**
|
||||
Subscribes an element handler, an error handler, a completion handler and disposed handler to an observable sequence.
|
||||
/**
|
||||
Subscribes an element handler, an error handler, a completion handler and disposed handler to an observable sequence.
|
||||
|
||||
- parameter onNext: Action to invoke for each element in the observable sequence.
|
||||
- parameter onError: Action to invoke upon errored termination of the observable sequence.
|
||||
- parameter onCompleted: Action to invoke upon graceful termination of the observable sequence.
|
||||
- parameter onDisposed: Action to invoke upon any type of termination of sequence (if the sequence has
|
||||
gracefully completed, errored, or if the generation is cancelled by disposing subscription).
|
||||
- returns: Subscription object used to unsubscribe from the observable sequence.
|
||||
*/
|
||||
public func subscribe(file: String = #file, line: UInt = #line, function: String = #function, onNext: ((E) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil)
|
||||
-> Disposable {
|
||||
- parameter onNext: Action to invoke for each element in the observable sequence.
|
||||
- parameter onError: Action to invoke upon errored termination of the observable sequence.
|
||||
- parameter onCompleted: Action to invoke upon graceful termination of the observable sequence.
|
||||
- parameter onDisposed: Action to invoke upon any type of termination of sequence (if the sequence has
|
||||
gracefully completed, errored, or if the generation is canceled by disposing subscription).
|
||||
- returns: Subscription object used to unsubscribe from the observable sequence.
|
||||
*/
|
||||
public func subscribe(file: String = #file, line: UInt = #line, function: String = #function, onNext: ((E) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil)
|
||||
-> Disposable {
|
||||
|
||||
let disposable: Disposable
|
||||
let disposable: Disposable
|
||||
|
||||
if let disposed = onDisposed {
|
||||
disposable = Disposables.create(with: disposed)
|
||||
}
|
||||
else {
|
||||
disposable = Disposables.create()
|
||||
}
|
||||
|
||||
let observer = AnonymousObserver<E> { e in
|
||||
switch e {
|
||||
case .next(let value):
|
||||
onNext?(value)
|
||||
case .error(let e):
|
||||
if let onError = onError {
|
||||
onError(e)
|
||||
}
|
||||
else {
|
||||
print("Received unhandled error: \(file):\(line):\(function) -> \(e)")
|
||||
}
|
||||
disposable.dispose()
|
||||
case .completed:
|
||||
onCompleted?()
|
||||
disposable.dispose()
|
||||
if let disposed = onDisposed {
|
||||
disposable = Disposables.create(with: disposed)
|
||||
}
|
||||
else {
|
||||
disposable = Disposables.create()
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
let _synchronizationTracker = SynchronizationTracker()
|
||||
#endif
|
||||
|
||||
let observer = AnonymousObserver<E> { e in
|
||||
#if DEBUG
|
||||
_synchronizationTracker.register(synchronizationErrorMessage: .default)
|
||||
defer { _synchronizationTracker.unregister() }
|
||||
#endif
|
||||
|
||||
switch e {
|
||||
case .next(let value):
|
||||
onNext?(value)
|
||||
case .error(let e):
|
||||
if let onError = onError {
|
||||
onError(e)
|
||||
}
|
||||
else {
|
||||
print("Received unhandled error: \(file):\(line):\(function) -> \(e)")
|
||||
}
|
||||
disposable.dispose()
|
||||
case .completed:
|
||||
onCompleted?()
|
||||
disposable.dispose()
|
||||
}
|
||||
}
|
||||
return Disposables.create(
|
||||
self.subscribeSafe(observer),
|
||||
disposable
|
||||
)
|
||||
}
|
||||
return Disposables.create(
|
||||
self.subscribeSafe(observer),
|
||||
disposable
|
||||
)
|
||||
}
|
||||
#else
|
||||
/**
|
||||
Subscribes an element handler, an error handler, a completion handler and disposed handler to an observable sequence.
|
||||
/**
|
||||
Subscribes an element handler, an error handler, a completion handler and disposed handler to an observable sequence.
|
||||
|
||||
- parameter onNext: Action to invoke for each element in the observable sequence.
|
||||
- parameter onError: Action to invoke upon errored termination of the observable sequence.
|
||||
- parameter onCompleted: Action to invoke upon graceful termination of the observable sequence.
|
||||
- parameter onDisposed: Action to invoke upon any type of termination of sequence (if the sequence has
|
||||
gracefully completed, errored, or if the generation is cancelled by disposing subscription).
|
||||
- returns: Subscription object used to unsubscribe from the observable sequence.
|
||||
*/
|
||||
public func subscribe(onNext: ((E) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil)
|
||||
-> Disposable {
|
||||
- parameter onNext: Action to invoke for each element in the observable sequence.
|
||||
- parameter onError: Action to invoke upon errored termination of the observable sequence.
|
||||
- parameter onCompleted: Action to invoke upon graceful termination of the observable sequence.
|
||||
- parameter onDisposed: Action to invoke upon any type of termination of sequence (if the sequence has
|
||||
gracefully completed, errored, or if the generation is canceled by disposing subscription).
|
||||
- returns: Subscription object used to unsubscribe from the observable sequence.
|
||||
*/
|
||||
public func subscribe(onNext: ((E) -> Void)? = nil, onError: ((Swift.Error) -> Void)? = nil, onCompleted: (() -> Void)? = nil, onDisposed: (() -> Void)? = nil)
|
||||
-> Disposable {
|
||||
|
||||
let disposable: Disposable
|
||||
let disposable: Disposable
|
||||
|
||||
if let disposed = onDisposed {
|
||||
disposable = Disposables.create(with: disposed)
|
||||
}
|
||||
else {
|
||||
disposable = Disposables.create()
|
||||
}
|
||||
|
||||
let observer = AnonymousObserver<E> { e in
|
||||
switch e {
|
||||
case .next(let value):
|
||||
onNext?(value)
|
||||
case .error(let e):
|
||||
onError?(e)
|
||||
disposable.dispose()
|
||||
case .completed:
|
||||
onCompleted?()
|
||||
disposable.dispose()
|
||||
if let disposed = onDisposed {
|
||||
disposable = Disposables.create(with: disposed)
|
||||
}
|
||||
else {
|
||||
disposable = Disposables.create()
|
||||
}
|
||||
|
||||
let observer = AnonymousObserver<E> { e in
|
||||
switch e {
|
||||
case .next(let value):
|
||||
onNext?(value)
|
||||
case .error(let e):
|
||||
onError?(e)
|
||||
disposable.dispose()
|
||||
case .completed:
|
||||
onCompleted?()
|
||||
disposable.dispose()
|
||||
}
|
||||
}
|
||||
return Disposables.create(
|
||||
self.subscribeSafe(observer),
|
||||
disposable
|
||||
)
|
||||
}
|
||||
return Disposables.create(
|
||||
self.subscribeSafe(observer),
|
||||
disposable
|
||||
)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Generated
+1
-1
@@ -29,7 +29,7 @@ public protocol ObservableType : ObservableConvertibleType {
|
||||
When sequence sends `Complete` or `Error` event all internal resources that compute sequence elements
|
||||
will be freed.
|
||||
|
||||
To cancel production of sequence elements and free resources immediatelly, call `dispose` on returned
|
||||
To cancel production of sequence elements and free resources immediately, call `dispose` on returned
|
||||
subscription.
|
||||
|
||||
- returns: Subscription for `observer` that can be used to cancel production of sequence elements and free resources.
|
||||
|
||||
+1
@@ -128,3 +128,4 @@ final fileprivate class Concat<S: Sequence> : Producer<S.Iterator.Element.E> whe
|
||||
return (sink: sink, subscription: subscription)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-129
@@ -1,129 +0,0 @@
|
||||
//
|
||||
// ConnectableObservable.swift
|
||||
// RxSwift
|
||||
//
|
||||
// Created by Krunoslav Zaher on 3/1/15.
|
||||
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
extension ObservableType {
|
||||
|
||||
/**
|
||||
Multicasts the source sequence notifications through the specified subject to the resulting connectable observable.
|
||||
|
||||
Upon connection of the connectable observable, the subject is subscribed to the source exactly one, and messages are forwarded to the observers registered with the connectable observable.
|
||||
|
||||
For specializations with fixed subject types, see `publish` and `replay`.
|
||||
|
||||
- seealso: [multicast operator on reactivex.io](http://reactivex.io/documentation/operators/publish.html)
|
||||
|
||||
- parameter subject: Subject to push source elements into.
|
||||
- returns: A connectable observable sequence that upon connection causes the source sequence to push results into the specified subject.
|
||||
*/
|
||||
public func multicast<S: SubjectType>(_ subject: S)
|
||||
-> ConnectableObservable<S.E> where S.SubjectObserverType.E == E {
|
||||
return ConnectableObservableAdapter(source: self.asObservable(), subject: subject)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
Represents an observable wrapper that can be connected and disconnected from its underlying observable sequence.
|
||||
*/
|
||||
public class ConnectableObservable<Element>
|
||||
: Observable<Element>
|
||||
, ConnectableObservableType {
|
||||
|
||||
/**
|
||||
Connects the observable wrapper to its source. All subscribed observers will receive values from the underlying observable sequence as long as the connection is established.
|
||||
|
||||
- returns: Disposable used to disconnect the observable wrapper from its source, causing subscribed observer to stop receiving values from the underlying observable sequence.
|
||||
*/
|
||||
public func connect() -> Disposable {
|
||||
rxAbstractMethod()
|
||||
}
|
||||
}
|
||||
|
||||
final class Connection<S: SubjectType> : ObserverType, Disposable {
|
||||
typealias E = S.SubjectObserverType.E
|
||||
|
||||
private var _lock: RecursiveLock
|
||||
// state
|
||||
private var _parent: ConnectableObservableAdapter<S>?
|
||||
private var _subscription : Disposable?
|
||||
private var _subjectObserver: S.SubjectObserverType
|
||||
|
||||
private var _disposed: Bool = false
|
||||
|
||||
init(parent: ConnectableObservableAdapter<S>, subjectObserver: S.SubjectObserverType, lock: RecursiveLock, subscription: Disposable) {
|
||||
_parent = parent
|
||||
_subscription = subscription
|
||||
_lock = lock
|
||||
_subjectObserver = subjectObserver
|
||||
}
|
||||
|
||||
func on(_ event: Event<S.SubjectObserverType.E>) {
|
||||
if _disposed {
|
||||
return
|
||||
}
|
||||
_subjectObserver.on(event)
|
||||
if event.isStopEvent {
|
||||
self.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
func dispose() {
|
||||
_lock.lock(); defer { _lock.unlock() } // {
|
||||
_disposed = true
|
||||
guard let parent = _parent else {
|
||||
return
|
||||
}
|
||||
|
||||
if parent._connection === self {
|
||||
parent._connection = nil
|
||||
}
|
||||
_parent = nil
|
||||
|
||||
_subscription?.dispose()
|
||||
_subscription = nil
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
final class ConnectableObservableAdapter<S: SubjectType>
|
||||
: ConnectableObservable<S.E> {
|
||||
typealias ConnectionType = Connection<S>
|
||||
|
||||
fileprivate let _subject: S
|
||||
fileprivate let _source: Observable<S.SubjectObserverType.E>
|
||||
|
||||
fileprivate let _lock = RecursiveLock()
|
||||
|
||||
// state
|
||||
fileprivate var _connection: ConnectionType?
|
||||
|
||||
init(source: Observable<S.SubjectObserverType.E>, subject: S) {
|
||||
_source = source
|
||||
_subject = subject
|
||||
_connection = nil
|
||||
}
|
||||
|
||||
override func connect() -> Disposable {
|
||||
return _lock.calculateLocked {
|
||||
if let connection = _connection {
|
||||
return connection
|
||||
}
|
||||
|
||||
let singleAssignmentDisposable = SingleAssignmentDisposable()
|
||||
let connection = Connection(parent: self, subjectObserver: _subject.asObserver(), lock: _lock, subscription: singleAssignmentDisposable)
|
||||
_connection = connection
|
||||
let subscription = _source.subscribe(connection)
|
||||
singleAssignmentDisposable.setDisposable(subscription)
|
||||
return connection
|
||||
}
|
||||
}
|
||||
|
||||
override func subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == S.E {
|
||||
return _subject.subscribe(observer)
|
||||
}
|
||||
}
|
||||
+3
-8
@@ -30,7 +30,7 @@ final fileprivate class AnonymousObservableSink<O: ObserverType> : Sink<O>, Obse
|
||||
private var _isStopped: AtomicInt = 0
|
||||
|
||||
#if DEBUG
|
||||
fileprivate var _numberOfConcurrentCalls: AtomicInt = 0
|
||||
fileprivate let _synchronizationTracker = SynchronizationTracker()
|
||||
#endif
|
||||
|
||||
override init(observer: O, cancel: Cancelable) {
|
||||
@@ -39,13 +39,8 @@ final fileprivate class AnonymousObservableSink<O: ObserverType> : Sink<O>, Obse
|
||||
|
||||
func on(_ event: Event<E>) {
|
||||
#if DEBUG
|
||||
if AtomicIncrement(&_numberOfConcurrentCalls) > 1 {
|
||||
rxFatalError("Warning: Recursive call or synchronization error!")
|
||||
}
|
||||
|
||||
defer {
|
||||
_ = AtomicDecrement(&_numberOfConcurrentCalls)
|
||||
}
|
||||
_synchronizationTracker.register(synchronizationErrorMessage: .default)
|
||||
defer { _synchronizationTracker.unregister() }
|
||||
#endif
|
||||
switch event {
|
||||
case .next:
|
||||
|
||||
+1
-1
@@ -57,7 +57,7 @@ final fileprivate class DelaySink<O: ObserverType>
|
||||
}
|
||||
|
||||
// All of these complications in this method are caused by the fact that
|
||||
// error should be propagated immediatelly. Error can bepotentially received on different
|
||||
// error should be propagated immediately. Error can be potentially received on different
|
||||
// scheduler so this process needs to be synchronized somehow.
|
||||
//
|
||||
// Another complication is that scheduler is potentially concurrent so internal queue is used.
|
||||
|
||||
Generated
+6
-6
@@ -37,18 +37,18 @@ extension ObservableType {
|
||||
|
||||
final fileprivate class DoSink<O: ObserverType> : Sink<O>, ObserverType {
|
||||
typealias Element = O.E
|
||||
typealias Parent = Do<Element>
|
||||
typealias EventHandler = (Event<Element>) throws -> Void
|
||||
|
||||
private let _parent: Parent
|
||||
private let _eventHandler: EventHandler
|
||||
|
||||
init(parent: Parent, observer: O, cancel: Cancelable) {
|
||||
_parent = parent
|
||||
init(eventHandler: @escaping EventHandler, observer: O, cancel: Cancelable) {
|
||||
_eventHandler = eventHandler
|
||||
super.init(observer: observer, cancel: cancel)
|
||||
}
|
||||
|
||||
func on(_ event: Event<Element>) {
|
||||
do {
|
||||
try _parent._eventHandler(event)
|
||||
try _eventHandler(event)
|
||||
forwardOn(event)
|
||||
if event.isStopEvent {
|
||||
dispose()
|
||||
@@ -80,7 +80,7 @@ final fileprivate class Do<Element> : Producer<Element> {
|
||||
|
||||
override func run<O: ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == Element {
|
||||
_onSubscribe?()
|
||||
let sink = DoSink(parent: self, observer: observer, cancel: cancel)
|
||||
let sink = DoSink(eventHandler: _eventHandler, observer: observer, cancel: cancel)
|
||||
let subscription = _source.subscribe(sink)
|
||||
_onSubscribed?()
|
||||
let onDispose = _onDispose
|
||||
|
||||
+194
-107
@@ -131,13 +131,30 @@ extension Observable {
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate final class MergeLimitedSinkIter<S: ObservableConvertibleType, O: ObserverType>
|
||||
// MARK: concatMap
|
||||
|
||||
extension ObservableType {
|
||||
/**
|
||||
Projects each element of an observable sequence to an observable sequence and concatenates the resulting observable sequences into one observable sequence.
|
||||
|
||||
- seealso: [concat operator on reactivex.io](http://reactivex.io/documentation/operators/concat.html)
|
||||
|
||||
- returns: An observable sequence that contains the elements of each observed inner sequence, in sequential order.
|
||||
*/
|
||||
|
||||
public func concatMap<O: ObservableConvertibleType>(_ selector: @escaping (E) throws -> O)
|
||||
-> Observable<O.E> {
|
||||
return ConcatMap(source: asObservable(), selector: selector)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate final class MergeLimitedSinkIter<SourceElement, SourceSequence: ObservableConvertibleType, Observer: ObserverType>
|
||||
: ObserverType
|
||||
, LockOwnerType
|
||||
, SynchronizedOnType where S.E == O.E {
|
||||
typealias E = O.E
|
||||
, SynchronizedOnType where SourceSequence.E == Observer.E {
|
||||
typealias E = Observer.E
|
||||
typealias DisposeKey = CompositeDisposable.DisposeKey
|
||||
typealias Parent = MergeLimitedSink<S, O>
|
||||
typealias Parent = MergeLimitedSink<SourceElement, SourceSequence, Observer>
|
||||
|
||||
private let _parent: Parent
|
||||
private let _disposeKey: DisposeKey
|
||||
@@ -179,13 +196,32 @@ fileprivate final class MergeLimitedSinkIter<S: ObservableConvertibleType, O: Ob
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate final class MergeLimitedSink<S: ObservableConvertibleType, O: ObserverType>
|
||||
: Sink<O>
|
||||
, ObserverType
|
||||
, LockOwnerType
|
||||
, SynchronizedOnType where S.E == O.E {
|
||||
typealias E = S
|
||||
typealias QueueType = Queue<S>
|
||||
fileprivate final class ConcatMapSink<SourceElement, SourceSequence: ObservableConvertibleType, Observer: ObserverType>: MergeLimitedSink<SourceElement, SourceSequence, Observer> where Observer.E == SourceSequence.E {
|
||||
typealias Selector = (SourceElement) throws -> SourceSequence
|
||||
|
||||
private let _selector: Selector
|
||||
|
||||
init(selector: @escaping Selector, observer: Observer, cancel: Cancelable) {
|
||||
_selector = selector
|
||||
super.init(maxConcurrent: 1, observer: observer, cancel: cancel)
|
||||
}
|
||||
|
||||
override func performMap(_ element: SourceElement) throws -> SourceSequence {
|
||||
return try _selector(element)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate final class MergeLimitedBasicSink<SourceSequence: ObservableConvertibleType, Observer: ObserverType>: MergeLimitedSink<SourceSequence, SourceSequence, Observer> where Observer.E == SourceSequence.E {
|
||||
|
||||
override func performMap(_ element: SourceSequence) throws -> SourceSequence {
|
||||
return element
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate class MergeLimitedSink<SourceElement, SourceSequence: ObservableConvertibleType, Observer: ObserverType>
|
||||
: Sink<Observer>
|
||||
, ObserverType where Observer.E == SourceSequence.E {
|
||||
typealias QueueType = Queue<SourceSequence>
|
||||
|
||||
let _maxConcurrent: Int
|
||||
|
||||
@@ -199,14 +235,14 @@ fileprivate final class MergeLimitedSink<S: ObservableConvertibleType, O: Observ
|
||||
let _sourceSubscription = SingleAssignmentDisposable()
|
||||
let _group = CompositeDisposable()
|
||||
|
||||
init(maxConcurrent: Int, observer: O, cancel: Cancelable) {
|
||||
init(maxConcurrent: Int, observer: Observer, cancel: Cancelable) {
|
||||
_maxConcurrent = maxConcurrent
|
||||
|
||||
let _ = _group.insert(_sourceSubscription)
|
||||
super.init(observer: observer, cancel: cancel)
|
||||
}
|
||||
|
||||
func run(_ source: Observable<S>) -> Disposable {
|
||||
func run(_ source: Observable<SourceElement>) -> Disposable {
|
||||
let _ = _group.insert(_sourceSubscription)
|
||||
|
||||
let disposable = source.subscribe(self)
|
||||
@@ -214,7 +250,7 @@ fileprivate final class MergeLimitedSink<S: ObservableConvertibleType, O: Observ
|
||||
return _group
|
||||
}
|
||||
|
||||
func subscribe(_ innerSource: E, group: CompositeDisposable) {
|
||||
func subscribe(_ innerSource: SourceSequence, group: CompositeDisposable) {
|
||||
let subscription = SingleAssignmentDisposable()
|
||||
|
||||
let key = group.insert(subscription)
|
||||
@@ -227,30 +263,56 @@ fileprivate final class MergeLimitedSink<S: ObservableConvertibleType, O: Observ
|
||||
}
|
||||
}
|
||||
|
||||
func on(_ event: Event<E>) {
|
||||
synchronizedOn(event)
|
||||
func performMap(_ element: SourceElement) throws -> SourceSequence {
|
||||
rxAbstractMethod()
|
||||
}
|
||||
|
||||
func _synchronized_on(_ event: Event<E>) {
|
||||
switch event {
|
||||
case .next(let value):
|
||||
@inline(__always)
|
||||
final private func nextElementArrived(element: SourceElement) -> SourceSequence? {
|
||||
_lock.lock(); defer { _lock.unlock() } // {
|
||||
let subscribe: Bool
|
||||
if _activeCount < _maxConcurrent {
|
||||
_activeCount += 1
|
||||
subscribe = true
|
||||
}
|
||||
else {
|
||||
_queue.enqueue(value)
|
||||
do {
|
||||
let value = try performMap(element)
|
||||
_queue.enqueue(value)
|
||||
} catch {
|
||||
forwardOn(.error(error))
|
||||
dispose()
|
||||
}
|
||||
subscribe = false
|
||||
}
|
||||
|
||||
if subscribe {
|
||||
self.subscribe(value, group: _group)
|
||||
do {
|
||||
return try performMap(element)
|
||||
} catch {
|
||||
forwardOn(.error(error))
|
||||
dispose()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
// }
|
||||
}
|
||||
|
||||
func on(_ event: Event<SourceElement>) {
|
||||
switch event {
|
||||
case .next(let element):
|
||||
if let sequence = self.nextElementArrived(element: element) {
|
||||
self.subscribe(sequence, group: _group)
|
||||
}
|
||||
case .error(let error):
|
||||
_lock.lock(); defer { _lock.unlock() }
|
||||
|
||||
forwardOn(.error(error))
|
||||
dispose()
|
||||
case .completed:
|
||||
_lock.lock(); defer { _lock.unlock() }
|
||||
|
||||
if _activeCount == 0 {
|
||||
forwardOn(.completed)
|
||||
dispose()
|
||||
@@ -264,17 +326,17 @@ fileprivate final class MergeLimitedSink<S: ObservableConvertibleType, O: Observ
|
||||
}
|
||||
}
|
||||
|
||||
final fileprivate class MergeLimited<S: ObservableConvertibleType> : Producer<S.E> {
|
||||
private let _source: Observable<S>
|
||||
final fileprivate class MergeLimited<SourceSequence: ObservableConvertibleType> : Producer<SourceSequence.E> {
|
||||
private let _source: Observable<SourceSequence>
|
||||
private let _maxConcurrent: Int
|
||||
|
||||
init(source: Observable<S>, maxConcurrent: Int) {
|
||||
init(source: Observable<SourceSequence>, maxConcurrent: Int) {
|
||||
_source = source
|
||||
_maxConcurrent = maxConcurrent
|
||||
}
|
||||
|
||||
override func run<O: ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == S.E {
|
||||
let sink = MergeLimitedSink<S, O>(maxConcurrent: _maxConcurrent, observer: observer, cancel: cancel)
|
||||
override func run<O: ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == SourceSequence.E {
|
||||
let sink = MergeLimitedBasicSink<SourceSequence, O>(maxConcurrent: _maxConcurrent, observer: observer, cancel: cancel)
|
||||
let subscription = sink.run(_source)
|
||||
return (sink: sink, subscription: subscription)
|
||||
}
|
||||
@@ -283,10 +345,6 @@ final fileprivate class MergeLimited<S: ObservableConvertibleType> : Producer<S.
|
||||
// MARK: Merge
|
||||
|
||||
fileprivate final class MergeBasicSink<S: ObservableConvertibleType, O: ObserverType> : MergeSink<S, S, O> where O.E == S.E {
|
||||
override init(observer: O, cancel: Cancelable) {
|
||||
super.init(observer: observer, cancel: cancel)
|
||||
}
|
||||
|
||||
override func performMap(_ element: S) throws -> S {
|
||||
return element
|
||||
}
|
||||
@@ -294,41 +352,41 @@ fileprivate final class MergeBasicSink<S: ObservableConvertibleType, O: Observer
|
||||
|
||||
// MARK: flatMap
|
||||
|
||||
fileprivate final class FlatMapSink<SourceType, S: ObservableConvertibleType, O: ObserverType> : MergeSink<SourceType, S, O> where O.E == S.E {
|
||||
typealias Selector = (SourceType) throws -> S
|
||||
fileprivate final class FlatMapSink<SourceElement, SourceSequence: ObservableConvertibleType, Observer: ObserverType> : MergeSink<SourceElement, SourceSequence, Observer> where Observer.E == SourceSequence.E {
|
||||
typealias Selector = (SourceElement) throws -> SourceSequence
|
||||
|
||||
private let _selector: Selector
|
||||
|
||||
init(selector: @escaping Selector, observer: O, cancel: Cancelable) {
|
||||
init(selector: @escaping Selector, observer: Observer, cancel: Cancelable) {
|
||||
_selector = selector
|
||||
super.init(observer: observer, cancel: cancel)
|
||||
}
|
||||
|
||||
override func performMap(_ element: SourceType) throws -> S {
|
||||
override func performMap(_ element: SourceElement) throws -> SourceSequence {
|
||||
return try _selector(element)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate final class FlatMapWithIndexSink<SourceType, S: ObservableConvertibleType, O: ObserverType> : MergeSink<SourceType, S, O> where O.E == S.E {
|
||||
typealias Selector = (SourceType, Int) throws -> S
|
||||
fileprivate final class FlatMapWithIndexSink<SourceElement, SourceSequence: ObservableConvertibleType, Observer: ObserverType> : MergeSink<SourceElement, SourceSequence, Observer> where Observer.E == SourceSequence.E {
|
||||
typealias Selector = (SourceElement, Int) throws -> SourceSequence
|
||||
|
||||
private var _index = 0
|
||||
private let _selector: Selector
|
||||
|
||||
init(selector: @escaping Selector, observer: O, cancel: Cancelable) {
|
||||
init(selector: @escaping Selector, observer: Observer, cancel: Cancelable) {
|
||||
_selector = selector
|
||||
super.init(observer: observer, cancel: cancel)
|
||||
}
|
||||
|
||||
override func performMap(_ element: SourceType) throws -> S {
|
||||
override func performMap(_ element: SourceElement) throws -> SourceSequence {
|
||||
return try _selector(element, try incrementChecked(&_index))
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: FlatMapFirst
|
||||
|
||||
fileprivate final class FlatMapFirstSink<SourceType, S: ObservableConvertibleType, O: ObserverType> : MergeSink<SourceType, S, O> where O.E == S.E {
|
||||
typealias Selector = (SourceType) throws -> S
|
||||
fileprivate final class FlatMapFirstSink<SourceElement, SourceSequence: ObservableConvertibleType, Observer: ObserverType> : MergeSink<SourceElement, SourceSequence, Observer> where Observer.E == SourceSequence.E {
|
||||
typealias Selector = (SourceElement) throws -> SourceSequence
|
||||
|
||||
private let _selector: Selector
|
||||
|
||||
@@ -336,20 +394,20 @@ fileprivate final class FlatMapFirstSink<SourceType, S: ObservableConvertibleTyp
|
||||
return _activeCount == 0
|
||||
}
|
||||
|
||||
init(selector: @escaping Selector, observer: O, cancel: Cancelable) {
|
||||
init(selector: @escaping Selector, observer: Observer, cancel: Cancelable) {
|
||||
_selector = selector
|
||||
super.init(observer: observer, cancel: cancel)
|
||||
}
|
||||
|
||||
override func performMap(_ element: SourceType) throws -> S {
|
||||
override func performMap(_ element: SourceElement) throws -> SourceSequence {
|
||||
return try _selector(element)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate final class MergeSinkIter<SourceType, S: ObservableConvertibleType, O: ObserverType> : ObserverType where O.E == S.E {
|
||||
typealias Parent = MergeSink<SourceType, S, O>
|
||||
fileprivate final class MergeSinkIter<SourceElement, SourceSequence: ObservableConvertibleType, Observer: ObserverType> : ObserverType where Observer.E == SourceSequence.E {
|
||||
typealias Parent = MergeSink<SourceElement, SourceSequence, Observer>
|
||||
typealias DisposeKey = CompositeDisposable.DisposeKey
|
||||
typealias E = O.E
|
||||
typealias E = Observer.E
|
||||
|
||||
private let _parent: Parent
|
||||
private let _disposeKey: DisposeKey
|
||||
@@ -377,11 +435,11 @@ fileprivate final class MergeSinkIter<SourceType, S: ObservableConvertibleType,
|
||||
}
|
||||
|
||||
|
||||
fileprivate class MergeSink<SourceType, S: ObservableConvertibleType, O: ObserverType>
|
||||
: Sink<O>
|
||||
, ObserverType where O.E == S.E {
|
||||
typealias ResultType = O.E
|
||||
typealias Element = SourceType
|
||||
fileprivate class MergeSink<SourceElement, SourceSequence: ObservableConvertibleType, Observer: ObserverType>
|
||||
: Sink<Observer>
|
||||
, ObserverType where Observer.E == SourceSequence.E {
|
||||
typealias ResultType = Observer.E
|
||||
typealias Element = SourceElement
|
||||
|
||||
let _lock = RecursiveLock()
|
||||
|
||||
@@ -396,55 +454,66 @@ fileprivate class MergeSink<SourceType, S: ObservableConvertibleType, O: Observe
|
||||
var _activeCount = 0
|
||||
var _stopped = false
|
||||
|
||||
override init(observer: O, cancel: Cancelable) {
|
||||
override init(observer: Observer, cancel: Cancelable) {
|
||||
super.init(observer: observer, cancel: cancel)
|
||||
}
|
||||
|
||||
func performMap(_ element: SourceType) throws -> S {
|
||||
func performMap(_ element: SourceElement) throws -> SourceSequence {
|
||||
rxAbstractMethod()
|
||||
}
|
||||
|
||||
func on(_ event: Event<SourceType>) {
|
||||
_lock.lock(); defer { _lock.unlock() } // lock {
|
||||
switch event {
|
||||
case .next(let element):
|
||||
if !subscribeNext {
|
||||
return
|
||||
}
|
||||
do {
|
||||
let value = try performMap(element)
|
||||
subscribeInner(value.asObservable())
|
||||
}
|
||||
catch let e {
|
||||
forwardOn(.error(e))
|
||||
dispose()
|
||||
}
|
||||
case .error(let error):
|
||||
forwardOn(.error(error))
|
||||
dispose()
|
||||
case .completed:
|
||||
_stopped = true
|
||||
_sourceSubscription.dispose()
|
||||
checkCompleted()
|
||||
|
||||
@inline(__always)
|
||||
final private func nextElementArrived(element: SourceElement) -> SourceSequence? {
|
||||
_lock.lock(); defer { _lock.unlock() } // {
|
||||
if !subscribeNext {
|
||||
return nil
|
||||
}
|
||||
//}
|
||||
|
||||
do {
|
||||
let value = try performMap(element)
|
||||
_activeCount += 1
|
||||
return value
|
||||
}
|
||||
catch let e {
|
||||
forwardOn(.error(e))
|
||||
dispose()
|
||||
return nil
|
||||
}
|
||||
// }
|
||||
}
|
||||
|
||||
func on(_ event: Event<SourceElement>) {
|
||||
switch event {
|
||||
case .next(let element):
|
||||
if let value = nextElementArrived(element: element) {
|
||||
subscribeInner(value.asObservable())
|
||||
}
|
||||
case .error(let error):
|
||||
_lock.lock(); defer { _lock.unlock() }
|
||||
forwardOn(.error(error))
|
||||
dispose()
|
||||
case .completed:
|
||||
_lock.lock(); defer { _lock.unlock() }
|
||||
_stopped = true
|
||||
_sourceSubscription.dispose()
|
||||
checkCompleted()
|
||||
}
|
||||
}
|
||||
|
||||
func subscribeInner(_ source: Observable<O.E>) {
|
||||
func subscribeInner(_ source: Observable<Observer.E>) {
|
||||
let iterDisposable = SingleAssignmentDisposable()
|
||||
if let disposeKey = _group.insert(iterDisposable) {
|
||||
_activeCount += 1
|
||||
let iter = MergeSinkIter(parent: self, disposeKey: disposeKey)
|
||||
let subscription = source.subscribe(iter)
|
||||
iterDisposable.setDisposable(subscription)
|
||||
}
|
||||
}
|
||||
|
||||
func run(_ sources: [SourceType]) -> Disposable {
|
||||
let _ = _group.insert(_sourceSubscription)
|
||||
func run(_ sources: [Observable<Observer.E>]) -> Disposable {
|
||||
_activeCount += sources.count
|
||||
|
||||
for source in sources {
|
||||
self.on(.next(source))
|
||||
subscribeInner(source)
|
||||
}
|
||||
|
||||
_stopped = true
|
||||
@@ -462,7 +531,7 @@ fileprivate class MergeSink<SourceType, S: ObservableConvertibleType, O: Observe
|
||||
}
|
||||
}
|
||||
|
||||
func run(_ source: Observable<SourceType>) -> Disposable {
|
||||
func run(_ source: Observable<SourceElement>) -> Disposable {
|
||||
let _ = _group.insert(_sourceSubscription)
|
||||
|
||||
let subscription = source.subscribe(self)
|
||||
@@ -474,82 +543,100 @@ fileprivate class MergeSink<SourceType, S: ObservableConvertibleType, O: Observe
|
||||
|
||||
// MARK: Producers
|
||||
|
||||
final fileprivate class FlatMap<SourceType, S: ObservableConvertibleType>: Producer<S.E> {
|
||||
typealias Selector = (SourceType) throws -> S
|
||||
final fileprivate class FlatMap<SourceElement, SourceSequence: ObservableConvertibleType>: Producer<SourceSequence.E> {
|
||||
typealias Selector = (SourceElement) throws -> SourceSequence
|
||||
|
||||
private let _source: Observable<SourceType>
|
||||
private let _source: Observable<SourceElement>
|
||||
|
||||
private let _selector: Selector
|
||||
|
||||
init(source: Observable<SourceType>, selector: @escaping Selector) {
|
||||
init(source: Observable<SourceElement>, selector: @escaping Selector) {
|
||||
_source = source
|
||||
_selector = selector
|
||||
}
|
||||
|
||||
override func run<O: ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == S.E {
|
||||
override func run<O: ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == SourceSequence.E {
|
||||
let sink = FlatMapSink(selector: _selector, observer: observer, cancel: cancel)
|
||||
let subscription = sink.run(_source)
|
||||
return (sink: sink, subscription: subscription)
|
||||
}
|
||||
}
|
||||
|
||||
final fileprivate class FlatMapWithIndex<SourceType, S: ObservableConvertibleType>: Producer<S.E> {
|
||||
typealias Selector = (SourceType, Int) throws -> S
|
||||
final fileprivate class FlatMapWithIndex<SourceElement, SourceSequence: ObservableConvertibleType>: Producer<SourceSequence.E> {
|
||||
typealias Selector = (SourceElement, Int) throws -> SourceSequence
|
||||
|
||||
private let _source: Observable<SourceType>
|
||||
private let _source: Observable<SourceElement>
|
||||
|
||||
private let _selector: Selector
|
||||
|
||||
init(source: Observable<SourceType>, selector: @escaping Selector) {
|
||||
init(source: Observable<SourceElement>, selector: @escaping Selector) {
|
||||
_source = source
|
||||
_selector = selector
|
||||
}
|
||||
|
||||
override func run<O: ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == S.E {
|
||||
let sink = FlatMapWithIndexSink<SourceType, S, O>(selector: _selector, observer: observer, cancel: cancel)
|
||||
override func run<O: ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == SourceSequence.E {
|
||||
let sink = FlatMapWithIndexSink<SourceElement, SourceSequence, O>(selector: _selector, observer: observer, cancel: cancel)
|
||||
let subscription = sink.run(_source)
|
||||
return (sink: sink, subscription: subscription)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
final fileprivate class FlatMapFirst<SourceType, S: ObservableConvertibleType>: Producer<S.E> {
|
||||
typealias Selector = (SourceType) throws -> S
|
||||
final fileprivate class FlatMapFirst<SourceElement, SourceSequence: ObservableConvertibleType>: Producer<SourceSequence.E> {
|
||||
typealias Selector = (SourceElement) throws -> SourceSequence
|
||||
|
||||
private let _source: Observable<SourceType>
|
||||
private let _source: Observable<SourceElement>
|
||||
|
||||
private let _selector: Selector
|
||||
|
||||
init(source: Observable<SourceType>, selector: @escaping Selector) {
|
||||
init(source: Observable<SourceElement>, selector: @escaping Selector) {
|
||||
_source = source
|
||||
_selector = selector
|
||||
}
|
||||
|
||||
override func run<O: ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == S.E {
|
||||
let sink = FlatMapFirstSink<SourceType, S, O>(selector: _selector, observer: observer, cancel: cancel)
|
||||
override func run<O: ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == SourceSequence.E {
|
||||
let sink = FlatMapFirstSink<SourceElement, SourceSequence, O>(selector: _selector, observer: observer, cancel: cancel)
|
||||
let subscription = sink.run(_source)
|
||||
return (sink: sink, subscription: subscription)
|
||||
}
|
||||
}
|
||||
|
||||
final fileprivate class Merge<S: ObservableConvertibleType> : Producer<S.E> {
|
||||
private let _source: Observable<S>
|
||||
final class ConcatMap<SourceElement, SourceSequence: ObservableConvertibleType>: Producer<SourceSequence.E> {
|
||||
typealias Selector = (SourceElement) throws -> SourceSequence
|
||||
|
||||
private let _source: Observable<SourceElement>
|
||||
private let _selector: Selector
|
||||
|
||||
init(source: Observable<SourceElement>, selector: @escaping Selector) {
|
||||
_source = source
|
||||
_selector = selector
|
||||
}
|
||||
|
||||
override func run<O: ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == SourceSequence.E {
|
||||
let sink = ConcatMapSink<SourceElement, SourceSequence, O>(selector: _selector, observer: observer, cancel: cancel)
|
||||
let subscription = sink.run(_source)
|
||||
return (sink: sink, subscription: subscription)
|
||||
}
|
||||
}
|
||||
|
||||
init(source: Observable<S>) {
|
||||
final class Merge<SourceSequence: ObservableConvertibleType> : Producer<SourceSequence.E> {
|
||||
private let _source: Observable<SourceSequence>
|
||||
|
||||
init(source: Observable<SourceSequence>) {
|
||||
_source = source
|
||||
}
|
||||
|
||||
override func run<O: ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == S.E {
|
||||
let sink = MergeBasicSink<S, O>(observer: observer, cancel: cancel)
|
||||
override func run<O: ObserverType>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O.E == SourceSequence.E {
|
||||
let sink = MergeBasicSink<SourceSequence, O>(observer: observer, cancel: cancel)
|
||||
let subscription = sink.run(_source)
|
||||
return (sink: sink, subscription: subscription)
|
||||
}
|
||||
}
|
||||
|
||||
final fileprivate class MergeArray<E> : Producer<E> {
|
||||
private let _sources: [Observable<E>]
|
||||
final fileprivate class MergeArray<Element> : Producer<Element> {
|
||||
private let _sources: [Observable<Element>]
|
||||
|
||||
init(sources: [Observable<E>]) {
|
||||
init(sources: [Observable<Element>]) {
|
||||
_sources = sources
|
||||
}
|
||||
|
||||
|
||||
+175
-2
@@ -6,6 +6,23 @@
|
||||
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
/**
|
||||
Represents an observable wrapper that can be connected and disconnected from its underlying observable sequence.
|
||||
*/
|
||||
public class ConnectableObservable<Element>
|
||||
: Observable<Element>
|
||||
, ConnectableObservableType {
|
||||
|
||||
/**
|
||||
Connects the observable wrapper to its source. All subscribed observers will receive values from the underlying observable sequence as long as the connection is established.
|
||||
|
||||
- returns: Disposable used to disconnect the observable wrapper from its source, causing subscribed observer to stop receiving values from the underlying observable sequence.
|
||||
*/
|
||||
public func connect() -> Disposable {
|
||||
rxAbstractMethod()
|
||||
}
|
||||
}
|
||||
|
||||
extension ObservableType {
|
||||
|
||||
/**
|
||||
@@ -109,6 +126,140 @@ extension ObservableType {
|
||||
}
|
||||
}
|
||||
|
||||
extension ObservableType {
|
||||
|
||||
/**
|
||||
Multicasts the source sequence notifications through the specified subject to the resulting connectable observable.
|
||||
|
||||
Upon connection of the connectable observable, the subject is subscribed to the source exactly one, and messages are forwarded to the observers registered with the connectable observable.
|
||||
|
||||
For specializations with fixed subject types, see `publish` and `replay`.
|
||||
|
||||
- seealso: [multicast operator on reactivex.io](http://reactivex.io/documentation/operators/publish.html)
|
||||
|
||||
- parameter subject: Subject to push source elements into.
|
||||
- returns: A connectable observable sequence that upon connection causes the source sequence to push results into the specified subject.
|
||||
*/
|
||||
public func multicast<S: SubjectType>(_ subject: S)
|
||||
-> ConnectableObservable<S.E> where S.SubjectObserverType.E == E {
|
||||
return ConnectableObservableAdapter(source: self.asObservable(), makeSubject: { subject })
|
||||
}
|
||||
|
||||
/**
|
||||
Multicasts the source sequence notifications through an instantiated subject to the resulting connectable observable.
|
||||
|
||||
Upon connection of the connectable observable, the subject is subscribed to the source exactly one, and messages are forwarded to the observers registered with the connectable observable.
|
||||
|
||||
Subject is cleared on connection disposal or in case source sequence produces terminal event.
|
||||
|
||||
- seealso: [multicast operator on reactivex.io](http://reactivex.io/documentation/operators/publish.html)
|
||||
|
||||
- parameter makeSubject: Factory function used to instantiate a subject for each connection.
|
||||
- returns: A connectable observable sequence that upon connection causes the source sequence to push results into the specified subject.
|
||||
*/
|
||||
public func multicast<S: SubjectType>(makeSubject: @escaping () -> S)
|
||||
-> ConnectableObservable<S.E> where S.SubjectObserverType.E == E {
|
||||
return ConnectableObservableAdapter(source: self.asObservable(), makeSubject: makeSubject)
|
||||
}
|
||||
}
|
||||
|
||||
final fileprivate class Connection<S: SubjectType> : ObserverType, Disposable {
|
||||
typealias E = S.SubjectObserverType.E
|
||||
|
||||
private var _lock: RecursiveLock
|
||||
// state
|
||||
private var _parent: ConnectableObservableAdapter<S>?
|
||||
private var _subscription : Disposable?
|
||||
private var _subjectObserver: S.SubjectObserverType
|
||||
|
||||
private var _disposed: Bool = false
|
||||
|
||||
init(parent: ConnectableObservableAdapter<S>, subjectObserver: S.SubjectObserverType, lock: RecursiveLock, subscription: Disposable) {
|
||||
_parent = parent
|
||||
_subscription = subscription
|
||||
_lock = lock
|
||||
_subjectObserver = subjectObserver
|
||||
}
|
||||
|
||||
func on(_ event: Event<S.SubjectObserverType.E>) {
|
||||
if _disposed {
|
||||
return
|
||||
}
|
||||
if event.isStopEvent {
|
||||
self.dispose()
|
||||
}
|
||||
_subjectObserver.on(event)
|
||||
}
|
||||
|
||||
func dispose() {
|
||||
_lock.lock(); defer { _lock.unlock() } // {
|
||||
_disposed = true
|
||||
guard let parent = _parent else {
|
||||
return
|
||||
}
|
||||
|
||||
if parent._connection === self {
|
||||
parent._connection = nil
|
||||
parent._subject = nil
|
||||
}
|
||||
_parent = nil
|
||||
|
||||
_subscription?.dispose()
|
||||
_subscription = nil
|
||||
// }
|
||||
}
|
||||
}
|
||||
|
||||
final fileprivate class ConnectableObservableAdapter<S: SubjectType>
|
||||
: ConnectableObservable<S.E> {
|
||||
typealias ConnectionType = Connection<S>
|
||||
|
||||
fileprivate let _source: Observable<S.SubjectObserverType.E>
|
||||
fileprivate let _makeSubject: () -> S
|
||||
|
||||
fileprivate let _lock = RecursiveLock()
|
||||
fileprivate var _subject: S?
|
||||
|
||||
// state
|
||||
fileprivate var _connection: ConnectionType?
|
||||
|
||||
init(source: Observable<S.SubjectObserverType.E>, makeSubject: @escaping () -> S) {
|
||||
_source = source
|
||||
_makeSubject = makeSubject
|
||||
_subject = nil
|
||||
_connection = nil
|
||||
}
|
||||
|
||||
override func connect() -> Disposable {
|
||||
return _lock.calculateLocked {
|
||||
if let connection = _connection {
|
||||
return connection
|
||||
}
|
||||
|
||||
let singleAssignmentDisposable = SingleAssignmentDisposable()
|
||||
let connection = Connection(parent: self, subjectObserver: self.lazySubject.asObserver(), lock: _lock, subscription: singleAssignmentDisposable)
|
||||
_connection = connection
|
||||
let subscription = _source.subscribe(connection)
|
||||
singleAssignmentDisposable.setDisposable(subscription)
|
||||
return connection
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate var lazySubject: S {
|
||||
if let subject = self._subject {
|
||||
return subject
|
||||
}
|
||||
|
||||
let subject = _makeSubject()
|
||||
self._subject = subject
|
||||
return subject
|
||||
}
|
||||
|
||||
override func subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == S.E {
|
||||
return self.lazySubject.subscribe(observer)
|
||||
}
|
||||
}
|
||||
|
||||
final fileprivate class RefCountSink<CO: ConnectableObservableType, O: ObserverType>
|
||||
: Sink<O>
|
||||
, ObserverType where CO.E == O.E {
|
||||
@@ -117,6 +268,8 @@ final fileprivate class RefCountSink<CO: ConnectableObservableType, O: ObserverT
|
||||
|
||||
private let _parent: Parent
|
||||
|
||||
private var _connectionIdSnapshot: Int64 = -1
|
||||
|
||||
init(parent: Parent, observer: O, cancel: Cancelable) {
|
||||
_parent = parent
|
||||
super.init(observer: observer, cancel: cancel)
|
||||
@@ -124,8 +277,14 @@ final fileprivate class RefCountSink<CO: ConnectableObservableType, O: ObserverT
|
||||
|
||||
func run() -> Disposable {
|
||||
let subscription = _parent._source.subscribe(self)
|
||||
|
||||
_parent._lock.lock(); defer { _parent._lock.unlock() } // {
|
||||
|
||||
_connectionIdSnapshot = _parent._connectionId
|
||||
|
||||
if self.disposed {
|
||||
return Disposables.create()
|
||||
}
|
||||
|
||||
if _parent._count == 0 {
|
||||
_parent._count = 1
|
||||
_parent._connectableSubscription = _parent._source.connect()
|
||||
@@ -138,6 +297,9 @@ final fileprivate class RefCountSink<CO: ConnectableObservableType, O: ObserverT
|
||||
return Disposables.create {
|
||||
subscription.dispose()
|
||||
self._parent._lock.lock(); defer { self._parent._lock.unlock() } // {
|
||||
if self._parent._connectionId != self._connectionIdSnapshot {
|
||||
return
|
||||
}
|
||||
if self._parent._count == 1 {
|
||||
self._parent._count = 0
|
||||
guard let connectableSubscription = self._parent._connectableSubscription else {
|
||||
@@ -162,6 +324,16 @@ final fileprivate class RefCountSink<CO: ConnectableObservableType, O: ObserverT
|
||||
case .next:
|
||||
forwardOn(event)
|
||||
case .error, .completed:
|
||||
_parent._lock.lock() // {
|
||||
if _parent._connectionId == self._connectionIdSnapshot {
|
||||
let connection = _parent._connectableSubscription
|
||||
defer { connection?.dispose() }
|
||||
_parent._count = 0
|
||||
_parent._connectionId = _parent._connectionId &+ 1
|
||||
_parent._connectableSubscription = nil
|
||||
}
|
||||
// }
|
||||
_parent._lock.unlock()
|
||||
forwardOn(event)
|
||||
dispose()
|
||||
}
|
||||
@@ -173,6 +345,7 @@ final fileprivate class RefCount<CO: ConnectableObservableType>: Producer<CO.E>
|
||||
|
||||
// state
|
||||
fileprivate var _count = 0
|
||||
fileprivate var _connectionId: Int64 = 0
|
||||
fileprivate var _connectableSubscription = nil as Disposable?
|
||||
|
||||
fileprivate let _source: CO
|
||||
@@ -203,7 +376,7 @@ final fileprivate class MulticastSink<S: SubjectType, O: ObserverType>: Sink<O>,
|
||||
func run() -> Disposable {
|
||||
do {
|
||||
let subject = try _parent._subjectSelector()
|
||||
let connectable = ConnectableObservableAdapter(source: _parent._source, subject: subject)
|
||||
let connectable = ConnectableObservableAdapter(source: _parent._source, makeSubject: { subject })
|
||||
|
||||
let observable = try _parent._selector(connectable)
|
||||
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@ extension Observable {
|
||||
- seealso: [from operator on reactivex.io](http://reactivex.io/documentation/operators/from.html)
|
||||
|
||||
- parameter elements: Elements to generate.
|
||||
- parameter scheduler: Scheduler to send elements on. If `nil`, elements are sent immediatelly on subscription.
|
||||
- parameter scheduler: Scheduler to send elements on. If `nil`, elements are sent immediately on subscription.
|
||||
- returns: The observable sequence whose elements are pulled from the given arguments.
|
||||
*/
|
||||
public static func of(_ elements: E ..., scheduler: ImmediateSchedulerType = CurrentThreadScheduler.instance) -> Observable<E> {
|
||||
|
||||
-127
@@ -1,127 +0,0 @@
|
||||
//
|
||||
// ShareReplay1.swift
|
||||
// RxSwift
|
||||
//
|
||||
// Created by Krunoslav Zaher on 10/10/15.
|
||||
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
extension ObservableType {
|
||||
|
||||
/**
|
||||
Returns an observable sequence that shares a single subscription to the underlying sequence, and immediately upon subscription replays maximum number of elements in buffer.
|
||||
|
||||
This operator is a specialization of replay which creates a subscription when the number of observers goes from zero to one, then shares that subscription with all subsequent observers until the number of observers returns to zero, at which point the subscription is disposed.
|
||||
|
||||
- seealso: [shareReplay operator on reactivex.io](http://reactivex.io/documentation/operators/replay.html)
|
||||
|
||||
- parameter bufferSize: Maximum element count of the replay buffer.
|
||||
- returns: An observable sequence that contains the elements of a sequence produced by multicasting the source sequence.
|
||||
*/
|
||||
public func shareReplay(_ bufferSize: Int)
|
||||
-> Observable<E> {
|
||||
if bufferSize == 1 {
|
||||
return ShareReplay1(source: self.asObservable())
|
||||
}
|
||||
else {
|
||||
return self.replay(bufferSize).refCount()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// optimized version of share replay for most common case
|
||||
final fileprivate class ShareReplay1<Element>
|
||||
: Observable<Element>
|
||||
, ObserverType
|
||||
, SynchronizedUnsubscribeType {
|
||||
|
||||
typealias Observers = AnyObserver<Element>.s
|
||||
typealias DisposeKey = Observers.KeyType
|
||||
|
||||
private let _source: Observable<Element>
|
||||
|
||||
private let _lock = RecursiveLock()
|
||||
|
||||
private var _connection: SingleAssignmentDisposable?
|
||||
private var _element: Element?
|
||||
private var _stopped = false
|
||||
private var _stopEvent = nil as Event<Element>?
|
||||
private var _observers = Observers()
|
||||
|
||||
init(source: Observable<Element>) {
|
||||
self._source = source
|
||||
}
|
||||
|
||||
override func subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == E {
|
||||
_lock.lock()
|
||||
let result = _synchronized_subscribe(observer)
|
||||
_lock.unlock()
|
||||
return result
|
||||
}
|
||||
|
||||
func _synchronized_subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == E {
|
||||
if let element = self._element {
|
||||
observer.on(.next(element))
|
||||
}
|
||||
|
||||
if let stopEvent = self._stopEvent {
|
||||
observer.on(stopEvent)
|
||||
return Disposables.create()
|
||||
}
|
||||
|
||||
let initialCount = self._observers.count
|
||||
|
||||
let disposeKey = self._observers.insert(observer.on)
|
||||
|
||||
if initialCount == 0 {
|
||||
let connection = SingleAssignmentDisposable()
|
||||
_connection = connection
|
||||
|
||||
connection.setDisposable(self._source.subscribe(self))
|
||||
}
|
||||
|
||||
return SubscriptionDisposable(owner: self, key: disposeKey)
|
||||
}
|
||||
|
||||
func synchronizedUnsubscribe(_ disposeKey: DisposeKey) {
|
||||
_lock.lock()
|
||||
_synchronized_unsubscribe(disposeKey)
|
||||
_lock.unlock()
|
||||
}
|
||||
|
||||
func _synchronized_unsubscribe(_ disposeKey: DisposeKey) {
|
||||
// if already unsubscribed, just return
|
||||
if self._observers.removeKey(disposeKey) == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if _observers.count == 0 {
|
||||
_connection?.dispose()
|
||||
_connection = nil
|
||||
}
|
||||
}
|
||||
|
||||
func on(_ event: Event<E>) {
|
||||
dispatch(_synchronized_on(event), event)
|
||||
}
|
||||
|
||||
func _synchronized_on(_ event: Event<E>) -> Observers {
|
||||
_lock.lock(); defer { _lock.unlock() }
|
||||
if _stopped {
|
||||
return Observers()
|
||||
}
|
||||
|
||||
switch event {
|
||||
case .next(let element):
|
||||
_element = element
|
||||
case .error, .completed:
|
||||
_stopEvent = event
|
||||
_stopped = true
|
||||
_connection?.dispose()
|
||||
_connection = nil
|
||||
}
|
||||
|
||||
return _observers
|
||||
}
|
||||
|
||||
}
|
||||
-175
@@ -1,175 +0,0 @@
|
||||
//
|
||||
// ShareReplay1WhileConnected.swift
|
||||
// RxSwift
|
||||
//
|
||||
// Created by Krunoslav Zaher on 12/6/15.
|
||||
// Copyright © 2015 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
extension ObservableType {
|
||||
|
||||
/**
|
||||
Returns an observable sequence that shares a single subscription to the underlying sequence, and immediately upon subscription replays latest element in buffer.
|
||||
|
||||
This operator is a specialization of replay which creates a subscription when the number of observers goes from zero to one, then shares that subscription with all subsequent observers until the number of observers returns to zero, at which point the subscription is disposed.
|
||||
|
||||
Unlike `shareReplay(bufferSize: Int)`, this operator will clear latest element from replay buffer in case number of subscribers drops from one to zero. In case sequence
|
||||
completes or errors out replay buffer is also cleared.
|
||||
|
||||
- seealso: [shareReplay operator on reactivex.io](http://reactivex.io/documentation/operators/replay.html)
|
||||
|
||||
- returns: An observable sequence that contains the elements of a sequence produced by multicasting the source sequence.
|
||||
*/
|
||||
public func shareReplayLatestWhileConnected()
|
||||
-> Observable<E> {
|
||||
return ShareReplay1WhileConnected(source: self.asObservable())
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate final class ShareReplay1WhileConnectedConnection<Element>
|
||||
: ObserverType
|
||||
, SynchronizedUnsubscribeType {
|
||||
typealias E = Element
|
||||
typealias Observers = AnyObserver<Element>.s
|
||||
typealias DisposeKey = Observers.KeyType
|
||||
|
||||
typealias Parent = ShareReplay1WhileConnected<Element>
|
||||
private let _parent: Parent
|
||||
private let _subscription = SingleAssignmentDisposable()
|
||||
|
||||
private let _lock: RecursiveLock
|
||||
private var _disposed: Bool = false
|
||||
fileprivate var _observers = Observers()
|
||||
fileprivate var _element: Element?
|
||||
|
||||
init(parent: Parent, lock: RecursiveLock) {
|
||||
_parent = parent
|
||||
_lock = lock
|
||||
|
||||
#if TRACE_RESOURCES
|
||||
_ = Resources.incrementTotal()
|
||||
#endif
|
||||
}
|
||||
|
||||
final func on(_ event: Event<E>) {
|
||||
_lock.lock()
|
||||
let observers = _synchronized_on(event)
|
||||
_lock.unlock()
|
||||
dispatch(observers, event)
|
||||
}
|
||||
|
||||
final private func _synchronized_on(_ event: Event<E>) -> Observers {
|
||||
if _disposed {
|
||||
return Observers()
|
||||
}
|
||||
|
||||
switch event {
|
||||
case .next(let element):
|
||||
_element = element
|
||||
return _observers
|
||||
case .error, .completed:
|
||||
let observers = _observers
|
||||
self._synchronized_dispose()
|
||||
return observers
|
||||
}
|
||||
}
|
||||
|
||||
final func connect() {
|
||||
_subscription.setDisposable(_parent._source.subscribe(self))
|
||||
}
|
||||
|
||||
final func _synchronized_subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == Element {
|
||||
_lock.lock(); defer { _lock.unlock() }
|
||||
if let element = _element {
|
||||
observer.on(.next(element))
|
||||
}
|
||||
|
||||
let disposeKey = _observers.insert(observer.on)
|
||||
|
||||
return SubscriptionDisposable(owner: self, key: disposeKey)
|
||||
}
|
||||
|
||||
final private func _synchronized_dispose() {
|
||||
_disposed = true
|
||||
if _parent._connection === self {
|
||||
_parent._connection = nil
|
||||
}
|
||||
_observers = Observers()
|
||||
_subscription.dispose()
|
||||
}
|
||||
|
||||
final func synchronizedUnsubscribe(_ disposeKey: DisposeKey) {
|
||||
_lock.lock()
|
||||
_synchronized_unsubscribe(disposeKey)
|
||||
_lock.unlock()
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
final private func _synchronized_unsubscribe(_ disposeKey: DisposeKey) {
|
||||
// if already unsubscribed, just return
|
||||
if self._observers.removeKey(disposeKey) == nil {
|
||||
return
|
||||
}
|
||||
|
||||
if _observers.count == 0 {
|
||||
_synchronized_dispose()
|
||||
}
|
||||
}
|
||||
|
||||
#if TRACE_RESOURCES
|
||||
deinit {
|
||||
_ = Resources.decrementTotal()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// optimized version of share replay for most common case
|
||||
final fileprivate class ShareReplay1WhileConnected<Element>
|
||||
: Observable<Element> {
|
||||
|
||||
fileprivate typealias Connection = ShareReplay1WhileConnectedConnection<Element>
|
||||
|
||||
fileprivate let _source: Observable<Element>
|
||||
|
||||
fileprivate let _lock = RecursiveLock()
|
||||
|
||||
fileprivate var _connection: Connection?
|
||||
|
||||
init(source: Observable<Element>) {
|
||||
self._source = source
|
||||
}
|
||||
|
||||
override func subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == E {
|
||||
_lock.lock()
|
||||
|
||||
let connection = _synchronized_subscribe(observer)
|
||||
let count = connection._observers.count
|
||||
|
||||
let disposable = connection._synchronized_subscribe(observer)
|
||||
|
||||
if count == 0 {
|
||||
connection.connect()
|
||||
}
|
||||
|
||||
_lock.unlock()
|
||||
|
||||
return disposable
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
private func _synchronized_subscribe<O : ObserverType>(_ observer: O) -> Connection where O.E == E {
|
||||
let connection: Connection
|
||||
|
||||
if let existingConnection = _connection {
|
||||
connection = existingConnection
|
||||
}
|
||||
else {
|
||||
connection = ShareReplay1WhileConnectedConnection<Element>(
|
||||
parent: self,
|
||||
lock: _lock)
|
||||
_connection = connection
|
||||
}
|
||||
|
||||
return connection
|
||||
}
|
||||
}
|
||||
+496
@@ -0,0 +1,496 @@
|
||||
//
|
||||
// ShareReplayScope.swift
|
||||
// RxSwift
|
||||
//
|
||||
// Created by Krunoslav Zaher on 5/28/17.
|
||||
// Copyright © 2017 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
/// Subject lifetime scope
|
||||
public enum SubjectLifetimeScope {
|
||||
/**
|
||||
**Each connection will have it's own subject instance to store replay events.**
|
||||
**Connections will be isolated from each another.**
|
||||
|
||||
Configures the underlying implementation to behave equivalent to.
|
||||
|
||||
```
|
||||
source.multicast(makeSubject: { MySubject() }).refCount()
|
||||
```
|
||||
|
||||
**This is the recommended default.**
|
||||
|
||||
This has the following consequences:
|
||||
* `retry` or `concat` operators will function as expected because terminating the sequence will clear internal state.
|
||||
* Each connection to source observable sequence will use it's own subject.
|
||||
* When the number of subscribers drops from 1 to 0 and connection to source sequence is disposed, subject will be cleared.
|
||||
|
||||
|
||||
```
|
||||
let xs = Observable.deferred { () -> Observable<TimeInterval> in
|
||||
print("Performing work ...")
|
||||
return Observable.just(Date().timeIntervalSince1970)
|
||||
}
|
||||
.share(replay: 1, scope: .whileConnected)
|
||||
|
||||
_ = xs.subscribe(onNext: { print("next \($0)") }, onCompleted: { print("completed\n") })
|
||||
_ = xs.subscribe(onNext: { print("next \($0)") }, onCompleted: { print("completed\n") })
|
||||
_ = xs.subscribe(onNext: { print("next \($0)") }, onCompleted: { print("completed\n") })
|
||||
|
||||
```
|
||||
|
||||
Notice how time interval is different and `Performing work ...` is printed each time)
|
||||
|
||||
```
|
||||
Performing work ...
|
||||
next 1495998900.82141
|
||||
completed
|
||||
|
||||
Performing work ...
|
||||
next 1495998900.82359
|
||||
completed
|
||||
|
||||
Performing work ...
|
||||
next 1495998900.82444
|
||||
completed
|
||||
|
||||
|
||||
```
|
||||
|
||||
*/
|
||||
case whileConnected
|
||||
|
||||
/**
|
||||
**One subject will store replay events for all connections to source.**
|
||||
**Connections won't be isolated from each another.**
|
||||
|
||||
Configures the underlying implementation behave equivalent to.
|
||||
|
||||
```
|
||||
source.multicast(MySubject()).refCount()
|
||||
```
|
||||
|
||||
This has the following consequences:
|
||||
* Using `retry` or `concat` operators after this operator usually isn't advised.
|
||||
* Each connection to source observable sequence will share the same subject.
|
||||
* After number of subscribers drops from 1 to 0 and connection to source observable sequence is dispose, this operator will
|
||||
continue holding a reference to the same subject.
|
||||
If at some later moment a new observer initiates a new connection to source it can potentially receive
|
||||
some of the stale events received during previous connection.
|
||||
* After source sequence terminates any new observer will always immediatelly receive replayed elements and terminal event.
|
||||
No new subscriptions to source observable sequence will be attempted.
|
||||
|
||||
```
|
||||
let xs = Observable.deferred { () -> Observable<TimeInterval> in
|
||||
print("Performing work ...")
|
||||
return Observable.just(Date().timeIntervalSince1970)
|
||||
}
|
||||
.share(replay: 1, scope: .forever)
|
||||
|
||||
_ = xs.subscribe(onNext: { print("next \($0)") }, onCompleted: { print("completed\n") })
|
||||
_ = xs.subscribe(onNext: { print("next \($0)") }, onCompleted: { print("completed\n") })
|
||||
_ = xs.subscribe(onNext: { print("next \($0)") }, onCompleted: { print("completed\n") })
|
||||
```
|
||||
|
||||
Notice how time interval is the same, replayed, and `Performing work ...` is printed only once
|
||||
|
||||
```
|
||||
Performing work ...
|
||||
next 1495999013.76356
|
||||
completed
|
||||
|
||||
next 1495999013.76356
|
||||
completed
|
||||
|
||||
next 1495999013.76356
|
||||
completed
|
||||
```
|
||||
|
||||
*/
|
||||
case forever
|
||||
}
|
||||
|
||||
extension ObservableType {
|
||||
|
||||
/**
|
||||
Returns an observable sequence that **shares a single subscription to the underlying sequence**, and immediately upon subscription replays elements in buffer.
|
||||
|
||||
This operator is equivalent to:
|
||||
* `.whileConnected`
|
||||
```
|
||||
// Each connection will have it's own subject instance to store replay events.
|
||||
// Connections will be isolated from each another.
|
||||
source.multicast(makeSubject: { Replay.create(bufferSize: replay) }).refCount()
|
||||
```
|
||||
* `.forever`
|
||||
```
|
||||
// One subject will store replay events for all connections to source.
|
||||
// Connections won't be isolated from each another.
|
||||
source.multicast(Replay.create(bufferSize: replay)).refCount()
|
||||
```
|
||||
|
||||
It uses optimized versions of the operators for most common operations.
|
||||
|
||||
- parameter replay: Maximum element count of the replay buffer.
|
||||
- parameter scope: Lifetime scope of sharing subject. For more information see `SubjectLifetimeScope` enum.
|
||||
|
||||
- seealso: [shareReplay operator on reactivex.io](http://reactivex.io/documentation/operators/replay.html)
|
||||
|
||||
- returns: An observable sequence that contains the elements of a sequence produced by multicasting the source sequence.
|
||||
*/
|
||||
public func share(replay: Int = 0, scope: SubjectLifetimeScope)
|
||||
-> Observable<E> {
|
||||
switch scope {
|
||||
case .forever:
|
||||
switch replay {
|
||||
case 0: return self.multicast(PublishSubject()).refCount()
|
||||
default: return shareReplay(replay)
|
||||
}
|
||||
case .whileConnected:
|
||||
switch replay {
|
||||
case 0: return ShareWhileConnected(source: self.asObservable())
|
||||
case 1: return ShareReplay1WhileConnected(source: self.asObservable())
|
||||
default: return self.multicast(makeSubject: { ReplaySubject.create(bufferSize: replay) }).refCount()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension ObservableType {
|
||||
|
||||
/**
|
||||
Returns an observable sequence that shares a single subscription to the underlying sequence, and immediately upon subscription replays latest element in buffer.
|
||||
|
||||
This operator is a specialization of replay which creates a subscription when the number of observers goes from zero to one, then shares that subscription with all subsequent observers until the number of observers returns to zero, at which point the subscription is disposed.
|
||||
|
||||
Unlike `shareReplay(bufferSize: Int)`, this operator will clear latest element from replay buffer in case number of subscribers drops from one to zero. In case sequence
|
||||
completes or errors out replay buffer is also cleared.
|
||||
|
||||
- seealso: [shareReplay operator on reactivex.io](http://reactivex.io/documentation/operators/replay.html)
|
||||
|
||||
- returns: An observable sequence that contains the elements of a sequence produced by multicasting the source sequence.
|
||||
*/
|
||||
public func shareReplayLatestWhileConnected()
|
||||
-> Observable<E> {
|
||||
return ShareReplay1WhileConnected(source: self.asObservable())
|
||||
}
|
||||
}
|
||||
|
||||
extension ObservableType {
|
||||
|
||||
/**
|
||||
Returns an observable sequence that shares a single subscription to the underlying sequence, and immediately upon subscription replays maximum number of elements in buffer.
|
||||
|
||||
This operator is a specialization of replay which creates a subscription when the number of observers goes from zero to one, then shares that subscription with all subsequent observers until the number of observers returns to zero, at which point the subscription is disposed.
|
||||
|
||||
- seealso: [shareReplay operator on reactivex.io](http://reactivex.io/documentation/operators/replay.html)
|
||||
|
||||
- parameter bufferSize: Maximum element count of the replay buffer.
|
||||
- returns: An observable sequence that contains the elements of a sequence produced by multicasting the source sequence.
|
||||
*/
|
||||
public func shareReplay(_ bufferSize: Int)
|
||||
-> Observable<E> {
|
||||
return self.replay(bufferSize).refCount()
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate final class ShareReplay1WhileConnectedConnection<Element>
|
||||
: ObserverType
|
||||
, SynchronizedUnsubscribeType {
|
||||
typealias E = Element
|
||||
typealias Observers = AnyObserver<Element>.s
|
||||
typealias DisposeKey = Observers.KeyType
|
||||
|
||||
typealias Parent = ShareReplay1WhileConnected<Element>
|
||||
private let _parent: Parent
|
||||
private let _subscription = SingleAssignmentDisposable()
|
||||
|
||||
private let _lock: RecursiveLock
|
||||
private var _disposed: Bool = false
|
||||
fileprivate var _observers = Observers()
|
||||
fileprivate var _element: Element?
|
||||
|
||||
init(parent: Parent, lock: RecursiveLock) {
|
||||
_parent = parent
|
||||
_lock = lock
|
||||
|
||||
#if TRACE_RESOURCES
|
||||
_ = Resources.incrementTotal()
|
||||
#endif
|
||||
}
|
||||
|
||||
final func on(_ event: Event<E>) {
|
||||
_lock.lock()
|
||||
let observers = _synchronized_on(event)
|
||||
_lock.unlock()
|
||||
dispatch(observers, event)
|
||||
}
|
||||
|
||||
final private func _synchronized_on(_ event: Event<E>) -> Observers {
|
||||
if _disposed {
|
||||
return Observers()
|
||||
}
|
||||
|
||||
switch event {
|
||||
case .next(let element):
|
||||
_element = element
|
||||
return _observers
|
||||
case .error, .completed:
|
||||
let observers = _observers
|
||||
self._synchronized_dispose()
|
||||
return observers
|
||||
}
|
||||
}
|
||||
|
||||
final func connect() {
|
||||
_subscription.setDisposable(_parent._source.subscribe(self))
|
||||
}
|
||||
|
||||
final func _synchronized_subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == Element {
|
||||
_lock.lock(); defer { _lock.unlock() }
|
||||
if let element = _element {
|
||||
observer.on(.next(element))
|
||||
}
|
||||
|
||||
let disposeKey = _observers.insert(observer.on)
|
||||
|
||||
return SubscriptionDisposable(owner: self, key: disposeKey)
|
||||
}
|
||||
|
||||
final private func _synchronized_dispose() {
|
||||
_disposed = true
|
||||
if _parent._connection === self {
|
||||
_parent._connection = nil
|
||||
}
|
||||
_observers = Observers()
|
||||
}
|
||||
|
||||
final func synchronizedUnsubscribe(_ disposeKey: DisposeKey) {
|
||||
_lock.lock()
|
||||
let shouldDisconnect = _synchronized_unsubscribe(disposeKey)
|
||||
_lock.unlock()
|
||||
if shouldDisconnect {
|
||||
_subscription.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
final private func _synchronized_unsubscribe(_ disposeKey: DisposeKey) -> Bool {
|
||||
// if already unsubscribed, just return
|
||||
if self._observers.removeKey(disposeKey) == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if _observers.count == 0 {
|
||||
_synchronized_dispose()
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
#if TRACE_RESOURCES
|
||||
deinit {
|
||||
_ = Resources.decrementTotal()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// optimized version of share replay for most common case
|
||||
final fileprivate class ShareReplay1WhileConnected<Element>
|
||||
: Observable<Element> {
|
||||
|
||||
fileprivate typealias Connection = ShareReplay1WhileConnectedConnection<Element>
|
||||
|
||||
fileprivate let _source: Observable<Element>
|
||||
|
||||
fileprivate let _lock = RecursiveLock()
|
||||
|
||||
fileprivate var _connection: Connection?
|
||||
|
||||
init(source: Observable<Element>) {
|
||||
self._source = source
|
||||
}
|
||||
|
||||
override func subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == E {
|
||||
_lock.lock()
|
||||
|
||||
let connection = _synchronized_subscribe(observer)
|
||||
let count = connection._observers.count
|
||||
|
||||
let disposable = connection._synchronized_subscribe(observer)
|
||||
|
||||
_lock.unlock()
|
||||
|
||||
if count == 0 {
|
||||
connection.connect()
|
||||
}
|
||||
|
||||
return disposable
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
private func _synchronized_subscribe<O : ObserverType>(_ observer: O) -> Connection where O.E == E {
|
||||
let connection: Connection
|
||||
|
||||
if let existingConnection = _connection {
|
||||
connection = existingConnection
|
||||
}
|
||||
else {
|
||||
connection = ShareReplay1WhileConnectedConnection<Element>(
|
||||
parent: self,
|
||||
lock: _lock)
|
||||
_connection = connection
|
||||
}
|
||||
|
||||
return connection
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate final class ShareWhileConnectedConnection<Element>
|
||||
: ObserverType
|
||||
, SynchronizedUnsubscribeType {
|
||||
typealias E = Element
|
||||
typealias Observers = AnyObserver<Element>.s
|
||||
typealias DisposeKey = Observers.KeyType
|
||||
|
||||
typealias Parent = ShareWhileConnected<Element>
|
||||
private let _parent: Parent
|
||||
private let _subscription = SingleAssignmentDisposable()
|
||||
|
||||
private let _lock: RecursiveLock
|
||||
private var _disposed: Bool = false
|
||||
fileprivate var _observers = Observers()
|
||||
|
||||
init(parent: Parent, lock: RecursiveLock) {
|
||||
_parent = parent
|
||||
_lock = lock
|
||||
|
||||
#if TRACE_RESOURCES
|
||||
_ = Resources.incrementTotal()
|
||||
#endif
|
||||
}
|
||||
|
||||
final func on(_ event: Event<E>) {
|
||||
_lock.lock()
|
||||
let observers = _synchronized_on(event)
|
||||
_lock.unlock()
|
||||
dispatch(observers, event)
|
||||
}
|
||||
|
||||
final private func _synchronized_on(_ event: Event<E>) -> Observers {
|
||||
if _disposed {
|
||||
return Observers()
|
||||
}
|
||||
|
||||
switch event {
|
||||
case .next:
|
||||
return _observers
|
||||
case .error, .completed:
|
||||
let observers = _observers
|
||||
self._synchronized_dispose()
|
||||
return observers
|
||||
}
|
||||
}
|
||||
|
||||
final func connect() {
|
||||
_subscription.setDisposable(_parent._source.subscribe(self))
|
||||
}
|
||||
|
||||
final func _synchronized_subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == Element {
|
||||
_lock.lock(); defer { _lock.unlock() }
|
||||
|
||||
let disposeKey = _observers.insert(observer.on)
|
||||
|
||||
return SubscriptionDisposable(owner: self, key: disposeKey)
|
||||
}
|
||||
|
||||
final private func _synchronized_dispose() {
|
||||
_disposed = true
|
||||
if _parent._connection === self {
|
||||
_parent._connection = nil
|
||||
}
|
||||
_observers = Observers()
|
||||
}
|
||||
|
||||
final func synchronizedUnsubscribe(_ disposeKey: DisposeKey) {
|
||||
_lock.lock()
|
||||
let shouldDisconnect = _synchronized_unsubscribe(disposeKey)
|
||||
_lock.unlock()
|
||||
if shouldDisconnect {
|
||||
_subscription.dispose()
|
||||
}
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
final private func _synchronized_unsubscribe(_ disposeKey: DisposeKey) -> Bool {
|
||||
// if already unsubscribed, just return
|
||||
if self._observers.removeKey(disposeKey) == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
if _observers.count == 0 {
|
||||
_synchronized_dispose()
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
#if TRACE_RESOURCES
|
||||
deinit {
|
||||
_ = Resources.decrementTotal()
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// optimized version of share replay for most common case
|
||||
final fileprivate class ShareWhileConnected<Element>
|
||||
: Observable<Element> {
|
||||
|
||||
fileprivate typealias Connection = ShareWhileConnectedConnection<Element>
|
||||
|
||||
fileprivate let _source: Observable<Element>
|
||||
|
||||
fileprivate let _lock = RecursiveLock()
|
||||
|
||||
fileprivate var _connection: Connection?
|
||||
|
||||
init(source: Observable<Element>) {
|
||||
self._source = source
|
||||
}
|
||||
|
||||
override func subscribe<O : ObserverType>(_ observer: O) -> Disposable where O.E == E {
|
||||
_lock.lock()
|
||||
|
||||
let connection = _synchronized_subscribe(observer)
|
||||
let count = connection._observers.count
|
||||
|
||||
let disposable = connection._synchronized_subscribe(observer)
|
||||
|
||||
_lock.unlock()
|
||||
|
||||
if count == 0 {
|
||||
connection.connect()
|
||||
}
|
||||
|
||||
return disposable
|
||||
}
|
||||
|
||||
@inline(__always)
|
||||
private func _synchronized_subscribe<O : ObserverType>(_ observer: O) -> Connection where O.E == E {
|
||||
let connection: Connection
|
||||
|
||||
if let existingConnection = _connection {
|
||||
connection = existingConnection
|
||||
}
|
||||
else {
|
||||
connection = ShareWhileConnectedConnection<Element>(
|
||||
parent: self,
|
||||
lock: _lock)
|
||||
_connection = connection
|
||||
}
|
||||
|
||||
return connection
|
||||
}
|
||||
}
|
||||
+3
-8
@@ -12,7 +12,7 @@ class Sink<O : ObserverType> : Disposable {
|
||||
fileprivate var _disposed: Bool
|
||||
|
||||
#if DEBUG
|
||||
fileprivate var _numberOfConcurrentCalls: AtomicInt = 0
|
||||
fileprivate let _synchronizationTracker = SynchronizationTracker()
|
||||
#endif
|
||||
|
||||
init(observer: O, cancel: Cancelable) {
|
||||
@@ -26,13 +26,8 @@ class Sink<O : ObserverType> : Disposable {
|
||||
|
||||
final func forwardOn(_ event: Event<O.E>) {
|
||||
#if DEBUG
|
||||
if AtomicIncrement(&_numberOfConcurrentCalls) > 1 {
|
||||
rxFatalError("Warning: Recursive call or synchronization error!")
|
||||
}
|
||||
|
||||
defer {
|
||||
_ = AtomicDecrement(&_numberOfConcurrentCalls)
|
||||
}
|
||||
_synchronizationTracker.register(synchronizationErrorMessage: .default)
|
||||
defer { _synchronizationTracker.unregister() }
|
||||
#endif
|
||||
if _disposed {
|
||||
return
|
||||
|
||||
+20
-15
@@ -45,9 +45,7 @@ extension ObservableType where E : ObservableConvertibleType {
|
||||
|
||||
fileprivate class SwitchSink<SourceType, S: ObservableConvertibleType, O: ObserverType>
|
||||
: Sink<O>
|
||||
, ObserverType
|
||||
, LockOwnerType
|
||||
, SynchronizedOnType where S.E == O.E {
|
||||
, ObserverType where S.E == O.E {
|
||||
typealias E = SourceType
|
||||
|
||||
fileprivate let _subscriptions: SingleAssignmentDisposable = SingleAssignmentDisposable()
|
||||
@@ -69,24 +67,33 @@ fileprivate class SwitchSink<SourceType, S: ObservableConvertibleType, O: Observ
|
||||
_subscriptions.setDisposable(subscription)
|
||||
return Disposables.create(_subscriptions, _innerSubscription)
|
||||
}
|
||||
|
||||
func on(_ event: Event<E>) {
|
||||
synchronizedOn(event)
|
||||
}
|
||||
|
||||
func performMap(_ element: SourceType) throws -> S {
|
||||
rxAbstractMethod()
|
||||
}
|
||||
|
||||
func _synchronized_on(_ event: Event<E>) {
|
||||
switch event {
|
||||
case .next(let element):
|
||||
@inline(__always)
|
||||
final private func nextElementArrived(element: E) -> (Int, Observable<S.E>)? {
|
||||
_lock.lock(); defer { _lock.unlock() } // {
|
||||
do {
|
||||
let observable = try performMap(element).asObservable()
|
||||
_hasLatest = true
|
||||
_latest = _latest &+ 1
|
||||
let latest = _latest
|
||||
return (_latest, observable)
|
||||
}
|
||||
catch let error {
|
||||
forwardOn(.error(error))
|
||||
dispose()
|
||||
}
|
||||
|
||||
return nil
|
||||
// }
|
||||
}
|
||||
|
||||
func on(_ event: Event<E>) {
|
||||
switch event {
|
||||
case .next(let element):
|
||||
if let (latest, observable) = nextElementArrived(element: element) {
|
||||
let d = SingleAssignmentDisposable()
|
||||
_innerSubscription.disposable = d
|
||||
|
||||
@@ -94,14 +101,12 @@ fileprivate class SwitchSink<SourceType, S: ObservableConvertibleType, O: Observ
|
||||
let disposable = observable.subscribe(observer)
|
||||
d.setDisposable(disposable)
|
||||
}
|
||||
catch let error {
|
||||
forwardOn(.error(error))
|
||||
dispose()
|
||||
}
|
||||
case .error(let error):
|
||||
_lock.lock(); defer { _lock.unlock() }
|
||||
forwardOn(.error(error))
|
||||
dispose()
|
||||
case .completed:
|
||||
_lock.lock(); defer { _lock.unlock() }
|
||||
_stopped = true
|
||||
|
||||
_subscriptions.dispose()
|
||||
|
||||
+1
-1
@@ -16,7 +16,7 @@ extension Observable {
|
||||
- parameter observableFactory: Factory function to obtain an observable sequence that depends on the obtained resource.
|
||||
- returns: An observable sequence whose lifetime controls the lifetime of the dependent resource object.
|
||||
*/
|
||||
public static func using<R: Disposable>(_ resourceFactory: @escaping () throws -> R, observableFactory: @escaping (R) throws -> Observable<E>) -> Observable<E> {
|
||||
public static func using<Resource: Disposable>(_ resourceFactory: @escaping () throws -> Resource, observableFactory: @escaping (Resource) throws -> Observable<E>) -> Observable<E> {
|
||||
return Using(resourceFactory: resourceFactory, observableFactory: observableFactory)
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+1
-1
@@ -13,7 +13,7 @@ public protocol ObserverType {
|
||||
|
||||
/// Notify observer about sequence event.
|
||||
///
|
||||
/// - parameter event: Event that occured.
|
||||
/// - parameter event: Event that occurred.
|
||||
func on(_ event: Event<E>)
|
||||
}
|
||||
|
||||
|
||||
+67
@@ -65,3 +65,70 @@ func decrementChecked(_ i: inout Int) throws -> Int {
|
||||
defer { i -= 1 }
|
||||
return i
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
import class Foundation.Thread
|
||||
final class SynchronizationTracker {
|
||||
private let _lock = RecursiveLock()
|
||||
|
||||
public enum SychronizationErrorMessages: String {
|
||||
case variable = "Two different threads are trying to assign the same `Variable.value` unsynchronized.\n This is undefined behavior because the end result (variable value) is nondeterministic and depends on the \n operating system thread scheduler. This will cause random behavior of your program.\n"
|
||||
case `default` = "Two different unsynchronized threads are trying to send some event simultaneously.\n This is undefined behavior because the ordering of the effects caused by these events is nondeterministic and depends on the \n operating system thread scheduler. This will result in a random behavior of your program.\n"
|
||||
}
|
||||
|
||||
private var _threads = Dictionary<UnsafeMutableRawPointer, Int>()
|
||||
|
||||
private func synchronizationError(_ message: String) {
|
||||
#if FATAL_SYNCHRONIZATION
|
||||
rxFatalError(message)
|
||||
#else
|
||||
print(message)
|
||||
#endif
|
||||
}
|
||||
|
||||
func register(synchronizationErrorMessage: SychronizationErrorMessages) {
|
||||
_lock.lock(); defer { _lock.unlock() }
|
||||
let pointer = Unmanaged.passUnretained(Thread.current).toOpaque()
|
||||
let count = (_threads[pointer] ?? 0) + 1
|
||||
|
||||
if count > 1 {
|
||||
synchronizationError(
|
||||
"⚠️ Reentrancy anomaly was detected. ⚠️\n" +
|
||||
" > Debugging: To debug this issue you can set a breakpoint in \(#file):\(#line) and observe the call stack.\n" +
|
||||
" > Problem: This behavior is breaking the observable sequence grammar. `next (error | completed)?`\n" +
|
||||
" This behavior breaks the grammar because there is overlapping between sequence events.\n" +
|
||||
" Observable sequence is trying to send an event before sending of previous event has finished.\n" +
|
||||
" > Interpretation: This could mean that there is some kind of unexpected cyclic dependency in your code,\n" +
|
||||
" or that the system is not behaving in the expected way.\n" +
|
||||
" > Remedy: If this is the expected behavior this message can be suppressed by adding `.observeOn(MainScheduler.asyncInstance)`\n" +
|
||||
" or by enqueing sequence events in some other way.\n"
|
||||
)
|
||||
}
|
||||
|
||||
_threads[pointer] = count
|
||||
|
||||
if _threads.count > 1 {
|
||||
synchronizationError(
|
||||
"⚠️ Synchronization anomaly was detected. ⚠️\n" +
|
||||
" > Debugging: To debug this issue you can set a breakpoint in \(#file):\(#line) and observe the call stack.\n" +
|
||||
" > Problem: This behavior is breaking the observable sequence grammar. `next (error | completed)?`\n" +
|
||||
" This behavior breaks the grammar because there is overlapping between sequence events.\n" +
|
||||
" Observable sequence is trying to send an event before sending of previous event has finished.\n" +
|
||||
" > Interpretation: " + synchronizationErrorMessage.rawValue +
|
||||
" > Remedy: If this is the expected behavior this message can be suppressed by adding `.observeOn(MainScheduler.asyncInstance)`\n" +
|
||||
" or by synchronizing sequence events in some other way.\n"
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
func unregister() {
|
||||
_lock.lock(); defer { _lock.unlock() }
|
||||
let pointer = Unmanaged.passUnretained(Thread.current).toOpaque()
|
||||
_threads[pointer] = (_threads[pointer] ?? 1) - 1
|
||||
if _threads[pointer] == 0 {
|
||||
_threads[pointer] = nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -45,7 +45,7 @@ public class ConcurrentDispatchQueueScheduler: SchedulerType {
|
||||
}
|
||||
|
||||
/**
|
||||
Schedules an action to be executed immediatelly.
|
||||
Schedules an action to be executed immediately.
|
||||
|
||||
- parameter state: State passed to the action to be executed.
|
||||
- parameter action: Action to be executed.
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ public final class ConcurrentMainScheduler : SchedulerType {
|
||||
public static let instance = ConcurrentMainScheduler(mainScheduler: MainScheduler.instance)
|
||||
|
||||
/**
|
||||
Schedules an action to be executed immediatelly.
|
||||
Schedules an action to be executed immediately.
|
||||
|
||||
- parameter state: State passed to the action to be executed.
|
||||
- parameter action: Action to be executed.
|
||||
|
||||
+1
-1
@@ -12,7 +12,7 @@ private final class ImmediateScheduler : ImmediateSchedulerType {
|
||||
private let _asyncLock = AsyncLock<AnonymousInvocable>()
|
||||
|
||||
/**
|
||||
Schedules an action to be executed immediatelly.
|
||||
Schedules an action to be executed immediately.
|
||||
|
||||
In case `schedule` is called recursively from inside of `action` callback, scheduled `action` will be enqueued
|
||||
and executed after current `action`. (`AsyncLock` behavior)
|
||||
|
||||
+1
-1
@@ -43,7 +43,7 @@ final class SchedulePeriodicRecursive<State> {
|
||||
case .tick:
|
||||
scheduler.schedule(.tick, dueTime: _period)
|
||||
|
||||
// The idea is that if on tick there wasn't any item enqueued, schedule to perform work immediatelly.
|
||||
// The idea is that if on tick there wasn't any item enqueued, schedule to perform work immediately.
|
||||
// Else work will be scheduled after previous enqueued work completes.
|
||||
if AtomicIncrement(&_pendingTickCount) == 1 {
|
||||
self.tick(.dispatchStart, scheduler: scheduler)
|
||||
|
||||
+1
-1
@@ -82,7 +82,7 @@ public class SerialDispatchQueueScheduler : SchedulerType {
|
||||
}
|
||||
|
||||
/**
|
||||
Schedules an action to be executed immediatelly.
|
||||
Schedules an action to be executed immediately.
|
||||
|
||||
- parameter state: State passed to the action to be executed.
|
||||
- parameter action: Action to be executed.
|
||||
|
||||
+1
-1
@@ -55,7 +55,7 @@ open class VirtualTimeScheduler<Converter: VirtualTimeConverterType>
|
||||
}
|
||||
|
||||
/**
|
||||
Schedules an action to be executed immediatelly.
|
||||
Schedules an action to be executed immediately.
|
||||
|
||||
- parameter state: State passed to the action to be executed.
|
||||
- parameter action: Action to be executed.
|
||||
|
||||
+9
@@ -38,6 +38,11 @@ public final class AsyncSubject<Element>
|
||||
}
|
||||
private var _lastElement: Element?
|
||||
|
||||
#if DEBUG
|
||||
fileprivate let _synchronizationTracker = SynchronizationTracker()
|
||||
#endif
|
||||
|
||||
|
||||
/// Creates a subject.
|
||||
public override init() {
|
||||
#if TRACE_RESOURCES
|
||||
@@ -50,6 +55,10 @@ public final class AsyncSubject<Element>
|
||||
///
|
||||
/// - parameter event: Event to send to the observers.
|
||||
public func on(_ event: Event<E>) {
|
||||
#if DEBUG
|
||||
_synchronizationTracker.register(synchronizationErrorMessage: .default)
|
||||
defer { _synchronizationTracker.unregister() }
|
||||
#endif
|
||||
let (observers, event) = _synchronized_on(event)
|
||||
switch event {
|
||||
case .next:
|
||||
|
||||
+9
-2
@@ -36,6 +36,10 @@ public final class BehaviorSubject<Element>
|
||||
private var _observers = Observers()
|
||||
private var _stoppedEvent: Event<Element>?
|
||||
|
||||
#if DEBUG
|
||||
fileprivate let _synchronizationTracker = SynchronizationTracker()
|
||||
#endif
|
||||
|
||||
/// Indicates whether the subject has been disposed.
|
||||
public var isDisposed: Bool {
|
||||
return _isDisposed
|
||||
@@ -75,12 +79,15 @@ public final class BehaviorSubject<Element>
|
||||
///
|
||||
/// - parameter event: Event to send to the observers.
|
||||
public func on(_ event: Event<E>) {
|
||||
_lock.lock()
|
||||
#if DEBUG
|
||||
_synchronizationTracker.register(synchronizationErrorMessage: .default)
|
||||
defer { _synchronizationTracker.unregister() }
|
||||
#endif
|
||||
dispatch(_synchronized_on(event), event)
|
||||
_lock.unlock()
|
||||
}
|
||||
|
||||
func _synchronized_on(_ event: Event<E>) -> Observers {
|
||||
_lock.lock(); defer { _lock.unlock() }
|
||||
if _stoppedEvent != nil || _isDisposed {
|
||||
return Observers()
|
||||
}
|
||||
|
||||
+9
-1
@@ -35,7 +35,11 @@ public final class PublishSubject<Element>
|
||||
private var _observers = Observers()
|
||||
private var _stopped = false
|
||||
private var _stoppedEvent = nil as Event<Element>?
|
||||
|
||||
|
||||
#if DEBUG
|
||||
fileprivate let _synchronizationTracker = SynchronizationTracker()
|
||||
#endif
|
||||
|
||||
/// Indicates whether the subject has been isDisposed.
|
||||
public var isDisposed: Bool {
|
||||
return _isDisposed
|
||||
@@ -53,6 +57,10 @@ public final class PublishSubject<Element>
|
||||
///
|
||||
/// - parameter event: Event to send to the observers.
|
||||
public func on(_ event: Event<Element>) {
|
||||
#if DEBUG
|
||||
_synchronizationTracker.register(synchronizationErrorMessage: .default)
|
||||
defer { _synchronizationTracker.unregister() }
|
||||
#endif
|
||||
dispatch(_synchronized_on(event), event)
|
||||
}
|
||||
|
||||
|
||||
+12
-4
@@ -39,6 +39,10 @@ public class ReplaySubject<Element>
|
||||
}
|
||||
fileprivate var _observers = Observers()
|
||||
|
||||
#if DEBUG
|
||||
fileprivate let _synchronizationTracker = SynchronizationTracker()
|
||||
#endif
|
||||
|
||||
func unsubscribe(_ key: DisposeKey) {
|
||||
rxAbstractMethod()
|
||||
}
|
||||
@@ -111,6 +115,10 @@ fileprivate class ReplayBufferBase<Element>
|
||||
}
|
||||
|
||||
override func on(_ event: Event<Element>) {
|
||||
#if DEBUG
|
||||
_synchronizationTracker.register(synchronizationErrorMessage: .default)
|
||||
defer { _synchronizationTracker.unregister() }
|
||||
#endif
|
||||
dispatch(_synchronized_on(event), event)
|
||||
}
|
||||
|
||||
@@ -196,7 +204,7 @@ fileprivate class ReplayBufferBase<Element>
|
||||
}
|
||||
}
|
||||
|
||||
final class ReplayOne<Element> : ReplayBufferBase<Element> {
|
||||
fileprivate final class ReplayOne<Element> : ReplayBufferBase<Element> {
|
||||
private var _value: Element?
|
||||
|
||||
override init() {
|
||||
@@ -223,7 +231,7 @@ final class ReplayOne<Element> : ReplayBufferBase<Element> {
|
||||
}
|
||||
}
|
||||
|
||||
class ReplayManyBase<Element> : ReplayBufferBase<Element> {
|
||||
fileprivate class ReplayManyBase<Element> : ReplayBufferBase<Element> {
|
||||
fileprivate var _queue: Queue<Element>
|
||||
|
||||
init(queueSize: Int) {
|
||||
@@ -246,7 +254,7 @@ class ReplayManyBase<Element> : ReplayBufferBase<Element> {
|
||||
}
|
||||
}
|
||||
|
||||
final class ReplayMany<Element> : ReplayManyBase<Element> {
|
||||
fileprivate final class ReplayMany<Element> : ReplayManyBase<Element> {
|
||||
private let _bufferSize: Int
|
||||
|
||||
init(bufferSize: Int) {
|
||||
@@ -262,7 +270,7 @@ final class ReplayMany<Element> : ReplayManyBase<Element> {
|
||||
}
|
||||
}
|
||||
|
||||
final class ReplayAll<Element> : ReplayManyBase<Element> {
|
||||
fileprivate final class ReplayAll<Element> : ReplayManyBase<Element> {
|
||||
init() {
|
||||
super.init(queueSize: 0)
|
||||
}
|
||||
|
||||
+4
-9
@@ -17,12 +17,12 @@ public final class Variable<Element> {
|
||||
private let _subject: BehaviorSubject<Element>
|
||||
|
||||
private var _lock = SpinLock()
|
||||
|
||||
|
||||
// state
|
||||
private var _value: E
|
||||
|
||||
#if DEBUG
|
||||
fileprivate var _numberOfConcurrentCalls: AtomicInt = 0
|
||||
fileprivate let _synchronizationTracker = SynchronizationTracker()
|
||||
#endif
|
||||
|
||||
/// Gets or sets current value of variable.
|
||||
@@ -37,13 +37,8 @@ public final class Variable<Element> {
|
||||
}
|
||||
set(newValue) {
|
||||
#if DEBUG
|
||||
if AtomicIncrement(&_numberOfConcurrentCalls) > 1 {
|
||||
rxFatalError("Warning: Recursive call or synchronization error!")
|
||||
}
|
||||
|
||||
defer {
|
||||
_ = AtomicDecrement(&_numberOfConcurrentCalls)
|
||||
}
|
||||
_synchronizationTracker.register(synchronizationErrorMessage: .variable)
|
||||
defer { _synchronizationTracker.unregister() }
|
||||
#endif
|
||||
_lock.lock()
|
||||
_value = newValue
|
||||
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
//
|
||||
// Completable+AndThen.swift
|
||||
// RxSwift
|
||||
//
|
||||
// Created by Krunoslav Zaher on 7/2/17.
|
||||
// Copyright © 2017 Krunoslav Zaher. All rights reserved.
|
||||
//
|
||||
|
||||
extension PrimitiveSequenceType where TraitType == CompletableTrait, ElementType == Never {
|
||||
/**
|
||||
Concatenates the second observable sequence to `self` upon successful termination of `self`.
|
||||
|
||||
- seealso: [concat operator on reactivex.io](http://reactivex.io/documentation/operators/concat.html)
|
||||
|
||||
- parameter second: Second observable sequence.
|
||||
- returns: An observable sequence that contains the elements of `self`, followed by those of the second sequence.
|
||||
*/
|
||||
public func andThen<E>(_ second: Single<E>) -> Single<E> {
|
||||
let completable = self.primitiveSequence.asObservable()
|
||||
return Single(raw: ConcatCompletable(completable: completable, second: second.asObservable()))
|
||||
}
|
||||
|
||||
/**
|
||||
Concatenates the second observable sequence to `self` upon successful termination of `self`.
|
||||
|
||||
- seealso: [concat operator on reactivex.io](http://reactivex.io/documentation/operators/concat.html)
|
||||
|
||||
- parameter second: Second observable sequence.
|
||||
- returns: An observable sequence that contains the elements of `self`, followed by those of the second sequence.
|
||||
*/
|
||||
public func andThen<E>(_ second: Maybe<E>) -> Maybe<E> {
|
||||
let completable = self.primitiveSequence.asObservable()
|
||||
return Maybe(raw: ConcatCompletable(completable: completable, second: second.asObservable()))
|
||||
}
|
||||
|
||||
/**
|
||||
Concatenates the second observable sequence to `self` upon successful termination of `self`.
|
||||
|
||||
- seealso: [concat operator on reactivex.io](http://reactivex.io/documentation/operators/concat.html)
|
||||
|
||||
- parameter second: Second observable sequence.
|
||||
- returns: An observable sequence that contains the elements of `self`, followed by those of the second sequence.
|
||||
*/
|
||||
public func andThen(_ second: Completable) -> Completable {
|
||||
let completable = self.primitiveSequence.asObservable()
|
||||
return Completable(raw: ConcatCompletable(completable: completable, second: second.asObservable()))
|
||||
}
|
||||
|
||||
/**
|
||||
Concatenates the second observable sequence to `self` upon successful termination of `self`.
|
||||
|
||||
- seealso: [concat operator on reactivex.io](http://reactivex.io/documentation/operators/concat.html)
|
||||
|
||||
- parameter second: Second observable sequence.
|
||||
- returns: An observable sequence that contains the elements of `self`, followed by those of the second sequence.
|
||||
*/
|
||||
public func andThen<E>(_ second: Observable<E>) -> Observable<E> {
|
||||
let completable = self.primitiveSequence.asObservable()
|
||||
return ConcatCompletable(completable: completable, second: second.asObservable())
|
||||
}
|
||||
}
|
||||
|
||||
final fileprivate class ConcatCompletable<Element> : Producer<Element> {
|
||||
fileprivate let _completable: Observable<Never>
|
||||
fileprivate let _second: Observable<Element>
|
||||
|
||||
init(completable: Observable<Never>, second: Observable<Element>) {
|
||||
self._completable = completable
|
||||
self._second = second
|
||||
}
|
||||
|
||||
override func run<O>(_ observer: O, cancel: Cancelable) -> (sink: Disposable, subscription: Disposable) where O : ObserverType, O.E == Element {
|
||||
let sink = ConcatCompletableSink(parent: self, observer: observer, cancel: cancel)
|
||||
let subscription = sink.run()
|
||||
return (sink: sink, subscription: subscription)
|
||||
}
|
||||
}
|
||||
|
||||
final fileprivate class ConcatCompletableSink<O: ObserverType>
|
||||
: Sink<O>
|
||||
, ObserverType {
|
||||
typealias E = Never
|
||||
typealias Parent = ConcatCompletable<O.E>
|
||||
|
||||
private let _parent: Parent
|
||||
private let _subscription = SerialDisposable()
|
||||
|
||||
init(parent: Parent, observer: O, cancel: Cancelable) {
|
||||
self._parent = parent
|
||||
super.init(observer: observer, cancel: cancel)
|
||||
}
|
||||
|
||||
func on(_ event: Event<E>) {
|
||||
switch event {
|
||||
case .error(let error):
|
||||
self.forwardOn(.error(error))
|
||||
self.dispose()
|
||||
case .next:
|
||||
break
|
||||
case .completed:
|
||||
let otherSink = ConcatCompletableSinkOther(parent: self)
|
||||
_subscription.disposable = _parent._second.subscribe(otherSink)
|
||||
}
|
||||
}
|
||||
|
||||
func run() -> Disposable {
|
||||
let subscription = SingleAssignmentDisposable()
|
||||
_subscription.disposable = subscription
|
||||
subscription.setDisposable(_parent._completable.subscribe(self))
|
||||
return _subscription
|
||||
}
|
||||
}
|
||||
|
||||
final fileprivate class ConcatCompletableSinkOther<O: ObserverType>
|
||||
: ObserverType {
|
||||
typealias E = O.E
|
||||
|
||||
typealias Parent = ConcatCompletableSink<O>
|
||||
|
||||
private let _parent: Parent
|
||||
|
||||
init(parent: Parent) {
|
||||
self._parent = parent
|
||||
}
|
||||
|
||||
func on(_ event: Event<O.E>) {
|
||||
_parent.forwardOn(event)
|
||||
if event.isStopEvent {
|
||||
_parent.dispose()
|
||||
}
|
||||
}
|
||||
}
|
||||
+135
@@ -579,6 +579,51 @@ extension PrimitiveSequence {
|
||||
-> PrimitiveSequence<Trait, Element> {
|
||||
return PrimitiveSequence(raw: source.debug(identifier, trimOutput: trimOutput, file: file, line: line, function: function))
|
||||
}
|
||||
|
||||
/**
|
||||
Constructs an observable sequence that depends on a resource object, whose lifetime is tied to the resulting observable sequence's lifetime.
|
||||
|
||||
- seealso: [using operator on reactivex.io](http://reactivex.io/documentation/operators/using.html)
|
||||
|
||||
- parameter resourceFactory: Factory function to obtain a resource object.
|
||||
- parameter primitiveSequenceFactory: Factory function to obtain an observable sequence that depends on the obtained resource.
|
||||
- returns: An observable sequence whose lifetime controls the lifetime of the dependent resource object.
|
||||
*/
|
||||
public static func using<Resource: Disposable>(_ resourceFactory: @escaping () throws -> Resource, primitiveSequenceFactory: @escaping (Resource) throws -> PrimitiveSequence<Trait, Element>)
|
||||
-> PrimitiveSequence<Trait, Element> {
|
||||
return PrimitiveSequence(raw: Observable.using(resourceFactory, observableFactory: { (resource: Resource) throws -> Observable<E> in
|
||||
return try primitiveSequenceFactory(resource).asObservable()
|
||||
}))
|
||||
}
|
||||
|
||||
/**
|
||||
Applies a timeout policy for each element in the observable sequence. If the next element isn't received within the specified timeout duration starting from its predecessor, a TimeoutError is propagated to the observer.
|
||||
|
||||
- seealso: [timeout operator on reactivex.io](http://reactivex.io/documentation/operators/timeout.html)
|
||||
|
||||
- parameter dueTime: Maximum duration between values before a timeout occurs.
|
||||
- parameter scheduler: Scheduler to run the timeout timer on.
|
||||
- returns: An observable sequence with a `RxError.timeout` in case of a timeout.
|
||||
*/
|
||||
public func timeout(_ dueTime: RxTimeInterval, scheduler: SchedulerType)
|
||||
-> PrimitiveSequence<Trait, Element> {
|
||||
return PrimitiveSequence(raw: source.timeout(dueTime, scheduler: scheduler))
|
||||
}
|
||||
|
||||
/**
|
||||
Applies a timeout policy for each element in the observable sequence, using the specified scheduler to run timeout timers. If the next element isn't received within the specified timeout duration starting from its predecessor, the other observable sequence is used to produce future messages from that point on.
|
||||
|
||||
- seealso: [timeout operator on reactivex.io](http://reactivex.io/documentation/operators/timeout.html)
|
||||
|
||||
- parameter dueTime: Maximum duration between values before a timeout occurs.
|
||||
- parameter other: Sequence to return in case of a timeout.
|
||||
- parameter scheduler: Scheduler to run the timeout timer on.
|
||||
- returns: The source sequence switching to the other sequence in case of a timeout.
|
||||
*/
|
||||
public func timeout(_ dueTime: RxTimeInterval, other: PrimitiveSequence<Trait, Element>, scheduler: SchedulerType)
|
||||
-> PrimitiveSequence<Trait, Element> {
|
||||
return PrimitiveSequence(raw: source.timeout(dueTime, other: other.source, scheduler: scheduler))
|
||||
}
|
||||
}
|
||||
|
||||
extension PrimitiveSequenceType where ElementType: SignedInteger
|
||||
@@ -622,6 +667,96 @@ extension PrimitiveSequenceType where TraitType == CompletableTrait, ElementType
|
||||
public static func empty() -> PrimitiveSequence<CompletableTrait, Never> {
|
||||
return PrimitiveSequence(raw: Observable.empty())
|
||||
}
|
||||
|
||||
/**
|
||||
Concatenates the second observable sequence to `self` upon successful termination of `self`.
|
||||
|
||||
- seealso: [concat operator on reactivex.io](http://reactivex.io/documentation/operators/concat.html)
|
||||
|
||||
- parameter second: Second observable sequence.
|
||||
- returns: An observable sequence that contains the elements of `self`, followed by those of the second sequence.
|
||||
*/
|
||||
public func concat(_ second: PrimitiveSequence<CompletableTrait, Never>) -> PrimitiveSequence<CompletableTrait, Never> {
|
||||
return Completable.concat(primitiveSequence, second)
|
||||
}
|
||||
|
||||
/**
|
||||
Concatenates all observable sequences in the given sequence, as long as the previous observable sequence terminated successfully.
|
||||
|
||||
- seealso: [concat operator on reactivex.io](http://reactivex.io/documentation/operators/concat.html)
|
||||
|
||||
- returns: An observable sequence that contains the elements of each given sequence, in sequential order.
|
||||
*/
|
||||
public static func concat<S: Sequence>(_ sequence: S) -> PrimitiveSequence<CompletableTrait, Never>
|
||||
where S.Iterator.Element == PrimitiveSequence<CompletableTrait, Never> {
|
||||
let source = Observable.concat(sequence.lazy.map { $0.asObservable() })
|
||||
return PrimitiveSequence<CompletableTrait, Never>(raw: source)
|
||||
}
|
||||
|
||||
/**
|
||||
Concatenates all observable sequences in the given sequence, as long as the previous observable sequence terminated successfully.
|
||||
|
||||
- seealso: [concat operator on reactivex.io](http://reactivex.io/documentation/operators/concat.html)
|
||||
|
||||
- returns: An observable sequence that contains the elements of each given sequence, in sequential order.
|
||||
*/
|
||||
public static func concat<C: Collection>(_ collection: C) -> PrimitiveSequence<CompletableTrait, Never>
|
||||
where C.Iterator.Element == PrimitiveSequence<CompletableTrait, Never> {
|
||||
let source = Observable.concat(collection.map { $0.asObservable() })
|
||||
return PrimitiveSequence<CompletableTrait, Never>(raw: source)
|
||||
}
|
||||
|
||||
/**
|
||||
Concatenates all observable sequences in the given sequence, as long as the previous observable sequence terminated successfully.
|
||||
|
||||
- seealso: [concat operator on reactivex.io](http://reactivex.io/documentation/operators/concat.html)
|
||||
|
||||
- returns: An observable sequence that contains the elements of each given sequence, in sequential order.
|
||||
*/
|
||||
public static func concat(_ sources: PrimitiveSequence<CompletableTrait, Never> ...) -> PrimitiveSequence<CompletableTrait, Never> {
|
||||
let source = Observable.concat(sources.map { $0.asObservable() })
|
||||
return PrimitiveSequence<CompletableTrait, Never>(raw: source)
|
||||
}
|
||||
|
||||
/**
|
||||
Merges elements from all observable sequences from collection into a single observable sequence.
|
||||
|
||||
- seealso: [merge operator on reactivex.io](http://reactivex.io/documentation/operators/merge.html)
|
||||
|
||||
- parameter sources: Collection of observable sequences to merge.
|
||||
- returns: The observable sequence that merges the elements of the observable sequences.
|
||||
*/
|
||||
public static func merge<C: Collection>(_ sources: C) -> PrimitiveSequence<CompletableTrait, Never>
|
||||
where C.Iterator.Element == PrimitiveSequence<CompletableTrait, Never> {
|
||||
let source = Observable.merge(sources.map { $0.asObservable() })
|
||||
return PrimitiveSequence<CompletableTrait, Never>(raw: source)
|
||||
}
|
||||
|
||||
/**
|
||||
Merges elements from all observable sequences from array into a single observable sequence.
|
||||
|
||||
- seealso: [merge operator on reactivex.io](http://reactivex.io/documentation/operators/merge.html)
|
||||
|
||||
- parameter sources: Array of observable sequences to merge.
|
||||
- returns: The observable sequence that merges the elements of the observable sequences.
|
||||
*/
|
||||
public static func merge(_ sources: [PrimitiveSequence<CompletableTrait, Never>]) -> PrimitiveSequence<CompletableTrait, Never> {
|
||||
let source = Observable.merge(sources.map { $0.asObservable() })
|
||||
return PrimitiveSequence<CompletableTrait, Never>(raw: source)
|
||||
}
|
||||
|
||||
/**
|
||||
Merges elements from all observable sequences into a single observable sequence.
|
||||
|
||||
- seealso: [merge operator on reactivex.io](http://reactivex.io/documentation/operators/merge.html)
|
||||
|
||||
- parameter sources: Collection of observable sequences to merge.
|
||||
- returns: The observable sequence that merges the elements of the observable sequences.
|
||||
*/
|
||||
public static func merge(_ sources: PrimitiveSequence<CompletableTrait, Never>...) -> PrimitiveSequence<CompletableTrait, Never> {
|
||||
let source = Observable.merge(sources.map { $0.asObservable() })
|
||||
return PrimitiveSequence<CompletableTrait, Never>(raw: source)
|
||||
}
|
||||
}
|
||||
|
||||
extension ObservableType {
|
||||
|
||||
+3
-4
@@ -1,9 +1,8 @@
|
||||
CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/Alamofire
|
||||
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Alamofire
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PODS_TARGET_SRCROOT = ${PODS_ROOT}/Alamofire
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
|
||||
+4
-5
@@ -1,10 +1,9 @@
|
||||
CONFIGURATION_BUILD_DIR = $PODS_CONFIGURATION_BUILD_DIR/PetstoreClient
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "$PODS_CONFIGURATION_BUILD_DIR/Alamofire" "$PODS_CONFIGURATION_BUILD_DIR/RxSwift"
|
||||
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/PetstoreClient
|
||||
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/RxSwift"
|
||||
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
|
||||
HEADER_SEARCH_PATHS = "${PODS_ROOT}/Headers/Private" "${PODS_ROOT}/Headers/Public"
|
||||
OTHER_SWIFT_FLAGS = $(inherited) "-D" "COCOAPODS"
|
||||
PODS_BUILD_DIR = $BUILD_DIR
|
||||
PODS_CONFIGURATION_BUILD_DIR = $PODS_BUILD_DIR/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_BUILD_DIR = ${BUILD_DIR}
|
||||
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
|
||||
PODS_ROOT = ${SRCROOT}
|
||||
PODS_TARGET_SRCROOT = ${PODS_ROOT}/../..
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user