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:
Daiki Matsudate
2018-08-21 16:17:56 +09:00
committed by William Cheng
parent 2044c36398
commit fcfd8ea76e
384 changed files with 9628 additions and 14700 deletions
@@ -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;
}
@@ -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;
}
@@ -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
@@ -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 = ""$""
}
/**
@@ -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
@@ -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""
}
/**
@@ -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]?
@@ -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
@@ -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": {
@@ -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
File diff suppressed because it is too large Load Diff
@@ -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}
@@ -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}
@@ -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
}
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 = ""$""
}
/**
@@ -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
@@ -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""
}
/**
@@ -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]?
@@ -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]?
@@ -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
@@ -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 = ""$""
}
/**
@@ -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
@@ -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""
}
/**
@@ -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]?
@@ -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
@@ -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,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
File diff suppressed because it is too large Load Diff
@@ -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}
@@ -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}
@@ -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
}
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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}
@@ -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
@@ -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 = ""$""
}
/**
@@ -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
@@ -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""
}
/**
@@ -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]?
@@ -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
@@ -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"
@@ -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
File diff suppressed because it is too large Load Diff
@@ -3,12 +3,6 @@
[![Travis CI](https://travis-ci.org/ReactiveX/RxSwift.svg?branch=master)](https://travis-ci.org/ReactiveX/RxSwift) ![platforms](https://img.shields.io/badge/platforms-iOS%20%7C%20macOS%20%7C%20tvOS%20%7C%20watchOS%20%7C%20Linux-333333.svg) ![pod](https://img.shields.io/cocoapods/v/RxSwift.svg) [![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage) [![Swift Package Manager compatible](https://img.shields.io/badge/Swift%20Package%20Manager-compatible-brightgreen.svg)](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)
@@ -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:
@@ -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.
@@ -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
@@ -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
}
@@ -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.
@@ -128,3 +128,4 @@ final fileprivate class Concat<S: Sequence> : Producer<S.Iterator.Element.E> whe
return (sink: sink, subscription: subscription)
}
}
@@ -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)
}
}
@@ -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:
@@ -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.
@@ -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
@@ -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
}
@@ -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)
@@ -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> {
@@ -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
}
}
@@ -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
}
}
@@ -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
}
}
@@ -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
@@ -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()
@@ -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)
}
}
@@ -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>)
}
@@ -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
@@ -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.
@@ -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.
@@ -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)
@@ -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)
@@ -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.
@@ -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.
@@ -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:
@@ -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()
}
@@ -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)
}
@@ -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)
}
@@ -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
@@ -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()
}
}
}
@@ -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 {
@@ -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}
@@ -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