Showing preview only (4,610K chars total). Download the full file or copy to clipboard to get everything.
Repository: parse-community/Parse-Swift
Branch: main
Commit: 645180e08206
Files: 401
Total size: 4.3 MB
Directory structure:
gitextract_a915zrx1/
├── .codecov.yml
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── ---1-report-an-issue.md
│ │ ├── ---2-feature-request.md
│ │ └── config.yml
│ ├── pull_request_template.md
│ └── workflows/
│ ├── ci.yml
│ └── release.yml
├── .gitignore
├── .spi.yml
├── .swiftlint.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── MIGRATION.md
├── Package.swift
├── Package@5.1.swift
├── Parse.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcshareddata/
│ └── IDEWorkspaceChecks.plist
├── ParseSwift-iOS/
│ └── Info.plist
├── ParseSwift-macOS/
│ └── Info.plist
├── ParseSwift-tvOS/
│ ├── Info.plist
│ └── ParseSwift_tvOS.h
├── ParseSwift-watchOS/
│ ├── Info.plist
│ └── ParseSwift_watchOS.h
├── ParseSwift.playground/
│ ├── Pages/
│ │ ├── 1 - Your first Object.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 10 - Cloud Code.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 11 - LiveQuery.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 12 - Roles and Relations.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 13 - Operations.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 14 - Config.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 15 - Custom ObjectId.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 16 - Analytics.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 17 - SwiftUI - Finding Objects.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 18 - SwiftUI - Finding Objects With Custom ViewModel.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 19 - SwiftUI - LiveQuery.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 2 - Finding Objects.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 20 - Cloud Schemas.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 21 - Cloud Push Notifications.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 22 - Cloud Hook Functions.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 23 - Cloud Hook Triggers.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 3 - User - Sign Up.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 4 - User - Continued.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 5 - ACL.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 6 - Installation.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 7 - GeoPoint.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 8 - Pointers.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ └── 9 - Files.xcplaygroundpage/
│ │ └── Contents.swift
│ ├── Sources/
│ │ └── Common.swift
│ └── contents.xcplayground
├── ParseSwift.podtemplate
├── ParseSwift.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata/
│ └── xcschemes/
│ ├── ParseSwift (iOS).xcscheme
│ ├── ParseSwift (macOS).xcscheme
│ ├── ParseSwift (tvOS).xcscheme
│ ├── ParseSwift (watchOS).xcscheme
│ ├── TestHost.xcscheme
│ └── TestHostTV.xcscheme
├── ParseSwiftTestsmacOS/
│ └── Info.plist
├── ParseSwiftTeststvOS/
│ └── Info.plist
├── README.md
├── Scripts/
│ ├── carthage.sh
│ ├── generate-documentation
│ ├── update-gh-pages-documentation-site
│ └── update_build
├── Sources/
│ └── ParseSwift/
│ ├── API/
│ │ ├── API+BatchCommand.swift
│ │ ├── API+Command+async.swift
│ │ ├── API+Command.swift
│ │ ├── API+NonParseBodyCommand+async.swift
│ │ ├── API+NonParseBodyCommand.swift
│ │ ├── API.swift
│ │ ├── BatchUtils.swift
│ │ ├── ParseURLSessionDelegate.swift
│ │ └── Responses.swift
│ ├── Authentication/
│ │ ├── 3rd Party/
│ │ │ ├── ParseApple/
│ │ │ │ ├── ParseApple+async.swift
│ │ │ │ ├── ParseApple+combine.swift
│ │ │ │ └── ParseApple.swift
│ │ │ ├── ParseFacebook/
│ │ │ │ ├── ParseFacebook+async.swift
│ │ │ │ ├── ParseFacebook+combine.swift
│ │ │ │ └── ParseFacebook.swift
│ │ │ ├── ParseGithub/
│ │ │ │ ├── ParseGitHub+async.swift
│ │ │ │ ├── ParseGitHub+combine.swift
│ │ │ │ └── ParseGitHub.swift
│ │ │ ├── ParseGoogle/
│ │ │ │ ├── ParseGoogle+async.swift
│ │ │ │ ├── ParseGoogle+combine.swift
│ │ │ │ └── ParseGoogle.swift
│ │ │ ├── ParseInstagram/
│ │ │ │ ├── ParseInstagram+async.swift
│ │ │ │ ├── ParseInstagram+combine.swift
│ │ │ │ └── ParseInstagram.swift
│ │ │ ├── ParseLDAP/
│ │ │ │ ├── ParseLDAP+async.swift
│ │ │ │ ├── ParseLDAP+combine.swift
│ │ │ │ └── ParseLDAP.swift
│ │ │ ├── ParseLinkedIn/
│ │ │ │ ├── ParseLinkedIn+async.swift
│ │ │ │ ├── ParseLinkedIn+combine.swift
│ │ │ │ └── ParseLinkedIn.swift
│ │ │ ├── ParseSpotify/
│ │ │ │ ├── ParseSpotify+async.swift
│ │ │ │ ├── ParseSpotify+combine.swift
│ │ │ │ └── ParseSpotify.swift
│ │ │ └── ParseTwitter/
│ │ │ ├── ParseTwitter+async.swift
│ │ │ ├── ParseTwitter+combine.swift
│ │ │ └── ParseTwitter.swift
│ │ ├── Internal/
│ │ │ ├── ParseAnonymous+async.swift
│ │ │ ├── ParseAnonymous+combine.swift
│ │ │ └── ParseAnonymous.swift
│ │ └── Protocols/
│ │ ├── ParseAuthentication+async.swift
│ │ ├── ParseAuthentication+combine.swift
│ │ └── ParseAuthentication.swift
│ ├── Coding/
│ │ ├── AnyCodable.swift
│ │ ├── AnyDecodable.swift
│ │ ├── AnyEncodable.swift
│ │ ├── ParseCoding.swift
│ │ └── ParseEncoder.swift
│ ├── Documentation.docc/
│ │ ├── ParseSwift.md
│ │ ├── ParseSwift.tutorial
│ │ └── Your First Object.tutorial
│ ├── Extensions/
│ │ ├── Data.swift
│ │ ├── Date.swift
│ │ ├── Dictionary.swift
│ │ ├── Encodable.swift
│ │ ├── URLCache.swift
│ │ └── URLSession.swift
│ ├── InternalObjects/
│ │ ├── BaseConfig.swift
│ │ ├── BaseParseInstallation.swift
│ │ ├── BaseParseUser.swift
│ │ └── NoBody.swift
│ ├── LiveQuery/
│ │ ├── LiveQueryConstants.swift
│ │ ├── LiveQuerySocket.swift
│ │ ├── Messages.swift
│ │ ├── Operations.swift
│ │ ├── ParseLiveQuery+async.swift
│ │ ├── ParseLiveQuery+combine.swift
│ │ ├── ParseLiveQuery.swift
│ │ ├── ParseLiveQueryConstants.swift
│ │ ├── Protocols/
│ │ │ ├── LiveQuerySocketDelegate.swift
│ │ │ ├── LiveQueryable.swift
│ │ │ ├── ParseLiveQueryDelegate.swift
│ │ │ └── QuerySubscribable.swift
│ │ ├── Subscription.swift
│ │ └── SubscriptionCallback.swift
│ ├── Objects/
│ │ ├── ParseCloudUser.swift
│ │ ├── ParseInstallation+async.swift
│ │ ├── ParseInstallation+combine.swift
│ │ ├── ParseInstallation.swift
│ │ ├── ParseObject+async.swift
│ │ ├── ParseObject+combine.swift
│ │ ├── ParseObject.swift
│ │ ├── ParsePushStatusable.swift
│ │ ├── ParseRole.swift
│ │ ├── ParseSession.swift
│ │ ├── ParseUser+async.swift
│ │ ├── ParseUser+combine.swift
│ │ └── ParseUser.swift
│ ├── Operations/
│ │ ├── Add.swift
│ │ ├── AddRelation.swift
│ │ ├── AddUnique.swift
│ │ ├── Delete.swift
│ │ ├── Increment.swift
│ │ ├── Operation.swift
│ │ ├── Remove.swift
│ │ └── RemoveRelation.swift
│ ├── Parse.h
│ ├── Parse.swift
│ ├── ParseConstants.swift
│ ├── Protocols/
│ │ ├── CloudObservable.swift
│ │ ├── Deletable.swift
│ │ ├── Fetchable.swift
│ │ ├── Fileable.swift
│ │ ├── Objectable.swift
│ │ ├── ParseCloudable+async.swift
│ │ ├── ParseCloudable+combine.swift
│ │ ├── ParseCloudable.swift
│ │ ├── ParseEncodable.swift
│ │ ├── ParseFileTransferable.swift
│ │ ├── ParseHookFunctionable+async.swift
│ │ ├── ParseHookFunctionable+combine.swift
│ │ ├── ParseHookFunctionable.swift
│ │ ├── ParseHookParametable.swift
│ │ ├── ParseHookRequestable+async.swift
│ │ ├── ParseHookRequestable+combine.swift
│ │ ├── ParseHookRequestable.swift
│ │ ├── ParseHookTriggerable+async.swift
│ │ ├── ParseHookTriggerable+combine.swift
│ │ ├── ParseHookTriggerable.swift
│ │ ├── ParseHookable.swift
│ │ ├── ParsePushApplePayloadable.swift
│ │ ├── ParsePushFirebasePayloadable.swift
│ │ ├── ParsePushPayloadable.swift
│ │ ├── ParseQueryScorable.swift
│ │ ├── ParseTypeable.swift
│ │ ├── QueryObservable.swift
│ │ ├── Queryable.swift
│ │ └── Savable.swift
│ ├── Storage/
│ │ ├── KeychainStore.swift
│ │ ├── ParseFileManager.swift
│ │ ├── ParseKeyValueStore.swift
│ │ ├── ParseStorage.swift
│ │ └── SecureStorage.swift
│ └── Types/
│ ├── CloudViewModel.swift
│ ├── Parse.h
│ ├── ParseACL.swift
│ ├── ParseAnalytics+async.swift
│ ├── ParseAnalytics+combine.swift
│ ├── ParseAnalytics.swift
│ ├── ParseBytes.swift
│ ├── ParseCLP.swift
│ ├── ParseConfig+async.swift
│ ├── ParseConfig+combine.swift
│ ├── ParseConfig.swift
│ ├── ParseConfiguration.swift
│ ├── ParseError.swift
│ ├── ParseField.swift
│ ├── ParseFieldOptions.swift
│ ├── ParseFile+async.swift
│ ├── ParseFile+combine.swift
│ ├── ParseFile.swift
│ ├── ParseFileDefaultTransfer.swift
│ ├── ParseGeoPoint.swift
│ ├── ParseHealth+async.swift
│ ├── ParseHealth+combine.swift
│ ├── ParseHealth.swift
│ ├── ParseHookFunctionRequest.swift
│ ├── ParseHookResponse.swift
│ ├── ParseHookTriggerRequest.swift
│ ├── ParseKeychainAccessGroup.swift
│ ├── ParseOperation+async.swift
│ ├── ParseOperation+combine.swift
│ ├── ParseOperation.swift
│ ├── ParsePolygon.swift
│ ├── ParsePush+async.swift
│ ├── ParsePush+combine.swift
│ ├── ParsePush.swift
│ ├── ParsePushPayload/
│ │ ├── Apple/
│ │ │ ├── ParsePushAppleAlert.swift
│ │ │ ├── ParsePushAppleSound.swift
│ │ │ └── ParsePushPayloadApple.swift
│ │ ├── Firebase/
│ │ │ ├── ParsePushFirebaseNotification.swift
│ │ │ └── ParsePushPayloadFirebase.swift
│ │ └── ParsePushPayloadAny.swift
│ ├── ParsePushStatus.swift
│ ├── ParseRelation.swift
│ ├── ParseSchema+async.swift
│ ├── ParseSchema+combine.swift
│ ├── ParseSchema.swift
│ ├── ParseVersion.swift
│ ├── Pointer+async.swift
│ ├── Pointer+combine.swift
│ ├── Pointer.swift
│ ├── Query+async.swift
│ ├── Query+combine.swift
│ ├── Query.swift
│ ├── QueryConstraint.swift
│ ├── QueryViewModel.swift
│ └── QueryWhere.swift
├── TestHost/
│ ├── AppDelegate.swift
│ ├── Assets.xcassets/
│ │ └── AppIcon.appiconset/
│ │ └── Contents.json
│ ├── Base.lproj/
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ └── Info.plist
├── TestHostTV/
│ ├── AppDelegate.swift
│ ├── Assets.xcassets/
│ │ ├── AccentColor.colorset/
│ │ │ └── Contents.json
│ │ ├── App Icon & Top Shelf Image.brandassets/
│ │ │ ├── App Icon - App Store.imagestack/
│ │ │ │ ├── Back.imagestacklayer/
│ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Contents.json
│ │ │ │ ├── Front.imagestacklayer/
│ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Middle.imagestacklayer/
│ │ │ │ ├── Content.imageset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ ├── App Icon.imagestack/
│ │ │ │ ├── Back.imagestacklayer/
│ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Contents.json
│ │ │ │ ├── Front.imagestacklayer/
│ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Middle.imagestacklayer/
│ │ │ │ ├── Content.imageset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── Top Shelf Image Wide.imageset/
│ │ │ │ └── Contents.json
│ │ │ └── Top Shelf Image.imageset/
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Base.lproj/
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ └── ViewController.swift
└── Tests/
├── LinuxMain.swift
└── ParseSwiftTests/
├── APICommandTests.swift
├── AnyCodableTests/
│ ├── AnyCodableTests.swift
│ ├── AnyDecodableTests.swift
│ └── AnyEncodableTests.swift
├── BatchUtilsTests.swift
├── ExtensionsTests.swift
├── IOS13Tests.swift
├── Info.plist
├── InitializeSDKTests.swift
├── KeychainStoreTests.swift
├── MigrateObjCSDKCombineTests.swift
├── MigrateObjCSDKTests.swift
├── NetworkMocking/
│ ├── MockURLProtocol.swift
│ └── MockURLResponse.swift
├── ParseACLTests.swift
├── ParseAnalyticsAsyncTests.swift
├── ParseAnalyticsCombineTests.swift
├── ParseAnalyticsTests.swift
├── ParseAnonymousAsyncTests.swift
├── ParseAnonymousCombineTests.swift
├── ParseAnonymousTests.swift
├── ParseAppleAsyncTests.swift
├── ParseAppleCombineTests.swift
├── ParseAppleTests.swift
├── ParseAuthenticationAsyncTests.swift
├── ParseAuthenticationCombineTests.swift
├── ParseAuthenticationTests.swift
├── ParseBytesTests.swift
├── ParseCLPTests.swift
├── ParseCloudViewModelTests.swift
├── ParseCloudableAsyncTests.swift
├── ParseCloudableCombineTests.swift
├── ParseCloudableTests.swift
├── ParseConfigAsyncTests.swift
├── ParseConfigCombineTests.swift
├── ParseConfigTests.swift
├── ParseEncoderTests/
│ ├── ParseEncoderExtraTests.swift
│ └── TestParseEncoder.swift
├── ParseErrorTests.swift
├── ParseFacebookAsyncTests.swift
├── ParseFacebookCombineTests.swift
├── ParseFacebookTests.swift
├── ParseFileAsyncTests.swift
├── ParseFileCombineTests.swift
├── ParseFileManagerTests.swift
├── ParseFileTests.swift
├── ParseFileTransferableTests.swift
├── ParseGeoPointTests.swift
├── ParseGitHubCombineTests.swift
├── ParseGitHubTests.swift
├── ParseGoogleCombineTests.swift
├── ParseGoogleTests.swift
├── ParseHealthAsyncTests.swift
├── ParseHealthCombineTests.swift
├── ParseHealthTests.swift
├── ParseHookFunctionCombineTests.swift
├── ParseHookFunctionRequestCombineTests.swift
├── ParseHookFunctionRequestTests.swift
├── ParseHookFunctionTests.swift
├── ParseHookResponseTests.swift
├── ParseHookTriggerCombineTests.swift
├── ParseHookTriggerRequestCombineTests.swift
├── ParseHookTriggerRequestTests.swift
├── ParseHookTriggerTests.swift
├── ParseInstagramAsyncTests.swift
├── ParseInstagramCombineTests.swift
├── ParseInstagramTests.swift
├── ParseInstallationAsyncTests.swift
├── ParseInstallationCombineTests.swift
├── ParseInstallationTests.swift
├── ParseKeychainAccessGroupTests.swift
├── ParseLDAPAsyncTests.swift
├── ParseLDAPCombineTests.swift
├── ParseLDAPTests.swift
├── ParseLinkedInCombineTests.swift
├── ParseLinkedInTests.swift
├── ParseLiveQueryAsyncTests.swift
├── ParseLiveQueryCombineTests.swift
├── ParseLiveQueryTests.swift
├── ParseObjectAsyncTests.swift
├── ParseObjectBatchTests.swift
├── ParseObjectCombineTests.swift
├── ParseObjectCustomObjectIdTests.swift
├── ParseObjectTests.swift
├── ParseOperationAsyncTests.swift
├── ParseOperationCombineTests.swift
├── ParseOperationTests.swift
├── ParsePointerAsyncTests.swift
├── ParsePointerCombineTests.swift
├── ParsePointerTests.swift
├── ParsePolygonTests.swift
├── ParsePushAsyncTests.swift
├── ParsePushCombineTests.swift
├── ParsePushPayloadAnyTests.swift
├── ParsePushPayloadAppleTests.swift
├── ParsePushPayloadFirebaseTests.swift
├── ParsePushTests.swift
├── ParseQueryAsyncTests.swift
├── ParseQueryCacheTests.swift
├── ParseQueryCombineTests.swift
├── ParseQueryTests.swift
├── ParseQueryViewModelTests.swift
├── ParseRelationTests.swift
├── ParseRoleTests.swift
├── ParseSchemaAsyncTests.swift
├── ParseSchemaCombineTests.swift
├── ParseSchemaTests.swift
├── ParseSessionTests.swift
├── ParseSpotifyAsyncTests.swift
├── ParseSpotifyCombineTests.swift
├── ParseSpotifyTests.swift
├── ParseTwitterAsyncTests.swift
├── ParseTwitterCombineTests.swift
├── ParseTwitterTests.swift
├── ParseUserAsyncTests.swift
├── ParseUserCombineTests.swift
├── ParseUserTests.swift
└── ParseVersionTests.swift
================================================
FILE CONTENTS
================================================
================================================
FILE: .codecov.yml
================================================
coverage:
ignore:
- Tests/ParseSwiftTests/.*
- TestHost/*
- TestHostTV/*
status:
patch:
default:
target: auto
changes: false
project:
default:
target: 89
comment:
require_changes: true
================================================
FILE: .github/ISSUE_TEMPLATE/---1-report-an-issue.md
================================================
---
name: "\U0001F41B Report an issue"
about: A feature is not working as expected.
title: ''
labels: ''
assignees: ''
---
### New Issue Checklist
<!--
Check every following box [x] before submitting your issue.
Click the "Preview" tab for better readability.
Thanks for contributing to Parse Platform!
-->
- [ ] I am not disclosing a [vulnerability](https://github.com/parse-community/Parse-Swift/security/policy).
- [ ] I am not just asking a [question](https://github.com/parse-community/.github/blob/main/SUPPORT.md).
- [ ] I have searched through [existing issues](https://github.com/parse-community/Parse-Swift/issues?q=is%3Aissue).
- [ ] I can reproduce the issue with the latest versions of [Parse Server](https://github.com/parse-community/parse-server/releases) and the [Parse Swift SDK](https://github.com/parse-community/Parse-Swift/releases). <!-- We don't investigate issues for outdated releases. -->
### Issue Description
<!-- What is the specific issue? -->
### Steps to reproduce
<!-- How can someone else reproduce the issue? -->
### Actual Outcome
<!-- What outcome did you get? -->
### Expected Outcome
<!-- What outcome did you expect? -->
### Environment
<!-- Be specific with versions, don't use "latest" or semver ranges like "~x.y.z" or "^x.y.z". -->
Client
- Parse Swift SDK version: `FILL_THIS_OUT`
- Xcode version: `FILL_THIS_OUT`
- Operating system (iOS, macOS, watchOS, etc.): `FILL_THIS_OUT`
- Operating system version: `FILL_THIS_OUT`
Server
- Parse Server version: `FILL_THIS_OUT`
- Operating system: `FILL_THIS_OUT`
- Local or remote host (AWS, Azure, Google Cloud, Heroku, Digital Ocean, etc): `FILL_THIS_OUT`
Database
- System (MongoDB or Postgres): `FILL_THIS_OUT`
- Database version: `FILL_THIS_OUT`
- Local or remote host (MongoDB Atlas, mLab, AWS, Azure, Google Cloud, etc): `FILL_THIS_OUT`
### Logs
<!-- Include relevant logs here. -->
================================================
FILE: .github/ISSUE_TEMPLATE/---2-feature-request.md
================================================
---
name: "\U0001F4A1 Request a feature"
about: Suggest new functionality or an enhancement of existing functionality.
title: ''
labels: ''
assignees: ''
---
### New Feature / Enhancement Checklist
<!--
Check all of the following boxes [x] before submitting your issue.
Click the "Preview" tab for better readability.
Thanks for contributing to Parse Swift!
-->
- [ ] I am not disclosing a [vulnerability](https://github.com/parse-community/Parse-Swift/security/policy).
- [ ] I am not just asking a [question](https://github.com/parse-community/.github/blob/main/SUPPORT.md).
- [ ] I have searched through [existing issues](https://github.com/parse-community/Parse-Swift/issues?q=is%3Aissue).
### Current Limitation
<!-- Which current limitation is the feature or enhancement addressing? -->
### Feature / Enhancement Description
<!-- What is the concept of the functionality and how should it be implemented? -->
### Example Use Case
<!-- What is an example use case in steps (1. / 2. / 3. / etc.) that describes the functionality? -->
### Alternatives / Workarounds
<!-- Which alternatives or workarounds exist currently? -->
### 3rd Party References
<!-- Have you seen a similar functionality provided somewhere else? -->
================================================
FILE: .github/ISSUE_TEMPLATE/config.yml
================================================
blank_issues_enabled: false
contact_links:
- name: 🙋🏽♀️ Getting help with code
url: https://stackoverflow.com/questions/tagged/parse-platform
about: Get help with code-level questions on Stack Overflow.
- name: 🙋 Getting general help
url: https://community.parseplatform.org
about: Get help with other questions on our Community Forum.
================================================
FILE: .github/pull_request_template.md
================================================
### New Pull Request Checklist
<!--
Please check the following boxes [x] before submitting your issue.
Click the "Preview" tab for better readability.
Thanks for contributing to Parse Platform!
-->
- [ ] I am not disclosing a [vulnerability](https://github.com/parse-community/Parse-Swift/security/policy).
- [ ] I am creating this PR in reference to an [issue](https://github.com/parse-community/Parse-Swift/issues?q=is%3Aissue).
### Issue Description
<!-- Add a brief description of the issue this PR solves. -->
Closes: FILL_THIS_OUT
### Approach
<!-- Add a description of the approach in this PR. -->
### TODOs before merging
<!--
Add TODOs that need to be completed before merging this PR.
Delete TODOs that do not apply to this PR.
-->
- [ ] Add tests
- [ ] Add entry to changelog
- [ ] Add changes to documentation (guides, repository pages, in-code descriptions)
================================================
FILE: .github/workflows/ci.yml
================================================
name: ci
on:
push:
branches: [ main ]
pull_request:
branches: '*'
env:
CI_XCODE_OLDEST: '/Applications/Xcode_12.5.1.app/Contents/Developer'
CI_XCODE_13: '/Applications/Xcode_13.4.1.app/Contents/Developer'
CI_XCODE_LATEST: '/Applications/Xcode_14.0.1.app/Contents/Developer'
jobs:
xcode-test-ios:
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- name: Use multiple cores
run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1
- name: Build-Test
run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -workspace Parse.xcworkspace -scheme ParseSwift\ \(iOS\) -destination platform\=iOS\ Simulator,name\=iPhone\ 12\ Pro\ Max -derivedDataPath DerivedData -test-iterations 10 -retry-tests-on-failure clean test | xcpretty
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
- name: Export code coverage
run: |
PROFDATA=$(find ./DerivedData -name 'Coverage.profdata' -type f | head -1)
XCTEST=$(find ./DerivedData -name '*.xctest' -type d | head -1)
EXEC="$XCTEST/Contents/MacOS/$(basename "$XCTEST" .xctest)"
xcrun llvm-cov export -format="lcov" "$EXEC" -instr-profile "$PROFDATA" > coverage.lcov
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: coverage.lcov
env_vars: IOS
fail_ci_if_error: true
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
xcode-test-macos:
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- name: Create and set the default keychain
run: |
security create-keychain -p "" temporary
security default-keychain -s temporary
security unlock-keychain -p "" temporary
security set-keychain-settings -lut 7200 temporary
- name: Use multiple cores
run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1
- name: Build-Test
run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -workspace Parse.xcworkspace -scheme ParseSwift\ \(macOS\) -destination platform\=macOS -derivedDataPath DerivedData -test-iterations 10 -retry-tests-on-failure clean test | xcpretty
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
- name: Export code coverage
run: |
PROFDATA=$(find ./DerivedData -name 'Coverage.profdata' -type f | head -1)
XCTEST=$(find ./DerivedData -name '*.xctest' -type d | head -1)
EXEC="$XCTEST/Contents/MacOS/$(basename "$XCTEST" .xctest)"
xcrun llvm-cov export -format="lcov" "$EXEC" -instr-profile "$PROFDATA" > coverage.lcov
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: coverage.lcov
env_vars: MACOS
fail_ci_if_error: true
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
xcode-test-tvos:
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- name: Use multiple cores
run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1
- name: Build
run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -workspace Parse.xcworkspace -scheme ParseSwift\ \(tvOS\) -destination platform\=tvOS\ Simulator,name\=Apple\ TV -derivedDataPath DerivedData -test-iterations 10 -retry-tests-on-failure clean test | xcpretty
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
- name: Export code coverage
run: |
PROFDATA=$(find ./DerivedData -name 'Coverage.profdata' -type f | head -1)
XCTEST=$(find ./DerivedData -name '*.xctest' -type d | head -1)
EXEC="$XCTEST/Contents/MacOS/$(basename "$XCTEST" .xctest)"
xcrun llvm-cov export -format="lcov" "$EXEC" -instr-profile "$PROFDATA" > coverage.lcov
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: coverage.lcov
env_vars: TVOS
fail_ci_if_error: true
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
xcode-build-watchos:
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- name: Use multiple cores
run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1
- name: Build
run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -target ParseSwift\ \(watchOS\) | xcpretty
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
env_vars: WATCHOS
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
spm-test:
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- name: Create and set the default keychain
run: |
security create-keychain -p "" temporary
security default-keychain -s temporary
security unlock-keychain -p "" temporary
security set-keychain-settings -lut 7200 temporary
- name: Use multiple cores
run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1
- name: Build and Test
run: swift test --enable-code-coverage -v
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
- name: Export code coverage
run: |
BIN_PATH=$(swift build --show-bin-path)
XCTEST=$(find "$BIN_PATH" -name '*.xctest' -type d | head -1)
PROFDATA=$(find .build -name 'default.profdata' -type f)
xcrun llvm-cov export -format="lcov" "$XCTEST" -instr-profile "$PROFDATA" > coverage.lcov
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: coverage.lcov
env_vars: SPM
fail_ci_if_error: true
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
spm-test-5_2:
needs: xcode-build-watchos
runs-on: macos-latest
steps:
- uses: actions/checkout@v3
- name: Build-Test
run: set -o pipefail && env NSUnbufferedIO=YES xcodebuild -workspace Parse.xcworkspace -scheme ParseSwift\ \(iOS\) -destination platform\=iOS\ Simulator,name\=iPhone\ 11 -derivedDataPath DerivedData clean test | xcpretty
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_OLDEST }}
- name: Export code coverage
run: |
PROFDATA=$(find ./DerivedData -name 'Coverage.profdata' -type f | head -1)
XCTEST=$(find ./DerivedData -name '*.xctest' -type d | head -1)
EXEC="$XCTEST/Contents/MacOS/$(basename "$XCTEST" .xctest)"
xcrun llvm-cov export -format="lcov" "$EXEC" -instr-profile "$PROFDATA" > coverage.lcov
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
files: coverage.lcov
env_vars: IOS_Earliest
fail_ci_if_error: true
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_OLDEST }}
linux:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v3
- uses: swift-actions/setup-swift@v2
with:
swift-version: "5"
- name: Build and Test
run: swift test --enable-test-discovery --enable-code-coverage -v
- name: Prepare codecov
run: |
llvm-cov export -format="lcov" .build/x86_64-unknown-linux-gnu/debug/ParseSwiftPackageTests.xctest -instr-profile .build/x86_64-unknown-linux-gnu/debug/codecov/default.profdata > info_linux.lcov
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
env_vars: LINUX
fail_ci_if_error: true
windows:
runs-on: windows-2019
steps:
- uses: actions/checkout@v3
- uses: swift-actions/setup-swift@v2
with:
swift-version: "5.5.1"
- name: Build and Test
run: |
swift test --enable-test-discovery --enable-code-coverage -v
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
env_vars: WINDOWS
fail_ci_if_error: false
windows-latest:
runs-on: windows-latest
steps:
- uses: actions/checkout@v3
- uses: swift-actions/setup-swift@v2
with:
swift-version: "5.6.3"
- name: Build
run: |
swift build -v
- name: Upload coverage to Codecov
uses: codecov/codecov-action@v3
with:
env_vars: WINDOWSLATEST
fail_ci_if_error: false
docs:
needs: xcode-build-watchos
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- name: Use multiple cores
run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1
- name: Generate Docs
run: set -o pipefail && env NSUnbufferedIO=YES Scripts/generate-documentation
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
cocoapods:
needs: xcode-build-watchos
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- name: Use multiple cores
run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1
- name: Update Framework Version
run: ./Scripts/update_build
env:
BUILD_VERSION: '1.8.3'
- name: CocoaPods
run: pod lib lint --allow-warnings
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_13 }}
carthage:
needs: xcode-build-watchos
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- name: Use multiple cores
run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1
- name: Carthage
run: ./Scripts/carthage.sh build --no-skip-current --use-xcframeworks
env:
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
================================================
FILE: .github/workflows/release.yml
================================================
name: release
on:
release:
types: [published]
env:
CI_XCODE_13: '/Applications/Xcode_13.4.1.app/Contents/Developer'
CI_XCODE_LATEST: '/Applications/Xcode_14.0.1.app/Contents/Developer'
jobs:
cocoapods:
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- name: Get release version
run: echo "TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV
- name: Use multiple cores
run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1
- name: Update Framework Version
run: ./Scripts/update_build
env:
BUILD_VERSION: ${{ env.TAG }}
- name: Deploy CocoaPods
run: set -o pipefail && env NSUnbufferedIO=YES pod trunk push ParseSwift.podspec --allow-warnings --verbose
env:
COCOAPODS_TRUNK_TOKEN: ${{ secrets.COCOAPODS_TRUNK_TOKEN }}
DEVELOPER_DIR: ${{ env.CI_XCODE_13 }}
docs:
runs-on: macos-12
steps:
- uses: actions/checkout@v3
- name: Get release version
run: echo "TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV
- name: Use multiple cores
run: defaults write com.apple.dt.XCBuild EnableSwiftBuildSystemIntegration 1
- name: Build and Deploy Docs
run: set -o pipefail && env NSUnbufferedIO=YES Scripts/update-gh-pages-documentation-site
env:
CURRENT_BRANCH_NAME: release
DEVELOPER_DIR: ${{ env.CI_XCODE_LATEST }}
================================================
FILE: .gitignore
================================================
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
## Build generated
build/
DerivedData/
.swiftpm
docs/
## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/
## Other
.DS_Store
*.moved-aside
*.xccheckout
*.xcscmblueprint
## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM
## Playgrounds
timeline.xctimeline
playground.xcworkspace
# Swift Package Manager
#
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies.
# Packages/
# Package.pins
.build/
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build
# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control
fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output
================================================
FILE: .spi.yml
================================================
version: 1
builder:
configs:
- platform: ios
scheme: "ParseSwift (iOS)"
- platform: macos-spm
documentation_targets: [ParseSwift]
- platform: macos-xcodebuild
scheme: "ParseSwift (macOS)"
- platform: macos-xcodebuild-arm
scheme: "ParseSwift (macOS)"
- platform: tvos
scheme: "ParseSwift (tvOS)"
- platform: watchos
scheme: "ParseSwift (watchOS)"
================================================
FILE: .swiftlint.yml
================================================
disabled_rules:
- file_length
- cyclomatic_complexity
- function_body_length
- type_body_length
- inclusive_language
- comment_spacing
- identifier_name
excluded: # paths to ignore during linting. Takes precedence over `included`.
- Tests/ParseSwiftTests/ParseEncoderTests
- DerivedData
- .build
- .dependencies
================================================
FILE: CHANGELOG.md
================================================
# Parse-Swift Changelog
### main
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.14.2...main), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/main/documentation/parseswift)
* _Contributing to this repo? Add info about your change here to be included in the next release_
### 4.14.2
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.14.1...4.14.2), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.14.2/documentation/parseswift)
__Fixes__
- Addressed an issue that prevented updating ParseObjects with saveAll ([#423](https://github.com/parse-community/Parse-Swift/pull/423)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.14.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.14.0...4.14.1), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.14.1/documentation/parseswift)
__Fixes__
- For Swift 5.5.2+ all asynchronous methods that attempt to save, create, update, or replace use the async/await version of deep saving ParseObjects. This fixes any purple warnings caused by the SDK in Xcode. Older Swift versions use the synchronous version of deep saving ([#418](https://github.com/parse-community/Parse-Swift/pull/418)), thanks to [Corey Baker](https://github.com/cbaker6).
- Can catch when the Parse Server throws an improper ParseError that only contains "error" or "message", but does not contain a "code" ([#418](https://github.com/parse-community/Parse-Swift/pull/418)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.14.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.13.1...4.14.0), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.14.0/documentation/parseswift)
__New features__
- Add file caching using the Parse download folder ([#416](https://github.com/parse-community/Parse-Swift/pull/416)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.13.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.13.0...4.13.1), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.13.1/documentation/parseswift)
__Fixes__
- Remove ParseFile caching due to OS not having a natural way to cache files. Instead, if developers want to access a saved ParseFile, they should check the download directory for the respective file name ([#414](https://github.com/parse-community/Parse-Swift/pull/414)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.13.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.12.0...4.13.0), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.13.0/documentation/parseswift)
__New features__
- Add helper methods to ParseFileTransferable protocol to assist with creating propper responses to file uploads ([#411](https://github.com/parse-community/Parse-Swift/pull/411)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- Remove cached error responses when decoding errors occur ([#411](https://github.com/parse-community/Parse-Swift/pull/411)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.12.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.11.0...4.12.0), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.12.0/documentation/parseswift)
__New features__
- Add the ParseFileTransferable protocol for overriding the default transfer behavior for ParseFile's. Allows for direct uploads to other file storage providers ([#410](https://github.com/parse-community/Parse-Swift/pull/410)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add the become method to ParseInstallation which allows any ParseInstallation to be copied to the current installation. This method can be used to migrate any ParseInstallation to the current installation in the Swift SDK ([#407](https://github.com/parse-community/Parse-Swift/pull/407)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- Properly get the session token from the Parse Objective-C Keychain when using ParseUser.loginUsingObjCKeychain ([#407](https://github.com/parse-community/Parse-Swift/pull/407)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.11.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.10.0...4.11.0), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.11.0/documentation/parseswift)
__New features__
- Add a set method that developers can call on their ParseObjects which automatically sends updated properties to a Parse Server and merges those updates with the original ParseObject locally. The feature removes the requirement to call mergeable and implement merge(), but comes at additional computational overhead ([#406](https://github.com/parse-community/Parse-Swift/pull/406)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.10.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.9.3...4.10.0), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.10.0/documentation/parseswift)
__New features__
- Add a new operation method that allows developers to set a new value to a KeyPath without needing the string version of the key. Also adds the get() method to allow developers to get the unwrapped property of any ParseObject based on its KeyPath ([#403](https://github.com/parse-community/Parse-Swift/pull/403)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add revertKeyPath() and revertObject() methods to ParseObject which allow developers to revert to original values of key paths or objects after mutating ParseObjects that already have an objectId ([#402](https://github.com/parse-community/Parse-Swift/pull/402)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.9.3
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.9.2...4.9.3), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.9.3/documentation/parseswift)
__Fixes__
- When saving ParseFiles locally, files that have a directory in their filename save correctly instead of throwing an error on the client ([#399](https://github.com/parse-community/Parse-Swift/pull/399)), thanks to [Corey Baker](https://github.com/cbaker6).
- Default to not setting kSecUseDataProtectionKeychain to true as this can cause issues with querying the Keychain in Swift Playgrounds or other apps that cannot setup the Keychain on macOS. This behavior can be changed by setting usingDataProtectionKeychain to true when initializing the SDK ([#398](https://github.com/parse-community/Parse-Swift/pull/398)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.9.2
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.9.1...4.9.2), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.9.2/documentation/parseswift)
__Fixes__
- Allow fully qualified ParseSwift types to be used externally by fixing clash with module name ([#397](https://github.com/parse-community/Parse-Swift/pull/397)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.9.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.9.0...4.9.1), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.9.1/documentation/parseswift)
__Fixes__
- Corrects a memory leak where multiple Parse URLSessions can get created. Use an actor for the url session delegates to ensure thread safety when making async calls in parallel ([#394](https://github.com/parse-community/Parse-Swift/pull/394)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.9.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.8.0...4.9.0), [Documentation](https://swiftpackageindex.com/parse-community/Parse-Swift/4.9.0/documentation/parseswift)
__New features__
- Add methods for migrating users and installations from the Parse Objective-C SDK to the Swift SDK ([#391](https://github.com/parse-community/Parse-Swift/pull/391)), thanks to [Corey Baker](https://github.com/cbaker6).
- Enable query caching by using GET instead of POST. GET is now used by default. To switch back to POST, set usingPostForQuery = true when initializing the SDK which will automatically disable all query caching ([#386](https://github.com/parse-community/Parse-Swift/pull/386)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add setAccessGroup method which allows the Parse Keychain to be shared with app extensions and iCloud accounts ([#378](https://github.com/parse-community/Parse-Swift/pull/378)), thanks to [Corey Baker](https://github.com/cbaker6).
__Improvements__
- Add more details to error messages related when decoding errors occur ([#388](https://github.com/parse-community/Parse-Swift/pull/388)), thanks to [Daniel Blyth](https://github.com/dblythy).
- Added discardableResult to allow developers to choose whether or not certain functions should return a result ([#385](https://github.com/parse-community/Parse-Swift/pull/385)), thanks to [Damian Van de Kauter](https://github.com/vdkdamian).
__Fixes__
- Ensure properties that are already saved ParseObject's are converted to Parse pointers when using saveAll ([#390](https://github.com/parse-community/Parse-Swift/pull/390)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.8.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.7.0...4.8.0)
__New features__
- Add ParseSpotify authentication ([#375](https://github.com/parse-community/Parse-Swift/pull/375)), thanks to [Ulaş Sancak](https://github.com/rocxteady).
__Fixes__
- Encode withinPolygon Queryconstraint correctly ([#381](https://github.com/parse-community/Parse-Swift/pull/381)), thanks to [Corey Baker](https://github.com/cbaker6).
- Use select for ParseLiveQuery when fields are not present ([#376](https://github.com/parse-community/Parse-Swift/pull/376)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.7.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.6.0...4.7.0)
__New features__
- Add support for ParseFile and beforeConnect triggers ([#376](https://github.com/parse-community/Parse-Swift/pull/376)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.6.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.5.0...4.6.0)
__New features__
- Add the ability to use Parse Hooks and Triggers ([#373](https://github.com/parse-community/Parse-Swift/pull/373)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add ParseInstagram authentication ([#372](https://github.com/parse-community/Parse-Swift/pull/372)), thanks to [Ulaş Sancak](https://github.com/rocxteady).
- Add the ability to send APN and FCM push notifications. Also adds the ability to query _PushStatus ([#371](https://github.com/parse-community/Parse-Swift/pull/371)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add ParseSchema, ParseCLP, and ParseFieldOptions. Should only be used when using the Swift SDK on a secured server ([#370](https://github.com/parse-community/Parse-Swift/pull/370)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.5.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.4.0...4.5.0)
__New features__
- Add toCLLocation and toCLLocationCoordinate2D computed properties to ParseGeoPoint, deprecate toCLLocation() and toCLLocationCoordinate2D() ([#366](https://github.com/parse-community/Parse-Swift/pull/366)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add query computed property to ParseObject ([#365](https://github.com/parse-community/Parse-Swift/pull/365)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add macCatalyst to SPM ([#363](https://github.com/parse-community/Parse-Swift/pull/363)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add an order() method to Query that excepts a variadic list as input ([#362](https://github.com/parse-community/Parse-Swift/pull/362)), thanks to [Corey Baker](https://github.com/cbaker6).
__Improvements__
- Allow includeAll key to be sent with additional include keys. When fetching, if the include argument is specified, convert it to a Set to prevent duplicate keys from being sent to the server ([#367](https://github.com/parse-community/Parse-Swift/pull/367)), thanks to [Corey Baker](https://github.com/cbaker6).
- Allow LiveQuery client to be set using ParseLiveQuery.defaultClient and deprecate ParseLiveQuery.setDefault(). Show usage of deprecated code as warnings during compile time and suggest changes ([#360](https://github.com/parse-community/Parse-Swift/pull/360)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.4.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.3.1...4.4.0)
__Improvements__
- Drop support for Swift 5.2 as App Store requires apps to be built in Xcode 12 ([#356](https://github.com/parse-community/Parse-Swift/pull/356)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.3.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.3.0...4.3.1)
__Fixes__
- Fix links to API documentation ([#354](https://github.com/parse-community/Parse-Swift/pull/354)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.3.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.2.0...4.3.0)
__Improvements__
- Use DocC for documentation instead of jazzy. Improved documentation ([#350](https://github.com/parse-community/Parse-Swift/pull/350)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.2.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.1.0...4.2.0)
__New features__
- Add variadic QueryConstraint methods for or, nor, and ([#345](https://github.com/parse-community/Parse-Swift/pull/345)), thanks to [Corey Baker](https://github.com/cbaker6).
__Improvements__
- Add clientDefault static property to ParseLiveQuery which replaces the getDefault() method. getDefault() is still avaiable, but will be deprecated in ParseSwift 5.0.0 so it is recommended to switch to defaultClient ([#342](https://github.com/parse-community/Parse-Swift/pull/342)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.1.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.0.1...4.1.0)
__Improvements__
- Let the OS and developer decide if app tracking authorization is required when using ParseAnalytics. ParseAnalytics can now take any Codable value in its' dimensions instead of just strings. Added a new property "date" to ParseAnalytics. The "at" property will be deprecated in ParseSwift 5.0.0, so developers should switch to "date". ParseAnalytics can now be properly decoded after encoding with a JSONEncoder. This is useful if ParseAnalytics need to be stored locally and sent to the server later ([#341](https://github.com/parse-community/Parse-Swift/pull/341)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.0.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.0.0...4.0.1)
__Fixes__
- Allow ParseRole's to be updated when the SDK is allowing custom objectId's ([#338](https://github.com/parse-community/Parse-Swift/pull/338)), thanks to [Corey Baker](https://github.com/cbaker6).
### 4.0.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/3.1.2...4.0.0)
__New features__
- Add the verifyPassword to ParseUser. This method defaults to using POST though POST is not available on the current Parse Server. Change userPost == false to use GET on older Parse Servers ([#333](https://github.com/parse-community/Parse-Swift/pull/333)), thanks to [Corey Baker](https://github.com/cbaker6).
- (Breaking Change) Bump the SPM toolchain from 5.1 to 5.5. This is done to take advantage of features in the latest toolchain. For developers using < Xcode 13 and depending on the Swift SDK through SPM, this will cause a break. You can either upgrade your Xcode or use Cocoapods or Carthage to depend on ParseSwift ([#326](https://github.com/parse-community/Parse-Swift/pull/326)), thanks to [Corey Baker](https://github.com/cbaker6).
- (Breaking Change) Add the ability to merge updated ParseObject's with original objects when using the .mergeable property. To do this, developers need to add an implementation of merge() to respective ParseObject's. The compiler will recommend the new originalData property be added to every ParseObject. If you used ParseObjectMutable in the past, you should remove it as it is now part of ParseObject. In addition, all ParseObject properties should be optional and every object needs to have a default initializer of init(). See the Playgrounds for recommendations on how to define a ParseObject. Look at the PR for details on why this is important when using the SDK ([#315](https://github.com/parse-community/Parse-Swift/pull/315)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add DocC for SDK documentation ([#209](https://github.com/parse-community/Parse-Swift/pull/214)), thanks to [Corey Baker](https://github.com/cbaker6).
__Improvements__
- (Breaking Change) Make ParseRelation conform to Codable and add methods to make decoded stored ParseRelations "usable". ParseObjects can now contain properties of ParseRelation<Self>. In addition, ParseRelations can now be made from ParseObject pointers. For ParseRole, the computed properties: users and roles, are now optional. The queryRoles property has been changed to queryRoles() to improve the handling of thrown errors ([#328](https://github.com/parse-community/Parse-Swift/pull/328)), thanks to [Corey Baker](https://github.com/cbaker6).
- (Breaking Change) Change the following method parameter names: isUsingMongoDB -> usingMongoDB, isIgnoreCustomObjectIdConfig -> ignoringCustomObjectIdConfig, isUsingEQ -> usingEqComparator ([#321](https://github.com/parse-community/Parse-Swift/pull/321)), thanks to [Corey Baker](https://github.com/cbaker6).
- (Breaking Change) Change the following method parameter names: isUsingMongoDB -> usingMongoDB, isIgnoreCustomObjectIdConfig -> ignoringCustomObjectIdConfig, isUsingEQ -> usingEqComparator ([#321](https://github.com/parse-community/Parse-Swift/pull/321)), thanks to [Corey Baker](https://github.com/cbaker6).
- (Breaking Change) Change the following method parameter names: isUsingTransactions -> usingTransactions, isAllowingCustomObjectIds -> allowingCustomObjectIds, isUsingEqualQueryConstraint -> usingEqualQueryConstraint, isMigratingFromObjcSDK -> migratingFromObjcSDK, isDeletingKeychainIfNeeded -> deletingKeychainIfNeeded ([#323](https://github.com/parse-community/Parse-Swift/pull/323)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- Async/await methods that return void would no throw errors received from server ([#334](https://github.com/parse-community/Parse-Swift/pull/334)), thanks to [Corey Baker](https://github.com/cbaker6).
- Always check for ParseError first when decoding responses from the server. Before this fix, this could cause issues depending on how calls are made from the Swift SDK ([#332](https://github.com/parse-community/Parse-Swift/pull/332)), thanks to [Corey Baker](https://github.com/cbaker6).
### 3.1.2
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/3.1.1...3.1.2)
__Fixes__
- Allowing building of the Swift SDK for Swift 5.5.0 and 5.5.1 re-enabling builds for Xcode 13.0 and 13.1. Note that async/await functionality is only available for Swift 5.5.2+ and Xcode 13.2+ ([#320](https://github.com/parse-community/Parse-Swift/pull/320)), thanks to [Corey Baker](https://github.com/cbaker6).
- Move the var score: Double? to a protocol named ParseQueryScorable. When developers want to sort by score using a matchesText QueryConstraint, they just conform their ParseObject's to ParseQueryScorable ([#319](https://github.com/parse-community/Parse-Swift/pull/319)), thanks to [Corey Baker](https://github.com/cbaker6).
### 3.1.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/3.1.0...3.1.1)
__Fixes__
- Always sort keys when using the ParseEncoder as it can cause issues when trying to save ParseObject's that have children ([#318](https://github.com/parse-community/Parse-Swift/pull/318)), thanks to [Corey Baker](https://github.com/cbaker6).
### 3.1.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/3.0.0...3.1.0)
__New features__
- Add the ability to explain MongoDB queries by setting usingMongoDB = true for the respective explain query ([#314](https://github.com/parse-community/Parse-Swift/pull/314)), thanks to [Corey Baker](https://github.com/cbaker6).
### 3.0.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.5.1...3.0.0)
__New features__
- Adds equalTo QueryConstraint along with ability to change the SDK default behavior of using $eq QueryConstraint parameter or not ([#310](https://github.com/parse-community/Parse-Swift/pull/310)), thanks to [Corey Baker](https://github.com/cbaker6).
- Adds isNull and isNotNull QueryConstraint along with the ability set/forceSet null using ParseOperation ([#308](https://github.com/parse-community/Parse-Swift/pull/308)), thanks to [Corey Baker](https://github.com/cbaker6).
- Adds auth support for GitHub, Google, and LinkedIn ([#307](https://github.com/parse-community/Parse-Swift/pull/307)), thanks to [Corey Baker](https://github.com/cbaker6).
- (Breaking Change) Adds options to matchesText QueryConstraint along with the ability to see matching score. The compiler will recommend the new score property be added to all ParseObjects ([#306](https://github.com/parse-community/Parse-Swift/pull/306)), thanks to [Corey Baker](https://github.com/cbaker6).
- Adds withCount query ([#306](https://github.com/parse-community/Parse-Swift/pull/306)), thanks to [Corey Baker](https://github.com/cbaker6).
__Improvements__
- (Breaking Change) Change boolean configuration parameters to match Swift conventions. The compilor should help with name changes ([#311](https://github.com/parse-community/Parse-Swift/pull/311)), thanks to [Corey Baker](https://github.com/cbaker6).
- Improve QueryWhere by making at a set of QueryConstraint's instead of any array. This dedupes the same constraint when encoding the query; improving the encoding speed when the same constraints are added ([#308](https://github.com/parse-community/Parse-Swift/pull/308)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.5.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.5.0...2.5.1)
__Improvements__
- Reduce call sites by having all methods with variadic arguments call their array counterparts ([#301](https://github.com/parse-community/Parse-Swift/pull/301)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- Let additional headers accept [AnyHashable: Any] ([#302](https://github.com/parse-community/Parse-Swift/pull/302)), thanks to [Corey Baker](https://github.com/cbaker6).
- Throw .missingObjectId when missing the client detects a missing objectId instead of throwing an .unknown error ([#300](https://github.com/parse-community/Parse-Swift/pull/300)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.5.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.4.0...2.5.0)
__New features__
- Added create(), replace(), update(), createAll(), replaceAll(), and updateAll() to ParseObjects. Currently, update() and updateAll() are unavaivalble due to limitations of PATCH on the Parse Server ([#299](https://github.com/parse-community/Parse-Swift/pull/299)), thanks to [Corey Baker](https://github.com/cbaker6).
- Added convenience methods to convert ParseObject's to Pointer<ParseObject>'s for QueryConstraint's: !=, containedIn, notContainedIn, containedBy, containsAll ([#298](https://github.com/parse-community/Parse-Swift/pull/298)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.4.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.3.1...2.4.0)
__New features__
- Added additional methods to ParseRelation to make it easier to create and query relations ([#294](https://github.com/parse-community/Parse-Swift/pull/294)), thanks to [Corey Baker](https://github.com/cbaker6).
- Enable async/await for iOS13, tvOS13, watchOS6, and macOS10_15. All async/await methods are MainActor's. Requires Xcode 13.2 or above to use async/await. Not compatible with Xcode 13.0/1, will need to upgrade to 13.2+. Still works with Xcode 11/12 ([#278](https://github.com/parse-community/Parse-Swift/pull/278)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- When transactions are enabled errors are now thrown from the client if the amount of objects in a transaction exceeds the batch size. An error will also be thrown if a developer attempts to save objects in a transation that has unsaved children ([#295](https://github.com/parse-community/Parse-Swift/pull/294)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.3.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.3.0...2.3.1)
__Fixes__
- Fixed an issue where querying an object did not dispatch to the proper queue which can cause app crashes ([#293](https://github.com/parse-community/Parse-Swift/pull/293)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.3.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.2.6...2.3.0)
__New features__
- Add a retry mechanism to the SDK that randomly (up to 3 seconds each) tries to reconnect up to 5 times. The developer can increase or reduce the amount of retries when configuring the SDK ([#291](https://github.com/parse-community/Parse-Swift/pull/291)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add toCLLocation and toCLLocationCoordinate2D methods for easy conversion from a ParseGeoPoint object ([#287](https://github.com/parse-community/Parse-Swift/pull/287)), thanks to [Jayson Ng](https://github.com/jaysonng).
__Fixes__
- Fixed an issue where an annonymous could not be turned into a regular user using signup ([#291](https://github.com/parse-community/Parse-Swift/pull/291)), thanks to [Corey Baker](https://github.com/cbaker6).
- The default ACL is now deleted from the keychain when a user is logged out. This previously caused an issue when logging out a user and logging in as a different user caused all objects to only have ACL permisions for the logged in user ([#291](https://github.com/parse-community/Parse-Swift/pull/291)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.2.6
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.2.5...2.2.6)
__Fixes__
- Use default ACL automatically on newley created ParseObject's if a default ACL is available ([#284](https://github.com/parse-community/Parse-Swift/pull/284)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.2.5
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.2.4...2.2.5)
__Fixes__
- Overload QueryConstraint to accept Pointer<ParseObject> ([#281](https://github.com/parse-community/Parse-Swift/pull/281)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add checks to build for Windows ([#281](https://github.com/parse-community/Parse-Swift/pull/281)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.2.4
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.2.3...2.2.4)
__Fixes__
- Delete all stored Parse data and cache when isDeletingKeychainIfNeeded is true ([#280](https://github.com/parse-community/Parse-Swift/pull/280)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.2.3
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.2.2...2.2.3)
__Fixes__
- Improve dpcumentation ([#276](https://github.com/parse-community/Parse-Swift/pull/276)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.2.2
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.2.1...2.2.2)
__Fixes__
- Improve equatable comparison of QueryConstraint ([#275](https://github.com/parse-community/Parse-Swift/pull/275)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.2.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.2.0...2.2.1)
__Fixes__
- Set the default cache policy for ParseFile to the default policy set when initializing the SDK ([#274](https://github.com/parse-community/Parse-Swift/pull/274)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.2.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.1.0...2.2.0)
__Improvements__
- Added ability to fetch ParsePointer using async/await ([#271](https://github.com/parse-community/Parse-Swift/pull/271)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- By default, do not use cache when fetching ParseObject's and ParseFile's. Developers can choose to fetch from cache if desired by passing the necessary option while fetching. Fixed a bug when the incorrect file location for a dowloaded ParseFile was being cached ([#272](https://github.com/parse-community/Parse-Swift/pull/272)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.1.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.0.3...2.1.0)
__Improvements__
- Make ParseUser.current, ParseInstallation.current, ParseConfig.current immutable. This prevents accidently setting to nil. When developers want to make changes, they should make mutable copies, mutate, then save ([#266](https://github.com/parse-community/Parse-Swift/pull/266)), thanks to [Corey Baker](https://github.com/cbaker6).
- Added the ParseObjectMutable protocol to make emptyObject more developer friendly ([#270](https://github.com/parse-community/Parse-Swift/pull/270)), thanks to [Damian Van de Kauter](https://github.com/novemTeam).
### 2.0.3
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.0.2...2.0.3)
__Fixes__
- Async/await methods should be available for watchOS 8+ ([#265](https://github.com/parse-community/Parse-Swift/pull/265)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.0.2
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.0.1...2.0.2)
__Improvements__
- Add static methods for accessing encoders/decoder so developers do not have to create instances to access ([#259](https://github.com/parse-community/Parse-Swift/pull/259)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- Parse ViewModels always dispatch to the main queue when updating published properties. This prevents possible issues when background async calls update properties used for views ([#260](https://github.com/parse-community/Parse-Swift/pull/260)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.0.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/2.0.0...2.0.1)
__Fixes__
- ParseUser should only encode email when User.current?.email is different from current user email ([#256](https://github.com/parse-community/Parse-Swift/pull/256)), thanks to [Corey Baker](https://github.com/cbaker6).
### 2.0.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.11.0...2.0.0)
__New features__
- Added option to delete Parse items from Keychain when the app is running for the first time ([#254](https://github.com/parse-community/Parse-Swift/pull/254)), thanks to [Corey Baker](https://github.com/cbaker6).
__Improvements__
- (Breaking Change) ParseObject's now conform to Identifiable and can be used directly with SwiftUI without additonal properties needed. Drops support for iOS 12, tvOS 12, watchOS 5, and macOS 10.13/14 ([#254](https://github.com/parse-community/Parse-Swift/pull/254)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.11.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.10.4...1.11.0)
__Improvements__
- Added `operation` for `set` and `forceSet`, used for single key updates ([#248](https://github.com/parse-community/Parse-Swift/pull/248)), thanks to [Daniel Blyth](https://github.com/dblythy) and [Corey Baker](https://github.com/cbaker6).
- Add more detail to invalid struct errors ([#238](https://github.com/parse-community/Parse-Swift/pull/238)), thanks to [Daniel Blyth](https://github.com/dblythy).
### 1.10.4
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.10.3...1.10.4)
__Improvements__
- Improve documentation for ParseObject ([#253](https://github.com/parse-community/Parse-Swift/pull/253)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.10.3
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.10.2...1.10.3)
__Improvements__
- Update documents to show new Swift 5.5 async/await methods ([#252](https://github.com/parse-community/Parse-Swift/pull/252)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.10.2
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.10.1...1.10.2)
__New features__
- Supports Swift 5.5 async/await ([#212](https://github.com/parse-community/Parse-Swift/pull/212)), thanks to [Corey Baker](https://github.com/cbaker6).
__Improvements__
- Added an extension to compare a Swift Error with a single ParseError or multiple ParseErrors ([#250](https://github.com/parse-community/Parse-Swift/pull/250)), thanks to [Damian Van de Kauter](https://github.com/novemTeam).
### 1.10.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.10.0...1.10.1)
__Improvements__
- Removes emptyObject requirement that was added in #243. Instead, has a recommendation in playgrounds on how to use emptyObject to only send select modified keys to the server ([#249](https://github.com/parse-community/Parse-Swift/pull/249)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.10.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.10...1.10.0)
__Improvements__
- (Breaking Change) Provide ParseObject property, emptyObject, that makes it easy to send only modified keys to the server. This change "might" be breaking depending on your implementation as it requires ParseObjects to now have an empty initializer, init() ([#243](https://github.com/parse-community/Parse-Swift/pull/243)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- ParseUser should not send email if it has not been modified or else email verification is resent ([#241](https://github.com/parse-community/Parse-Swift/pull/241)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.9.10
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.9...1.9.10)
__Fixes__
- ParseInstallation cannot be retreived from Keychain after the first fun ([#236](https://github.com/parse-community/Parse-Swift/pull/236)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.9.9
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.8...1.9.9)
__Fixes__
- Saving ParseObjects with ParseFile properties now saves files on background queue ([#230](https://github.com/parse-community/Parse-Swift/pull/230)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.9.8
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.7...1.9.8)
__Fixes__
- Use a seperate Keychain for each app bundleId. This only effects macOS apps as their Keychain is handled by the OS differently. For macOS app developers only, the user who logged in last to your app will have their Keychain upgraded to the patched version. Other users/apps will either need to login again or logout then login again ([#224](https://github.com/parse-community/Parse-Swift/pull/224)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.9.7
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.6...1.9.7)
__Improvements__
- Properly allow a mixed custom objectId environment without compromising safety checks using .save(). If a developer wants to ignore the objectId checks, they need to specify ignoringCustomObjectIdConfig = true each time ([#222](https://github.com/parse-community/Parse-Swift/pull/222)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.9.6
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.5...1.9.6)
__Fixes__
- Query withinMiles and withinKilometers was not returning unsorted results when sort=false ([#219](https://github.com/parse-community/Parse-Swift/pull/219)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.9.5
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.4...1.9.5)
__Improvements__
- LiveQuery web socket connections handle URL error codes -1001 "The request timed out" and -1011 "There was a bad response from the server." ([#217](https://github.com/parse-community/Parse-Swift/pull/217)), thanks to [Lukas Smilek](https://github.com/lsmilek1).
### 1.9.4
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.3...1.9.4)
__Fixes__
- Fix LiveQuery reconnections when server disconnects. Always receive and pass connection errors to ParseLiveQuery delegate ([#211](https://github.com/parse-community/Parse-Swift/pull/211)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.9.3
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.2...1.9.3)
__Improvements__
- Ensure delegate set before resuming a ParseLiveQuery task ([#209](https://github.com/parse-community/Parse-Swift/pull/209)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.9.2
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.1...1.9.2)
__Improvements__
- ParseLiveQuery checks all states of a websocket and reacts as needed after an error ([#207](https://github.com/parse-community/Parse-Swift/pull/207)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.9.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.9.0...1.9.1)
__Improvements__
- Clear caching when a user logs out ([#198](https://github.com/parse-community/Parse-Swift/pull/198)), thanks to [Corey Baker](https://github.com/cbaker6).
- Close all LiveQuery connections when a user logs out ([#199](https://github.com/parse-community/Parse-Swift/pull/199)), thanks to [Corey Baker](https://github.com/cbaker6).
- ParseLiveQuery attempts to reconnect upon disconnection error ([#204](https://github.com/parse-community/Parse-Swift/pull/204)), thanks to [Corey Baker](https://github.com/cbaker6).
- Make ParseFileManager public so developers can easily find the location of ParseFiles ([#205](https://github.com/parse-community/Parse-Swift/pull/205)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- Fix Facebook and Twitter login setting incorrect keys ([#202](https://github.com/parse-community/Parse-Swift/pull/202)), thanks to [Daniel Blyth](https://github.com/dblythy).
### 1.9.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.6...1.9.0)
__New features__
- (Breaking Change) Added a new type, QueryViewModel which conforms to ObservableObject. The new type serves as a view model property for any Parse Query. Simply call query.viewModel to use the view model with any SwiftUI view. QueryViewModel can be subclassed for customization. In addition, developers can create their own view models for queries by conforming to QueryObservable. LiveQuery Subscription's inherrit from QueryViewModel meaning instances of Subscription provides a single view model that publishes updates from LiveQuery events and traditional find, first, count, and aggregate queries. A breaking change is introduced for those use custom subscriptions as ParseSubscription has been renamed to QuerySubscribable ([#183](https://github.com/parse-community/Parse-Swift/pull/183)), thanks to [Corey Baker](https://github.com/cbaker6).
- Added a new type, CloudViewModel which conforms to ObservableObject. The new type serves as a view model property for any Cloud Code. Simply call cloud.viewModel to use the view model with any SwiftUI view. CloudViewModel can be subclassed for customization. In addition, developers can create their own view models for queries by conforming to CloudObservable ([#183](https://github.com/parse-community/Parse-Swift/pull/183)), thanks to [Corey Baker](https://github.com/cbaker6).
- Added two missing Parse types, ParseBytes and ParsePolygon ([#190](https://github.com/parse-community/Parse-Swift/pull/190)), thanks to [Corey Baker](https://github.com/cbaker6).
- Added caching of http requests along with adding additional headers. Caching and additional headers can be set when initializing the SDK. Caching can also be set per request using API.Options ([#196](https://github.com/parse-community/Parse-Swift/pull/196)), thanks to [Corey Baker](https://github.com/cbaker6).
__Improvements__
- Removed CommonCrypto and now uses encoded string as a hash for child ParseObjects across all OS's ([#184](https://github.com/parse-community/Parse-Swift/pull/184)), thanks to [Corey Baker](https://github.com/cbaker6).
- All types now conform to CustomStringConvertible ([#185](https://github.com/parse-community/Parse-Swift/pull/185)), thanks to [Corey Baker](https://github.com/cbaker6).
- Setting limit = 0 of a query does not query the server and instead just returns empty or no results depending on the query ([#189](https://github.com/parse-community/Parse-Swift/pull/189)), thanks to [Corey Baker](https://github.com/cbaker6).
- ParseGeoPoint initializer now throws if geopoints are out-of-bounds instead of asserting ([#190](https://github.com/parse-community/Parse-Swift/pull/190)), thanks to [Corey Baker](https://github.com/cbaker6).
- Persist all properties of ParseUser and ParseInstallation to keychain so they can be accessed via current. Developers do not have to fetch the ParseUser or ParseInstlation after app restart anymore ([#191](https://github.com/parse-community/Parse-Swift/pull/191)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- Fixed a bug when signing up from a ParseUser instance resulted in custom keys not being persisted to the keychain ([#187](https://github.com/parse-community/Parse-Swift/pull/187)), thanks to [Corey Baker](https://github.com/cbaker6).
- Fixed a bug where countExplain query result was not returned as an array ([#189](https://github.com/parse-community/Parse-Swift/pull/189)), thanks to [Corey Baker](https://github.com/cbaker6).
- The query withinPolygon(key: String, points: [ParseGeoPoint]) now works correctly and sends an array of doubles instead of an array of GeoPoint's ([#190](https://github.com/parse-community/Parse-Swift/pull/190)), thanks to [Corey Baker](https://github.com/cbaker6).
- Fixed a bug where the ParseEncoder incorrectly detects a circular dependency when two child objects are the same ([#194](https://github.com/parse-community/Parse-Swift/pull/194)), thanks to [Corey Baker](https://github.com/cbaker6).
- Make sure all LiveQuery socket changes are received on the correct queue to prevent threading issues ([#195](https://github.com/parse-community/Parse-Swift/pull/195)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.8.6
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.5...1.8.6)
__Improvements__
- Added SwiftUI query combine example to playgrounds. Skip id when encoding ParseObjects ([#181](https://github.com/parse-community/Parse-Swift/pull/181)), thanks to [Corey Baker](https://github.com/cbaker6).
- Persist current SDK version for migrating between versions ([#182](https://github.com/parse-community/Parse-Swift/pull/182)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.8.5
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.4...1.8.5)
__Fixes__
- Fixed a bug in LiveQuery when a close frame is sent from the server that resulted in closing
all running websocket tasks instead of the particular task the request was intended for. The fix
includes a new delegate method named `closedSocket()` which provides the close code
and reason the server closed the connection ([#176](https://github.com/parse-community/Parse-Swift/pull/176)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.8.4
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.3...1.8.4)
__Fixes__
- Switched context header X-Parse-Context to X-Parse-Cloud-Context to match server ([#170](https://github.com/parse-community/Parse-Swift/pull/170)), thanks to [Corey Baker](https://github.com/cbaker6).
- Fixed a bug in LiveQuery that prevented reconnecting after a connection was closed. Also added a sendPing method to LiveQuery ([#172](https://github.com/parse-community/Parse-Swift/pull/172)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.8.3
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.2...1.8.3)
__Fixes__
- Fixed a bug that prevented saving ParseObjects that had Pointers as properties ([#169](https://github.com/parse-community/Parse-Swift/pull/169)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.8.2
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.1...1.8.2)
__Improvements__
- Ensure pipeline and fields are checked when comparing queries ([#163](https://github.com/parse-community/Parse-Swift/pull/163)), thanks to [Corey Baker](https://github.com/cbaker6).
- Allow custom error codes to be thrown from Cloud Functions ([#165](https://github.com/parse-community/Parse-Swift/pull/165)), thanks to [Daniel Blyth](https://github.com/dblythy).
### 1.8.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.8.0...1.8.1)
__Improvements__
- Append instead of replace when using query select, exclude, include, and fields ([#155](https://github.com/parse-community/Parse-Swift/pull/155)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- Transactions currently do not work when using MongoDB(postgres does work) on the parse-server. Internal use of transactions are disabled by default. If you want the Swift SDK to use transactions internally, you need to set isUsingTransactionsInternally=true when configuring the client. It is recommended not to use transactions if you are using MongoDB until it is fixed on the server ([#158](https://github.com/parse-community/Parse-Swift/pull/158)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.8.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.7.2...1.8.0)
__New features__
- Add ParseAnalytics. Requires app tracking authorization in latest OS's ([#147](https://github.com/parse-community/Parse-Swift/pull/147)), thanks to [Corey Baker](https://github.com/cbaker6).
__Improvements__
- Adds the ability to directly use == as a QueryConstraint on a field that's a ParseObject ([#147](https://github.com/parse-community/Parse-Swift/pull/147)), thanks to [Corey Baker](https://github.com/cbaker6).
- Future proof SDK by always sending client version header. Also added http method PATCH to API for future use ([#146](https://github.com/parse-community/Parse-Swift/pull/146)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- Fixed an error that occured when deleting a ParseFile which resulted in the file being downloaded locally ([#147](https://github.com/parse-community/Parse-Swift/pull/147)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.7.2
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.7.1...1.7.2)
__New features__
- Added ability to send context with object by specifying it within options ([#140](https://github.com/parse-community/Parse-Swift/pull/140)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- ParseFiles cannot be updated from the client and will now throw an error if attempted. Instead another file should be created and the older file should be deleted by the developer. ([#144](https://github.com/parse-community/Parse-Swift/pull/144)), thanks to [Corey Baker](https://github.com/cbaker6).
- Fixed issue where Swift SDK prevented fetching of Parse objects when custom objectId was enabled ([#139](https://github.com/parse-community/Parse-Swift/pull/139)), thanks to [Corey Baker](https://github.com/cbaker6).
__Improvements__
- Add playground example of saving Parse objects with a custom objectId ([#137](https://github.com/parse-community/Parse-Swift/pull/137)), thanks to [Corey Baker](https://github.com/cbaker6).
- Improved comparison of query constraints by comparing value ([#140](https://github.com/parse-community/Parse-Swift/pull/140)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.7.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.7.0...1.7.1)
__New features__
- Can now check the health of a Parse Server using ParseHealth. ([#134](https://github.com/parse-community/Parse-Swift/pull/134)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.7.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.6.0...1.7.0)
__Improvements__
- Add emailVerified to ParseUser. Make relative query take a QueryConstraint as an argument. Add more documentation ([#129](https://github.com/parse-community/Parse-Swift/pull/129)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.6.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.5.1...1.6.0)
__Improvements__
- Make AnyCodable internal. If developers want to use AnyCodable, AnyEncodable, or AnyDecodable for `explain` or `ParseCloud`, they should add the [AnyCodable](https://github.com/Flight-School/AnyCodable) package to their app. In addition developers can create their own type-erased wrappers or use whatever they desire ([#127](https://github.com/parse-community/Parse-Swift/pull/127)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.5.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.5.0...1.5.1)
__Improvements__
- Update ParseError to match server and make ParseError and ParseObject Pointer documentation public ([#125](https://github.com/parse-community/Parse-Swift/pull/125)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.5.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.4.0...1.5.0)
__Improvements__
- (Breaking Change) Aggregrate takes any Encodable type. Query planning methods are now: findExlpain, firstEplain, countExplain, etc. The distinct query now works. The client will also not throw an error anymore when attempting to delete a File and the masterKey is not available. The developer will still need to configure the server to delete the file properly ([#122](https://github.com/parse-community/Parse-Swift/pull/122)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.4.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.3.1...1.4.0)
__Improvements__
- (Breaking Change) A query hint can now be set using a method and its return type is automatically inferred. In addition, a hint can now be any Encodable type instead of just a String ([#119](https://github.com/parse-community/Parse-Swift/pull/119)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.3.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.3.0...1.3.1)
__New features__
- Add findAll query to find all objects ([#118](https://github.com/parse-community/Parse-Swift/pull/118)), thanks to [Corey Baker](https://github.com/cbaker6).
- Can now delete the iOS Objective-C SDK Keychain from app ([#118](https://github.com/parse-community/Parse-Swift/pull/118)), thanks to [Corey Baker](https://github.com/cbaker6).
- Migrate installationId from obj-c SDK ([#117](https://github.com/parse-community/Parse-Swift/pull/117)), thanks to [Corey Baker](https://github.com/cbaker6).
__Improvements__
- Added ability to initialize SDK with ParseConfiguration. Can now update certificate pinning authorization after SDK is initializated ([#117](https://github.com/parse-community/Parse-Swift/pull/117)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.3.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.6...1.3.0)
__Improvements__
- (Breaking Change) No longer require dispatch to main queue when using ParseInstallation. The side effect of this is badge is no longer retrieved by the SDK. The developer should retrieve the badge count on their own and save it to `ParseInstallation` if they require badge ([#114](https://github.com/parse-community/Parse-Swift/pull/114)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- (Breaking Change) Correctly saves objectId of ParseInstallation to Keychain when saving to server. Also fixes issue when using deleteAll with current ParseUser and ParseInstallation. Old installations will automatically be migrated to the new one. If you end up having issues you can delete all of the installations in your ParseDashboard that were created with Parse-Swift < 1.30. If you are not able to do this, you can all log out of devices using Parse-Swift < 1.30 and then log back in ([#116](https://github.com/parse-community/Parse-Swift/pull/116)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.2.6
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.5...1.2.6)
__Fixes__
- Recreate installation automatically after deletion from Keychain ([#112](https://github.com/parse-community/Parse-Swift/pull/112)), thanks to [Corey Baker](https://github.com/cbaker6).
- Error when linking auth types due to server not sending sessionToken ([#109](https://github.com/parse-community/Parse-Swift/pull/109)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.2.5
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.4...1.2.5)
__Fixes__
- Let ParseFacebook accept expiresIn parameter instead of converting to date ([#104](https://github.com/parse-community/Parse-Swift/pull/104)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.2.4
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.3...1.2.4)
__Fixes__
- Ensure all dates are encoded/decoded to the proper UTC time ([#103](https://github.com/parse-community/Parse-Swift/pull/103)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.2.3
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.2...1.2.3)
__Fixes__
- Fixed a bug that prevented custom objectIds from working ([#101](https://github.com/parse-community/Parse-Swift/pull/101)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.2.2
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.1...1.2.2)
__New features__
- Allow custom objectIds ([#100](https://github.com/parse-community/Parse-Swift/pull/100)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add ParseTwitter and ParseFacebook authentication ([#97](https://github.com/parse-community/Parse-Swift/pull/97)), thanks to [Abdulaziz Alhomaidhi](https://github.com/abs8090).
- Add build support for Android ([#90](https://github.com/parse-community/Parse-Swift/pull/90)), thanks to [jt9897253](https://github.com/jt9897253).
__Fixes__
- There was another bug after a user first logs in anonymously and then becomes a real user. The authData sent to the server was not stripped, keep the user anonymous instead of making them a real user ([#100](https://github.com/parse-community/Parse-Swift/pull/100)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.2.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.2.0...1.2.1)
__Improvements__
- Child objects are now automatically saved in batches using transactions. This will result in less network overhead and prevent uneccessary clean up of data on the server if a child objects throws an error while saving ([#94](https://github.com/parse-community/Parse-Swift/pull/94)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- There was a bug after a user first logs in anonymously and then becomes a real user as the server sends a new sessionToken when this occurs, but the SDK used the old sessionToken, resulting in an invalid sessionToken error ([#94](https://github.com/parse-community/Parse-Swift/pull/94)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.2.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.6...1.2.0)
__New features__
- Add transaction support to batch saveAll and deleteAll ([#89](https://github.com/parse-community/Parse-Swift/pull/89)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add modifiers to containsString, hasPrefix, hasSuffix ([#85](https://github.com/parse-community/Parse-Swift/pull/85)), thanks to [Corey Baker](https://github.com/cbaker6).
__Improvements__
- (Breaking Change) Allows return types to be specified for `ParseCloud`, query `hint`, and `explain` (see playgrounds for examples). Changed functionality of synchronous `query.first()`. It use to return nil if no values are found. Now it will throw an error if none are found. ([#92](https://github.com/parse-community/Parse-Swift/pull/92)), thanks to [Corey Baker](https://github.com/cbaker6).
- Better error reporting when decode errors occur ([#92](https://github.com/parse-community/Parse-Swift/pull/92)), thanks to [Corey Baker](https://github.com/cbaker6).
- Can use a variadic version of exclude. Added examples of select and exclude query in playgrounds ([#88](https://github.com/parse-community/Parse-Swift/pull/88)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.1.6
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.5...1.1.6)
__Fixes__
- Send correct SDK version number to Parse Server ([#84](https://github.com/parse-community/Parse-Swift/pull/84)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.1.5
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.4...1.1.5)
__Improvements__
- Make it easier to use `ParseApple` ([#81](https://github.com/parse-community/Parse-Swift/pull/81)), thanks to [Corey Baker](https://github.com/cbaker6).
- `ParseACL` improvements. Only call `ParseUser.current` when necessary ([#80](https://github.com/parse-community/Parse-Swift/pull/80)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.1.4
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.3...1.1.4)
__New features__
- LDAP authentication support ([#79](https://github.com/parse-community/Parse-Swift/pull/79)), thanks to [Corey Baker](https://github.com/cbaker6).
- Support for push notifications through `ParseInstallation` ([#78](https://github.com/parse-community/Parse-Swift/pull/78)), thanks to [Corey Baker](https://github.com/cbaker6).
- Fetch with include ([#74](https://github.com/parse-community/Parse-Swift/pull/74)), thanks to [Corey Baker](https://github.com/cbaker6).
__Improvements__
- Added `ParseLiveQuery` SwiftUI example to Playgrounds ([#77](https://github.com/parse-community/Parse-Swift/pull/77)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.1.3
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.2...1.1.3)
__New features__
- SwiftUI ready! ([#73](https://github.com/parse-community/Parse-Swift/pull/73)), thanks to [Corey Baker](https://github.com/cbaker6).
__Fixes__
- Fixes some issues with `ParseUser.logout` ([#73](https://github.com/parse-community/Parse-Swift/pull/73)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.1.2
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.1...1.1.2)
__Fixes__
Installing via SPM crashes ([#69](https://github.com/parse-community/Parse-Swift/pull/69)), thanks to [pmmlo](https://github.com/pmmlo).
### 1.1.1
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.1.0...1.1.1)
__Fixes__
- Expose `ParseLiveQuery` subscription properties ([#66](https://github.com/parse-community/Parse-Swift/pull/66)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.1.0
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.0.2...1.1.0)
__New features__
- Enable `ParseFile` for Linux ([#64](https://github.com/parse-community/Parse-Swift/pull/64)), thanks to [jt9897253](https://github.com/jt9897253).
- Use a `ParseLiveQuery` subscription as a SwiftUI view model ([#65](https://github.com/parse-community/Parse-Swift/pull/65)), thanks to [Corey Baker](https://github.com/cbaker6).
- Idempotency support ([#62](https://github.com/parse-community/Parse-Swift/pull/62)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.0.2
[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/1.0.0...1.0.2)
__New features__
- Linux support. See the PR for limitations ([#59](https://github.com/parse-community/Parse-Swift/pull/59)), thanks to [Corey Baker](https://github.com/cbaker6).
### 1.0.0
__New features__
- Config support ([#56](https://github.com/parse-community/Parse-Swift/pull/56)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).
- Role and Relation support. Also improved Parse operations and added examples in Playgrounds ([#54](https://github.com/parse-community/Parse-Swift/pull/54)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).
- Added more `Query` support for distinct, aggregate, nor, containedBy, and relative time ([#54](https://github.com/parse-community/Parse-Swift/pull/54)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).
- Annonymous and Apple login along with `ParseAuthentication` protocol for support of any adapter ([#53](https://github.com/parse-community/Parse-Swift/pull/53)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).
- Developer side network authentication for certificate pinning. Parse-Swift can share authentication with `ParseLiveQuery` or they can use seperate ([#45](https://github.com/parse-community/Parse-Swift/pull/45)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).
- Full LiveQuery support (min requirement: macOS 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0) ([#45](https://github.com/parse-community/Parse-Swift/pull/45)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).
- Support of Cloud and Job functions along with password reset and verification email request ([#43](https://github.com/parse-community/Parse-Swift/pull/43)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).
- Add `ParseFile` support ([#40](https://github.com/parse-community/Parse-Swift/pull/40)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add `deleteAll` to Parse objects ([#34](https://github.com/parse-community/Parse-Swift/pull/34)), thanks to [Corey Baker](https://github.com/cbaker6).
- Save child pointers and deep saving of objects ([#21](https://github.com/parse-community/Parse-Swift/pull/21)), thanks to [Corey Baker](https://github.com/cbaker6).
- Persist `ParseUser`, `ParseInstallation`, and default `ParseACL` to Keychain ([#19](https://github.com/parse-community/Parse-Swift/pull/19)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add PrimitiveObectStore protocol that extends Keychain Store ([#13](https://github.com/parse-community/Parse-Swift/pull/13)), thanks to [Pranjal Satija](https://github.com/pranjalsatija).
- Add `AnyCodable` support ([#12](https://github.com/parse-community/Parse-Swift/pull/12)), thanks to [Corey Baker](https://github.com/cbaker6) and [Shawn Baek](https://github.com/ShawnBaek).
- Add Keychain storage ([#7](https://github.com/parse-community/Parse-Swift/pull/7)), thanks to [Florent Vilmart](https://github.com/flovilmart).
- Add `ParseError`, SwiftLint, saveAll, SPM, synchronous support ([#6](https://github.com/parse-community/Parse-Swift/pull/6)), thanks to [Florent Vilmart](https://github.com/flovilmart).
- Create Parse-Swift project, project Playground, and add Travis CI ([#1](https://github.com/parse-community/Parse-Swift/pull/1)), thanks to [Florent Vilmart](https://github.com/flovilmart).
__Improvements__
- Naming conventions and structure ([#54](https://github.com/parse-community/Parse-Swift/pull/54)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).
- Improve network progress updates and threading ([#51](https://github.com/parse-community/Parse-Swift/pull/51)), thanks to [Corey Baker](https://github.com/cbaker6).
- User login now uses `POST` instead of `GET` ([#45](https://github.com/parse-community/Parse-Swift/pull/45)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).
- Dedicated Parse URLSession for more control and delegation ([#45](https://github.com/parse-community/Parse-Swift/pull/45)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).
- Objects are batched in groups of 50 ([#43](https://github.com/parse-community/Parse-Swift/pull/43)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).
- Add default queues to async calls ([#38](https://github.com/parse-community/Parse-Swift/pull/38)), thanks to [Corey Baker](https://github.com/cbaker6).
- Persist queried and fetch objects to Keychain if they match a `current` object already stored ([#34](https://github.com/parse-community/Parse-Swift/pull/34)), thanks to [Corey Baker](https://github.com/cbaker6).
- Improve ParseEncoder to support arrays ([#33](https://github.com/parse-community/Parse-Swift/pull/33)), thanks to [Corey Baker](https://github.com/cbaker6).
- Add a new ParseEncoder from Swift 5.3 open-source JSON encoder ([#21](https://github.com/parse-community/Parse-Swift/pull/21)), thanks to [Corey Baker](https://github.com/cbaker6).
- Full support of `ParseGeopoint` and improve querying ([#21](https://github.com/parse-community/Parse-Swift/pull/21)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).
- Improved async networking calls ([#15](https://github.com/parse-community/Parse-Swift/pull/15)), thanks to [Corey Baker](https://github.com/cbaker6).
- Rename and restructure project ([#13](https://github.com/parse-community/Parse-Swift/pull/13)), thanks to [Pranjal Satija](https://github.com/pranjalsatija).
- Update to Swift 5.0 ([#12](https://github.com/parse-community/Parse-Swift/pull/12)), thanks to [Corey Baker](https://github.com/cbaker6).
- Remove RESTCommand and add API.Command ([#6](https://github.com/parse-community/Parse-Swift/pull/6)), thanks to [Florent Vilmart](https://github.com/flovilmart).
__Fixes__
- Delete current installation during logout ([#52](https://github.com/parse-community/Parse-Swift/pull/52)), thanks to [Corey Baker](https://github.com/cbaker6).
- Parse server supports `$eq`, but this is not supported by LiveQueryServer, switched to supported ([#49](https://github.com/parse-community/Parse-Swift/pull/49)), thanks to [Corey Baker](https://github.com/cbaker6).
- Bug when updating a ParseObject bug where objects was accidently converted to pointers ([#48](https://github.com/parse-community/Parse-Swift/pull/48)), thanks to [Corey Baker](https://github.com/cbaker6).
- User logout was calling the wrong endpoint ([#43](https://github.com/parse-community/Parse-Swift/pull/43)), thanks to [Corey Baker](https://github.com/cbaker6) and [Tom Fox](https://github.com/TomWFox).
- Fix an issue where ACL was overwritten with nil ([#40](https://github.com/parse-community/Parse-Swift/pull/40)), thanks to [Corey Baker](https://github.com/cbaker6).
- Update Keychain during fetch. Fix synchronous bug that occured with `ParseError` was thrown ([#38](https://github.com/parse-community/Parse-Swift/pull/38)), thanks to [Corey Baker](https://github.com/cbaker6).
- Fix ParseEncoder bugs ([#27](https://github.com/parse-community/Parse-Swift/pull/27)), thanks to [Corey Baker](https://github.com/cbaker6).
- Fix async callback queue bug ([#27](https://github.com/parse-community/Parse-Swift/pull/27)), thanks to [Corey Baker](https://github.com/cbaker6).
- Fix bugs in ParseACL and bump minimum OS support to `.iOS(.v11), .macOS(.v10_13), .tvOS(.v11), .watchOS(.v4)` ([#19](https://github.com/parse-community/Parse-Swift/pull/19)), thanks to [Corey Baker](https://github.com/cbaker6).
- Fix bugs in batch and save responses ([#15](https://github.com/parse-community/Parse-Swift/pull/15)), thanks to [Corey Baker](https://github.com/cbaker6).
- Fix Keychain tests ([#12](https://github.com/parse-community/Parse-Swift/pull/12)), thanks to [Corey Baker](https://github.com/cbaker6).
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to the ParseSwift SDK <!-- omit in toc -->
## Table of Contents <!-- omit in toc -->
- [Contributing](#contributing)
- [Why Contributing?](#why-contributing)
- [Environment Setup](#environment-setup)
- [Setting up your local machine](#setting-up-your-local-machine)
- [Swift Playgrounds](#swift-playgrounds)
- [Please Do's](#please-dos)
- [Pull Request](#pull-request)
- [Evolution](#evolution)
- [Code of Conduct](#code-of-conduct)
We really want the ParseSwift SDK to be yours, to see it grow and thrive in the open source community.
If you are not familiar with Pull Requests and want to know more about them, you can visit the [Creating a pull request](https://help.github.com/articles/creating-a-pull-request/) article. It contains detailed information about the process.
## Contributing
Before you start to code, please open a [new issue](https://github.com/parse-community/Parse-Swift/issues/new/choose) to describe your idea, or search for and continue the discussion in an [existing issue](https://github.com/parse-community/Parse-Swift/issues).
> ⚠️ Please do not post a security vulnerability on GitHub or in the Parse Community Forum. Instead, follow the [Parse Community Security Policy](https://github.com/parse-community/parse-server/security/policy).
Please completely fill out any templates to provide essential information about your new feature or the bug you discovered.
Together we will plan out the best conceptual approach for your contribution, so that your and our time is invested in the best possible approach. The discussion often reveals how to leverage existing features of ParseSwift SDK to reach your goal with even less effort and in a more sustainable way.
When you are ready to code, you can find more information about opening a pull request in the [GitHub docs](https://help.github.com/articles/creating-a-pull-request/).
Whether this is your first contribution or you are already an experienced contributor, the Parse Community has your back – do not hesitate to ask for help!
## Why Contributing?
Buy cheap, buy twice. What? No, this is not the Economics 101 class, but the same is true for contributing.
There are two ways of writing a feature or fixing a bug. Sometimes the quick solution is to just write a Cloud Code function that does what you want. Contributing by making the change directly in ParseSwift may take a bit longer, but it actually saves you much more time in the long run.
Consider the benefits you get:
- #### 🚀 Higher efficiency
Your code is examined for efficiency and interoperability with existing features by the community.
- #### 🛡 Stronger security
Your code is scrutinized for bugs and vulnerabilities and automated checks help to identify security issues that may arise in the future.
- #### 🧬 Continuous improvement
If your feature is used by others it is likely to be continuously improved and extended by the community.
- #### 💝 Giving back
You give back to the community that contributed to make the Parse Platform become what it is today and for future developers to come.
- #### 🧑🎓 Improving yourself
You learn to better understand the inner workings of ParseSwift, which will help you to write more efficient and resilient code for your own application.
Most importantly, with every contribution you improve your skills so that future contributions take even less time and you get all the benefits above for free — easy choice, right?
## Environment Setup
### Setting up your local machine
* [Fork](https://github.com/parse-community/Parse-Swift) this project and clone the fork on to your local machine:
```sh
$ git clone https://github.com/parse-community/Parse-Swift
$ cd Parse-Swift # go into the clone directory
```
* Please install [SwiftLint](https://github.com/realm/SwiftLint) to ensure that your PR conforms to our coding standards:
```sh
$ brew install swiftlint
```
### Swift Playgrounds
Any feature additions should work with a real Parse Server. You can experiment with features in the ParseSwift SDK by modifying the [ParseSwift Playground files](https://github.com/parse-community/Parse-Swift/tree/main/ParseSwift.playground/Pages). It is recommended to make sure your ParseSwift workspace in Xcode is set to build for `ParseSwift (macOS)` framework when using Swift Playgrounds. To configure the playgounds, you can do one of the following:
* Use the pre-configured parse-server in [this repo](https://github.com/netreconlab/parse-hipaa/tree/parse-swift) which comes with docker compose files (`docker-compose up` gives you a working server) configured to connect with the ParseSwift Playgrounds. The docker comes with [Parse Dashboard](https://github.com/parse-community/parse-dashboard) and can be used with MongoDB or PostgreSQL.
* Configure the ParseSwift Playgrounds to work with your own Parse Server by editing the configuation in [Common.swift](https://github.com/parse-community/Parse-Swift/blob/e9ba846c399257100b285d25d2bd055628b13b4b/ParseSwift.playground/Sources/Common.swift#L4-L19).
### Please Do's
* Take testing seriously! Aim to increase the test coverage with every pull request
* Add/modify test files for the code you are working on in [ParseSwiftTests](https://github.com/parse-community/Parse-Swift/tree/main/Tests/ParseSwiftTests)
* Run the tests for the file you are working on using Xcode
* Run the tests for the whole project to make sure the code passes all tests. This can be done by running the tests in Xcode
* Address all errors and warnings your fixes introduce as the ParseSwift SDK should have zero warnings
* Test your additions in Swift Playgrounds and add to the Playgrounds if applicable
* Please consider if any changes to the [docs](http://docs.parseplatform.org) are needed or add additional sections in the case of an enhancement or feature.
## Pull Request
For release automation, the title of pull requests needs to be written in a defined syntax. We loosely follow the [Conventional Commits](https://www.conventionalcommits.org) specification, which defines this syntax:
```
<type>: <summary>
```
The _type_ is the category of change that is made, possible types are:
- `feat` - add a new feature
- `fix` - fix a bug
- `refactor` - refactor code without impact on features or performance
- `docs` - add or edit code comments, documentation, GitHub pages
- `style` - edit code style
- `build` - retry failing build and anything build process related
- `perf` - performance optimization
- `ci` - continuous integration
- `test` - tests
The _summary_ is a short change description in present tense, not capitalized, without period at the end. This summary will also be used as the changelog entry.
- It must be short and self-explanatory for a reader who does not see the details of the full pull request description
- It must not contain abbreviations, e.g. instead of `LQ` write `LiveQuery`
- It must use the correct product and feature names as referenced in the documentation, e.g. instead of `Cloud Validator` use `Cloud Function validation`
- In case of a breaking change, the summary must not contain duplicate information that is also in the [BREAKING CHANGE](#breaking-change) chapter of the pull request description. It must not contain a note that it is a breaking change, as this will be automatically flagged as such if the pull request description contains the BREAKING CHANGE chapter.
For example:
```
feat: add handle to door for easy opening
```
Currently, we are not making use of the commit _scope_, which would be written as `<type>(<scope>): <summary>`, that attributes a change to a specific part of the product.
## Evolution
The ParseSwift SDK is not a port of the [Parse-SDK-iOS-OSX SDK](https://github.com/parse-community/Parse-SDK-iOS-OSX) and though some of it may feel familiar, it is not backwards compatible and is designed using [protocol oriented programming (POP) and value types](https://www.pluralsight.com/guides/protocol-oriented-programming-in-swift) instead of OOP and reference types. You can learn more about POP by watching [this](https://developer.apple.com/videos/play/wwdc2015/408/) or [that](https://developer.apple.com/videos/play/wwdc2016/419/) videos from previous WWDC's. Please see [this thread](https://github.com/parse-community/Parse-Swift/issues/3) for a detailed discussion about the intended evolution of this SDK.
## Code of Conduct
This project adheres to the [Contributor Covenant Code of Conduct](https://github.com/parse-community/.github/blob/main/CODE_OF_CONDUCT.md). By participating, you are expected to honor this code.
================================================
FILE: LICENSE
================================================
MIT License
Copyright (c) 2021 Parse Community
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
================================================
FILE: MIGRATION.md
================================================
# Migration from Parse ObjC SDK <!-- omit in toc -->
This document describes how to migrate from the [Parse ObjC SDK](https://github.com/parse-community/Parse-SDK-iOS-OSX) to the Parse Swift SDK.
ℹ️ *This document is a work-in-progress. If you find information missing, please submit a pull request to help us updating this document for the benefit of others.*
- [Behavioral Differences](#behavioral-differences)
- [Known Issues](#known-issues)
- [Installation](#installation)
- [Feature Comparison](#feature-comparison)
# Behavioral Differences
- ⚠️ Partially updating an object sends the complete object (including unchanged properties) to the server if you follow the familiar syntax from the Parse ObjC SDK or any other Parse SDK. This can have a significant impact on data transfer costs depending on your use case and architecture. All other Parse SDKs, including the Parse ObjC SDK, only send the changed properties to the server. The Parse Swift SDK requires a different syntax with additional overhead to achieve the same behavior. See [#401](https://github.com/parse-community/Parse-Swift/issues/401), [#242](https://github.com/parse-community/Parse-Swift/issues/242).
<details>
<summary>Code Examples</summary>
```swift
// The following examples compare how to update a saved object in the Parse ObjC SDK vs. the
// Parse Swift SDK. For simplicity, the examples show how to migrate synchonrous methods. If
// you are migrating asynchronous methods your code looks slightly differently, but the same
// approach applies.
// Parse ObjC SDK
PFObject *obj = [PFObject objectWithClassName:@"Example"];
obj[@"key"] = @"value1";
[obj save];
obj[@"key"] = @"value2";
[obj save];
// Parse Swift SDK - Variant 1
// This sends the complete object to the server when partially updating the object. This approach
// is not recommended as sending unchanged properties is unnecessary and therefore wastes resources.
struct Example: ParseObject {
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
var key: String?
}
let obj = Example()
obj.key = "value1"
obj.save()
obj.key = "value2"
obj.save()
// Parse Swift SDK - Variant 2
// This sends only the changed properties to the server. Note that `objMergable` only contains the
// modified properties and is missing the unchanged properties. To also contain the unchanged
// properties in addition to the changed properties, an additional `fetch` call on the respective
// object would be necessary. This aproach is not recommended as it adds an additional server
// request to get data that is already present locally. This is unrelated to the limitation that
// any Parse SDK is unaware of any object modification that is done via Cloud Code triggers.
struct Example: ParseObject {
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
var key: String?
}
let obj = Example()
obj.key = "value1"
obj.save()
var objMergable = obj.mergeable
objMergable.key = "value2"
objMergable.save()
// Parse Swift SDK - Variant 3
// This sends only the changed properties to the server. By overriding the `merge` method the
// `objMergable` also contains the unchanged properties of the original `obj`. This means no
// additional `fetch` call is needed. This is the recommned approach which corresponds the most
// with the behavior of the Parse ObjC SDK. Note that any change of custom properies will need
// to reflect in the `merge` method, otherwise `objMergable` may only partially contain the
// original data which leads to data inconsistencies that may be difficult to track down.
struct Example: ParseObject {
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
var key: String?
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.key, original: object) {
updated.key = object.key
}
return updated
}
}
let obj = Example()
obj.key = "value1"
obj.save()
var objMergable = obj.mergeable
objMergable.key = "value2"
objMergable.save()
```
</details>
# Known Issues
The following issues are important to consider before migrating.
## Installation
After migrating an app to the Parse Swift SDK, launching the app will create a new `_Installation` object with a new `installationId`. It will appear as if the app had been uninstalled and then reinstalled, even though it was only updated with the new Parse Swift SDK.
This may be problematic if the installation object is directly referenced in your app or if it contains fields that should be maintained, like the `badge` number field for example. To address this, here are two options:
- a) Use the Parse Swift SDK *together with* the Parse ObjC SDK in your project. This way you can migrate the installation by referencing the installation's `objectId`:
```swift
import Parse // Parse ObjC SDK
import ParseSwift // Parse Swift SDK
let objcInstallation = PFInstallation.current()!
let swiftInstallation = try await Installation.become(objcInstallation.objectId!)
```
- b) Release an update for your app which stores the installation's `objectId` somewhere. Once the app has seen a sufficient adoption, you could release an app update with only the Parse Swift SDK and use the stored `objectId` to migrate to the installation.
Both options may require a long-term migration if your existing app has many installations and until the adoption rate with either approach is high enough.
# Feature Comparison
This table only lists features that are known to be available in the Parse ObjC SDK but still missing in the Swift SDK. *This table is a work-in-progress.*
| Feature | Parse ObjC SDK | Parse Swift SDK |
|-----------------------------|--------------------------------------|-------------------------------------------------------------|
| [Saving objects offline][1] | `saveEventually`, `deleteEventually` | unsupported; requires implementing a custom offline storage |
[1]: https://docs.parseplatform.org/ios/guide/#saving-objects-offline
================================================
FILE: Package.swift
================================================
// swift-tools-version:5.5
import PackageDescription
let package = Package(
name: "ParseSwift",
platforms: [.iOS(.v13),
.macCatalyst(.v13),
.macOS(.v10_15),
.tvOS(.v13),
.watchOS(.v6)],
products: [
.library(
name: "ParseSwift",
targets: ["ParseSwift"])
],
targets: [
.target(
name: "ParseSwift",
dependencies: []),
.testTarget(
name: "ParseSwiftTests",
dependencies: ["ParseSwift"],
exclude: ["Info.plist"])
]
)
================================================
FILE: Package@5.1.swift
================================================
// swift-tools-version:5.1
import PackageDescription
let package = Package(
name: "ParseSwift",
platforms: [.iOS(.v13),
.macCatalyst(.v13),
.macOS(.v10_15),
.tvOS(.v13),
.watchOS(.v6)],
products: [
.library(
name: "ParseSwift",
targets: ["ParseSwift"])
],
targets: [
.target(
name: "ParseSwift",
dependencies: []),
.testTarget(
name: "ParseSwiftTests",
dependencies: ["ParseSwift"],
exclude: ["Info.plist"])
]
)
================================================
FILE: Parse.xcworkspace/contents.xcworkspacedata
================================================
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "container:ParseSwift.xcodeproj">
</FileRef>
</Workspace>
================================================
FILE: Parse.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
================================================
FILE: ParseSwift-iOS/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>ParseSwift</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
================================================
FILE: ParseSwift-macOS/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>NSHumanReadableCopyright</key>
<string>Copyright © 2020 Parse Community. All rights reserved.</string>
<key>NSPrincipalClass</key>
<string></string>
</dict>
</plist>
================================================
FILE: ParseSwift-tvOS/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
</dict>
</plist>
================================================
FILE: ParseSwift-tvOS/ParseSwift_tvOS.h
================================================
//
// ParseSwift_tvOS.h
// ParseSwift-tvOS
//
// Created by Corey Baker on 7/30/20.
// Copyright © 2020 Parse Community. All rights reserved.
//
#import <Foundation/Foundation.h>
//! Project version number for ParseSwift_tvOS.
FOUNDATION_EXPORT double ParseSwift_tvOSVersionNumber;
//! Project version string for ParseSwift_tvOS.
FOUNDATION_EXPORT const unsigned char ParseSwift_tvOSVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <ParseSwift_tvOS/PublicHeader.h>
================================================
FILE: ParseSwift-watchOS/Info.plist
================================================
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
</dict>
</plist>
================================================
FILE: ParseSwift-watchOS/ParseSwift_watchOS.h
================================================
//
// ParseSwift_watchOS.h
// ParseSwift-watchOS
//
// Created by Corey Baker on 7/30/20.
// Copyright © 2020 Parse Community. All rights reserved.
//
#import <Foundation/Foundation.h>
//! Project version number for ParseSwift_watchOS.
FOUNDATION_EXPORT double ParseSwift_watchOSVersionNumber;
//! Project version string for ParseSwift_watchOS.
FOUNDATION_EXPORT const unsigned char ParseSwift_watchOSVersionString[];
// In this header, you should import all the public headers of your framework using statements like #import <ParseSwift_watchOS/PublicHeader.h>
================================================
FILE: ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift
================================================
//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting
//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`
//: in the `File Inspector` is `Platform = macOS`. This is because
//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should
//: be set to build for `macOS` unless specified.
import PlaygroundSupport
import Foundation
import ParseSwift
PlaygroundPage.current.needsIndefiniteExecution = true
/*: start parse-server with
npm start -- --appId applicationId --clientKey clientKey --masterKey masterKey --mountPath /1
*/
//: In Xcode, make sure you are building the "ParseSwift (macOS)" framework.
initializeParse()
//: Get current SDK version
if let version = ParseVersion.current {
print("Current Swift SDK version is \"\(version)\"")
}
//: Check the health of your Parse Server.
do {
print("Server health is: \(try ParseHealth.check())")
} catch {
print(error)
}
//: Create your own value typed `ParseObject`.
struct GameScore: ParseObject {
//: These are required by ParseObject
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: Your own properties.
var points: Int?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
return updated
}
}
//: It's recommended to place custom initializers in an extension
//: to preserve the memberwise initializer.
extension GameScore {
init(points: Int) {
self.points = points
}
init(objectId: String?) {
self.objectId = objectId
}
}
struct GameData: ParseObject {
//: These are required by ParseObject
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: Your own properties.
var polygon: ParsePolygon?
//: `ParseBytes` needs to be a part of the original schema
//: or else you will need your masterKey to force an upgrade.
var bytes: ParseBytes?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if shouldRestoreKey(\.polygon,
original: object) {
updated.polygon = object.polygon
}
if shouldRestoreKey(\.bytes,
original: object) {
updated.bytes = object.bytes
}
return updated
}
}
//: It's recommended to place custom initializers in an extension
//: to preserve the memberwise initializer.
extension GameData {
init (bytes: ParseBytes?, polygon: ParsePolygon) {
self.bytes = bytes
self.polygon = polygon
}
}
//: Define initial GameScores.
let score = GameScore(points: 10)
let score2 = GameScore(points: 3)
/*: Save asynchronously (preferred way) - Performs work on background
queue and returns to specified callbackQueue.
If no callbackQueue is specified it returns to main queue.
*/
score.save { result in
switch result {
case .success(let savedScore):
assert(savedScore.objectId != nil)
assert(savedScore.createdAt != nil)
assert(savedScore.updatedAt != nil)
assert(savedScore.points == 10)
/*:
To modify, you need to make it a var as the value type
was initialized as immutable. Using `mergeable`
allows you to only send the updated keys to the
parse server as opposed to the whole object. Make sure
to call `mergeable` before you begin
your first mutation of your `ParseObject`.
*/
var changedScore = savedScore.mergeable
changedScore.points = 200
changedScore.save { result in
switch result {
case .success(let savedChangedScore):
assert(savedChangedScore.points == 200)
assert(savedScore.objectId == savedChangedScore.objectId)
case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}
case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}
//: This will store the second batch score to be used later.
var score2ForFetchedLater: GameScore?
//: Saving multiple GameScores at once.
[score, score2].saveAll { results in
switch results {
case .success(let otherResults):
var index = 0
otherResults.forEach { otherResult in
switch otherResult {
case .success(let savedScore):
print("""
Saved \"\(savedScore.className)\" with
points \(String(describing: savedScore.points)) successfully
""")
if index == 1 {
score2ForFetchedLater = savedScore
}
index += 1
case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}
case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}
//: Saving multiple GameScores at once using a transaction.
//: May not work on MongoDB depending on your configuration.
/*[score, score2].saveAll(transaction: true) { results in
switch results {
case .success(let otherResults):
var index = 0
otherResults.forEach { otherResult in
switch otherResult {
case .success(let savedScore):
print("Saved \"\(savedScore.className)\" with points \(savedScore.points) successfully")
if index == 1 {
score2ForFetchedLater = savedScore
}
index += 1
case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}
case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}*/
//: Save synchronously (not preferred - all operations on current queue).
let savedScore: GameScore?
do {
savedScore = try score.save()
} catch {
savedScore = nil
fatalError("Error saving: \(error)")
}
assert(savedScore != nil)
assert(savedScore?.objectId != nil)
assert(savedScore?.createdAt != nil)
assert(savedScore?.updatedAt != nil)
assert(savedScore?.points == 10)
/*:
To modify, you need to make a mutable copy of `savedScore`.
Instead of using `mergeable` this time, we will use the `set()`
method which allows us to accomplish the same thing
as `mergeable`. You can choose to use `set()` or
`mergeable` as long as you use either before you begin
your first mutation of your `ParseObject`.
*/
guard var changedScore = savedScore else {
fatalError("Should have produced mutable changedScore")
}
changedScore = changedScore.set(\.points, to: 200)
let savedChangedScore: GameScore?
do {
savedChangedScore = try changedScore.save()
print("Updated score: \(String(describing: savedChangedScore))")
} catch {
savedChangedScore = nil
fatalError("Error saving: \(error)")
}
assert(savedChangedScore != nil)
assert(savedChangedScore!.points == 200)
assert(savedScore!.objectId == savedChangedScore!.objectId)
let otherResults: [(Result<GameScore, ParseError>)]?
do {
otherResults = try [score, score2].saveAll()
} catch {
otherResults = nil
fatalError("Error saving: \(error)")
}
assert(otherResults != nil)
otherResults!.forEach { result in
switch result {
case .success(let savedScore):
print("Saved \"\(savedScore.className)\" with points \(String(describing: savedScore.points)) successfully")
case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}
//: Now we will create another object and delete it.
let score3 = GameScore(points: 30)
//: Save the score and store it in "scoreToDelete".
var scoreToDelete: GameScore!
do {
scoreToDelete = try score3.save()
print("Successfully saved: \(scoreToDelete!)")
} catch {
assertionFailure("Error deleting: \(error)")
}
//: Delete the score from parse-server synchronously.
do {
try scoreToDelete.delete()
print("Successfully deleted: \(scoreToDelete!)")
} catch {
assertionFailure("Error deleting: \(error)")
}
//: Now we will fetch a ParseObject that has already been saved based on its' objectId.
let scoreToFetch = GameScore(objectId: savedScore?.objectId)
//: Asynchronously (preferred way) fetch this GameScore based on it is objectId alone.
scoreToFetch.fetch { result in
switch result {
case .success(let fetchedScore):
print("Successfully fetched: \(fetchedScore)")
case .failure(let error):
assertionFailure("Error fetching: \(error)")
}
}
//: Synchronously fetch this GameScore based on it is objectId alone.
do {
let fetchedScore = try scoreToFetch.fetch()
print("Successfully fetched: \(fetchedScore)")
} catch {
assertionFailure("Error fetching: \(error)")
}
//: Now we will fetch `ParseObject`'s in batch that have already been saved based on its' objectId.
let score2ToFetch = GameScore(objectId: score2ForFetchedLater?.objectId)
//: Asynchronously (preferred way) fetch GameScores based on it is objectId alone.
[scoreToFetch, score2ToFetch].fetchAll { result in
switch result {
case .success(let fetchedScores):
fetchedScores.forEach { result in
switch result {
case .success(let fetched):
print("Successfully fetched: \(fetched)")
case .failure(let error):
print("Error fetching: \(error)")
}
}
case .failure(let error):
assertionFailure("Error fetching: \(error)")
}
}
var fetchedScore: GameScore!
//: Synchronously fetchAll GameScore's based on it is objectId's alone.
do {
let fetchedScores = try [scoreToFetch, score2ToFetch].fetchAll()
fetchedScores.forEach { result in
switch result {
case .success(let fetched):
fetchedScore = fetched
print("Successfully fetched: \(fetched)")
case .failure(let error):
print("Error fetching: \(error)")
}
}
} catch {
assertionFailure("Error fetching: \(error)")
}
//: Asynchronously (preferred way) deleteAll GameScores based on it is objectId alone.
[scoreToFetch, score2ToFetch].deleteAll { result in
switch result {
case .success(let deletedScores):
deletedScores.forEach { result in
switch result {
case .success:
print("Successfully deleted score")
case .failure(let error):
print("Error deleting: \(error)")
}
}
case .failure(let error):
assertionFailure("Error deleting: \(error)")
}
}
//: Synchronously deleteAll GameScore's based on it is objectId's alone.
//: Commented out because the async above deletes the items already.
/* do {
let fetchedScores = try [scoreToFetch, score2ToFetch].deleteAll()
fetchedScores.forEach { result in
switch result {
case .success(let fetched):
print("Successfully deleted: \(fetched)")
case .failure(let error):
print("Error deleted: \(error)")
}
}
} catch {
assertionFailure("Error deleting: \(error)")
}*/
//: How to add `ParseBytes` and `ParsePolygon` to objects.
let points = [
try ParseGeoPoint(latitude: 0, longitude: 0),
try ParseGeoPoint(latitude: 0, longitude: 1),
try ParseGeoPoint(latitude: 1, longitude: 1),
try ParseGeoPoint(latitude: 1, longitude: 0),
try ParseGeoPoint(latitude: 0, longitude: 0)
]
do {
let polygon = try ParsePolygon(points)
let bytes = ParseBytes(data: "hello world".data(using: .utf8)!)
var gameData = GameData(bytes: bytes, polygon: polygon)
gameData = try gameData.save()
print("Successfully saved: \(gameData)")
} catch {
print("Error saving: \(error.localizedDescription)")
}
PlaygroundPage.current.finishExecution()
//: [Next](@next)
================================================
FILE: ParseSwift.playground/Pages/10 - Cloud Code.xcplaygroundpage/Contents.swift
================================================
//: [Previous](@previous)
//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting
//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`
//: in the `File Inspector` is `Platform = macOS`. This is because
//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should
//: be set to build for `macOS` unless specified.
import PlaygroundSupport
import Foundation
import ParseSwift
PlaygroundPage.current.needsIndefiniteExecution = true
initializeParse()
//: Create your own value typed `ParseCloudable` type.
struct Hello: ParseCloudable {
//: Return type of your Cloud Function
typealias ReturnType = String
//: These are required by `ParseCloudable`, you can set the default value to make it easier
//: to use.
var functionJobName: String = "hello"
}
//: Create another `ParseCloudable` type.
struct TestCloudCode: ParseCloudable {
//: Return type of your Cloud Function
typealias ReturnType = [String: Int]
//: These are required by `ParseCloudable`, you can set the default value to make it easier
//: to use.
var functionJobName: String = "testCloudCode"
//: If your cloud function takes arguments, they can be passed by creating properties:
var argument1: [String: Int]
}
//: Create another `ParseCloudable` type.
struct TestCloudCodeError: ParseCloudable {
//: Return type of your Cloud Function
typealias ReturnType = String
//: These are required by `ParseCloudable`, you can set the default value to make it easier
//: to use.
var functionJobName: String = "testCloudCodeError"
}
/*: Assuming you have the Cloud Function named "hello" on your parse-server:
// main.js
Parse.Cloud.define('hello', async (request) => {
console.log('From client: ' + JSON.stringify(request));
return 'Hello world!';
});
*/
let hello = Hello()
hello.runFunction { result in
switch result {
case .success(let response):
print("Response from cloud function: \(response)")
case .failure(let error):
assertionFailure("Error calling cloud function: \(error)")
}
}
/*: Assuming you have the Cloud Function named "testCloudCode" on your parse-server.
You can catch custom errors created in Cloud Code:
// main.js
Parse.Cloud.define("testCloudCode", async(request) => {
console.log('From client: ' + JSON.stringify(request));
return request.params.argument1;
});
*/
let testCloudCode = TestCloudCode(argument1: ["test": 5])
testCloudCode.runFunction { result in
switch result {
case .success(let response):
print("Response from cloud function: \(response)")
case .failure(let error):
assertionFailure("Error: \(error.localizedDescription)")
}
}
/*: Assuming you have the Cloud Function named "testCloudCode" on your parse-server.
You can catch custom errors created in Cloud Code:
// main.js
Parse.Cloud.define("testCloudCodeError", async(request) => {
console.log('From client: ' + JSON.stringify(request));
throw new Parse.Error(3000, "cloud has an error on purpose.");
});
*/
let testCloudCodeError = TestCloudCodeError()
testCloudCodeError.runFunction { result in
switch result {
case .success:
assertionFailure("Should have thrown a custom error")
case .failure(let error):
switch error.code {
case .other:
guard let otherCode = error.otherCode else {
assertionFailure("Should have unwrapped otherCode")
return
}
switch otherCode {
case 3000:
print("Received Cloud Code error: \(error)")
default:
assertionFailure("""
Should have received code \"3000\"
Instead received \(error)
""")
}
default:
assertionFailure("""
Should have received code \"other\"
Instead received \(error)
""")
}
}
}
//: Jobs can be run the same way by using the method `startJob()`.
/*: Saving objects with context for beforeSave, afterSave, etc.
Parse.Cloud.beforeSave("GameScore", async(request) => {
console.log('From client context: ' + JSON.stringify(request.context));
});
*/
//: Create your own value typed `ParseObject`.
struct GameScore: ParseObject {
//: These are required by ParseObject
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: Your own properties.
var points: Int?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
return updated
}
}
//: It's recommended to place custom initializers in an extension
//: to preserve the memberwise initializer.
extension GameScore {
//: Custom initializer.
init(points: Int) {
self.points = points
}
init(objectId: String?) {
self.objectId = objectId
}
}
//: Define a GameScore.
let score = GameScore(points: 10)
//: Save asynchronously (preferred way) with the context option.
score.save(options: [.context(["hello": "world"])]) { result in
switch result {
case .success(let savedScore):
print("Successfully saved \(savedScore)")
case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}
PlaygroundPage.current.finishExecution()
//: [Next](@next)
================================================
FILE: ParseSwift.playground/Pages/11 - LiveQuery.xcplaygroundpage/Contents.swift
================================================
//: [Previous](@previous)
import PlaygroundSupport
import Foundation
import ParseSwift
import SwiftUI
PlaygroundPage.current.needsIndefiniteExecution = true
initializeParse()
//: Create your own value typed ParseObject.
struct GameScore: ParseObject {
//: These are required by `ParseObject`.
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: Your own properties.
var points: Int?
var location: ParseGeoPoint?
var name: String?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
if updated.shouldRestoreKey(\.location,
original: object) {
updated.location = object.location
}
if updated.shouldRestoreKey(\.name,
original: object) {
updated.name = object.name
}
return updated
}
}
//: It's recommended to place custom initializers in an extension
//: to preserve the memberwise initializer.
extension GameScore {
//: Custom initializer.
init(name: String, points: Int) {
self.name = name
self.points = points
}
}
//: Create a delegate for LiveQuery errors
class LiveQueryDelegate: ParseLiveQueryDelegate {
func received(_ error: Error) {
print(error)
}
func closedSocket(_ code: URLSessionWebSocketTask.CloseCode?, reason: Data?) {
print("Socket closed with \(String(describing: code)) and \(String(describing: reason))")
}
}
//: Be sure you have LiveQuery enabled on your server.
//: Set the delegate.
let delegate = LiveQueryDelegate()
if let socket = ParseLiveQuery.defaultClient {
socket.receiveDelegate = delegate
}
//: Create a query just as you normally would.
var query = GameScore.query("points" < 11)
//: This is how you subscribe to your created query using callbacks.
let subscription = query.subscribeCallback!
//: This is how you receive notifications about the success
//: of your subscription.
subscription.handleSubscribe { subscribedQuery, isNew in
//: You can check this subscription is for this query
if isNew {
print("Successfully subscribed to new query \(subscribedQuery)")
} else {
print("Successfully updated subscription to new query \(subscribedQuery)")
}
}
//: This is how you register to receive notifications of events related to your LiveQuery.
subscription.handleEvent { _, event in
switch event {
case .entered(let object):
print("Entered: \(object)")
case .left(let object):
print("Left: \(object)")
case .created(let object):
print("Created: \(object)")
case .updated(let object):
print("Updated: \(object)")
case .deleted(let object):
print("Deleted: \(object)")
}
}
//: Ping the LiveQuery server
ParseLiveQuery.client?.sendPing { error in
if let error = error {
print("Error pinging LiveQuery server: \(error)")
} else {
print("Successfully pinged server!")
}
}
//: Now go to your dashboard, go to the GameScore table and add, update or remove rows.
//: You should receive notifications for each.
//: This is how you register to receive notifications about being unsubscribed.
subscription.handleUnsubscribe { query in
print("Unsubscribed from \(query)")
}
//: To unsubscribe from your query.
do {
try query.unsubscribe()
} catch {
print(error)
}
//: If you look at your server log, you will notice the client and server disconnnected.
//: This is because there is no more LiveQuery subscriptions.
//: Ping the LiveQuery server. This should produce an error
//: because LiveQuery is disconnected.
ParseLiveQuery.client?.sendPing { error in
if let error = error {
print("Error pinging LiveQuery server: \(error)")
} else {
print("Successfully pinged server!")
}
}
//: Create a new query.
var query2 = GameScore.query("points" > 50)
//: Select the fields you are interested in receiving.
query2.select("points")
//: Subscribe to your new query.
let subscription2 = query2.subscribeCallback!
//: As before, setup your subscription, event, and unsubscribe handlers.
subscription2.handleSubscribe { subscribedQuery, isNew in
//: You can check this subscription is for this query.
if isNew {
print("Successfully subscribed to new query \(subscribedQuery)")
} else {
print("Successfully updated subscription to new query \(subscribedQuery)")
}
}
subscription2.handleEvent { _, event in
switch event {
case .entered(let object):
print("Entered: \(object)")
case .left(let object):
print("Left: \(object)")
case .created(let object):
print("Created: \(object)")
case .updated(let object):
print("Updated: \(object)")
case .deleted(let object):
print("Deleted: \(object)")
}
}
subscription2.handleUnsubscribe { query in
print("Unsubscribed from \(query)")
}
//: To close the current LiveQuery connection.
ParseLiveQuery.client?.close()
//: To close all LiveQuery connections use:
//ParseLiveQuery.client?.closeAll()
//: Ping the LiveQuery server. This should produce an error
//: because LiveQuery is disconnected.
ParseLiveQuery.client?.sendPing { error in
if let error = error {
print("Error pinging LiveQuery server: \(error)")
} else {
print("Successfully pinged server!")
}
}
//: Resubscribe to your previous query.
//: Since we never unsubscribed you can use your previous handlers.
let subscription3 = query2.subscribeCallback!
//: Resubscribe to another previous query.
//: This one needs new handlers.
let subscription4 = query.subscribeCallback!
//: Need a new handler because we previously unsubscribed.
subscription4.handleSubscribe { subscribedQuery, isNew in
//: You can check this subscription is for this query
if isNew {
print("Successfully subscribed to new query \(subscribedQuery)")
} else {
print("Successfully updated subscription to new query \(subscribedQuery)")
}
}
//: Need a new event handler because we previously unsubscribed.
subscription4.handleEvent { _, event in
switch event {
case .entered(let object):
print("Entered: \(object)")
case .left(let object):
print("Left: \(object)")
case .created(let object):
print("Created: \(object)")
case .updated(let object):
print("Updated: \(object)")
case .deleted(let object):
print("Deleted: \(object)")
}
}
//: Need a new unsubscribe handler because we previously unsubscribed.
subscription4.handleUnsubscribe { query in
print("Unsubscribed from \(query)")
}
//: To unsubscribe from your query.
do {
try query2.unsubscribe()
} catch {
print(error)
}
//: Ping the LiveQuery server
ParseLiveQuery.client?.sendPing { error in
if let error = error {
print("Error pinging LiveQuery server: \(error)")
} else {
print("Successfully pinged server!")
}
}
//: To unsubscribe from your your last query.
do {
try query.unsubscribe()
} catch {
print(error)
}
//: If you look at your server log, you will notice the client and server disconnnected.
//: This is because there is no more LiveQuery subscriptions.
PlaygroundPage.current.finishExecution()
//: [Next](@next)
================================================
FILE: ParseSwift.playground/Pages/12 - Roles and Relations.xcplaygroundpage/Contents.swift
================================================
//: [Previous](@previous)
//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting
//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`
//: in the `File Inspector` is `Platform = macOS`. This is because
//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should
//: be set to build for `macOS` unless specified.
import PlaygroundSupport
import Foundation
import ParseSwift
PlaygroundPage.current.needsIndefiniteExecution = true
initializeParse()
struct User: ParseUser {
//: These are required by `ParseObject`.
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: These are required by `ParseUser`.
var username: String?
var email: String?
var emailVerified: Bool?
var password: String?
var authData: [String: [String: String]?]?
//: Your custom keys.
var customKey: String?
var scores: ParseRelation<Self>?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.customKey,
original: object) {
updated.customKey = object.customKey
}
return updated
}
}
struct Role<RoleUser: ParseUser>: ParseRole {
//: Required by `ParseObject`.
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: Provided by Role.
var name: String?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.name,
original: object) {
updated.name = object.name
}
return updated
}
}
//: Create your own value typed `ParseObject`.
struct GameScore: ParseObject {
//: These are required by ParseObject
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: Your own properties.
var points: Int?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
return updated
}
}
//: It's recommended to place custom initializers in an extension
//: to preserve the memberwise initializer.
extension GameScore {
init(points: Int) {
self.points = points
}
init(objectId: String?) {
self.objectId = objectId
}
}
//: Roles can provide additional access/security to your apps.
//: This variable will store the saved role.
var savedRole: Role<User>?
//: Now we will create the Role.
guard let currentUser = User.current else {
fatalError("User currently is not signed in")
}
//: Every Role requires an ACL that cannot be changed after saving.
var acl = ParseACL()
acl.setReadAccess(user: currentUser, value: true)
acl.setWriteAccess(user: currentUser, value: true)
do {
//: Create the actual Role with a name and ACL.
let adminRole = try Role<User>(name: "Administrator", acl: acl)
adminRole.save { result in
switch result {
case .success(let saved):
print("The role saved successfully: \(saved)")
print("Check your \"Role\" class in Parse Dashboard.")
//: Store the saved role so we can use it later...
savedRole = saved
case .failure(let error):
print("Error saving role: \(error)")
}
}
} catch {
print("Error: \(error)")
}
//: Lets check to see if our Role has saved.
if savedRole != nil {
print("We have a saved Role")
}
//: Users can be added to our previously saved Role.
do {
//: `ParseRoles` have `ParseRelations` that relate them either `ParseUser` and `ParseRole` objects.
//: The `ParseUser` relations can be accessed using `users`. We can then add `ParseUser`'s to the relation.
try savedRole!.users?.add([User.current!]).save { result in
switch result {
case .success(let saved):
print("The role saved successfully: \(saved)")
print("Check \"users\" field in your \"Role\" class in Parse Dashboard.")
case .failure(let error):
print("Error saving role: \(error)")
}
}
} catch {
print("Error: \(error)")
}
//: To retrieve the users who are all Administrators, we need to query the relation.
do {
let query: Query<User>? = try savedRole!.users?.query()
query?.find { result in
switch result {
case .success(let relatedUsers):
print("""
The following users are part of the
\"\(String(describing: savedRole!.name)) role: \(relatedUsers)
""")
case .failure(let error):
print("Error querying role: \(error)")
}
}
} catch {
print(error)
}
//: Of course, you can remove users from the roles as well.
do {
try savedRole!.users?.remove([User.current!]).save { result in
switch result {
case .success(let saved):
print("The role removed successfully: \(saved)")
print("Check \"users\" field in your \"Role\" class in Parse Dashboard.")
case .failure(let error):
print("Error saving role: \(error)")
}
}
} catch {
print(error)
}
//: Additional roles can be created and tied to already created roles. Lets create a "Member" role.
//: This variable will store the saved role.
var savedRoleModerator: Role<User>?
do {
//: Create the actual Role with a name and ACL.
let memberRole = try Role<User>(name: "Member", acl: acl)
memberRole.save { result in
switch result {
case .success(let saved):
print("The role saved successfully: \(saved)")
print("Check your \"Role\" class in Parse Dashboard.")
//: Store the saved role so we can use it later...
savedRoleModerator = saved
case .failure(let error):
print("Error saving role: \(error)")
}
}
} catch {
print("Error: \(error)")
}
//: Lets check to see if our Role has saved
if savedRoleModerator != nil {
print("We have a saved Role")
}
//: Roles can be added to our previously saved Role.
do {
//: `ParseRoles` have `ParseRelations` that relate them either `ParseUser` and `ParseRole` objects.
//: The `ParseUser` relations can be accessed using `users`. We can then add `ParseUser`'s to the relation.
try savedRole!.roles?.add([savedRoleModerator!]).save { result in
switch result {
case .success(let saved):
print("The role saved successfully: \(saved)")
print("Check \"roles\" field in your \"Role\" class in Parse Dashboard.")
case .failure(let error):
print("Error saving role: \(error)")
}
}
} catch {
print("Error: \(error)")
}
//: To retrieve the users who are all Administrators, we need to query the relation.
//: This time we will use a helper query from `ParseRole`.
do {
try savedRole!.queryRoles().find { result in
switch result {
case .success(let relatedRoles):
print("""
The following roles are part of the
\"\(String(describing: savedRole!.name)) role: \(relatedRoles)
""")
case .failure(let error):
print("Error querying role: \(error)")
}
}
} catch {
print("Error: \(error)")
}
//: Of course, you can remove users from the roles as well.
do {
try savedRole!.roles?.remove([savedRoleModerator!]).save { result in
switch result {
case .success(let saved):
print("The role removed successfully: \(saved)")
print("Check the \"roles\" field in your \"Role\" class in Parse Dashboard.")
case .failure(let error):
print("Error saving role: \(error)")
}
}
} catch {
print(error)
}
//: Using this relation, you can create one-to-many relationships with other `ParseObjecs`,
//: similar to `users` and `roles`.
//: All `ParseObject`s have a `ParseRelation` attribute that be used on instances.
//: For example, the User has:
var relation = User.current!.relation
let score1 = GameScore(points: 53)
let score2 = GameScore(points: 57)
//: Add new child relationships.
[score1, score2].saveAll { result in
switch result {
case .success(let savedScores):
//: Make an array of all scores that were properly saved.
let scores = savedScores.compactMap { try? $0.get() }
do {
guard let newRelations = try relation?.add("scores", objects: scores) else {
print("Error: should have unwrapped relation")
return
}
newRelations.save { result in
switch result {
case .success(let saved):
print("The relation saved successfully: \(saved)")
print("Check \"points\" field in your \"_User\" class in Parse Dashboard.")
case .failure(let error):
print("Error saving role: \(error)")
}
}
} catch {
print(error)
}
case .failure(let error):
print("Could not save scores. \(error)")
}
}
//: You can also do
// let specificRelation = User.current!.relation("scores", className: "GameScore")
do {
let specificRelation = try User.current!.relation("scores", child: score1)
try (specificRelation.query() as Query<GameScore>).find { result in
switch result {
case .success(let scores):
print("Found related scores: \(scores)")
case .failure(let error):
print("Error querying scores: \(error)")
}
}
} catch {
print(error)
}
//: In addition, you can leverage the child to find scores related to the parent.
do {
try GameScore.queryRelations("scores", parent: User.current!).find { result in
switch result {
case .success(let scores):
print("Found related scores from child: \(scores)")
case .failure(let error):
print("Error querying scores from child: \(error)")
}
}
} catch {
print(error)
}
//: Now we will see how to use the stored `ParseRelation on` property in User to create query
//: all of the relations to `scores`.
var updatedCurrentUser: User
do {
//: Fetch the updated user since the previous relations were created on the server.
updatedCurrentUser = try User.current!.fetch()
print("Updated current user with relation: \(updatedCurrentUser)")
} catch {
updatedCurrentUser = User.current!
print("\(error.localizedDescription)")
}
do {
let usableStoredRelation = try updatedCurrentUser.relation(updatedCurrentUser.scores, key: "scores")
try (usableStoredRelation.query() as Query<GameScore>).find { result in
switch result {
case .success(let scores):
print("Found related scores from stored ParseRelation: \(scores)")
case .failure(let error):
print("Error querying scores from stored ParseRelation: \(error)")
}
}
} catch {
print("\(error.localizedDescription)")
}
PlaygroundPage.current.finishExecution()
//: [Next](@next)
================================================
FILE: ParseSwift.playground/Pages/13 - Operations.xcplaygroundpage/Contents.swift
================================================
//: [Previous](@previous)
//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting
//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`
//: in the `File Inspector` is `Platform = macOS`. This is because
//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should
//: be set to build for `macOS` unless specified.
import PlaygroundSupport
import Foundation
import ParseSwift
PlaygroundPage.current.needsIndefiniteExecution = true
initializeParse()
struct GameScore: ParseObject {
//: These are required by ParseObject.
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: Your own properties.
var points: Int?
var name: String?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
if updated.shouldRestoreKey(\.name,
original: object) {
updated.name = object.name
}
return updated
}
}
//: It's recommended to place custom initializers in an extension
//: to preserve the memberwise initializer.
extension GameScore {
//: Custom initializer.
init(points: Int) {
self.points = points
}
init(objectId: String?) {
self.objectId = objectId
}
}
//: You can have the server do operations on your `ParseObject`'s for you.
//: First lets create another GameScore.
let savedScore: GameScore!
do {
let score = GameScore(points: 102, name: "player1")
savedScore = try score.save()
} catch {
savedScore = nil
assertionFailure("Error saving: \(error)")
}
//: Then we will increment the points.
let incrementOperation = savedScore
.operation.increment("points", by: 1)
incrementOperation.save { result in
switch result {
case .success:
print("Original score: \(String(describing: savedScore)). Check the new score on Parse Dashboard.")
case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}
//: You can increment the score again syncronously.
do {
_ = try incrementOperation.save()
print("Original score: \(String(describing: savedScore)). Check the new score on Parse Dashboard.")
} catch {
print(error)
}
//: Query all scores whose name is null or undefined.
let query1 = GameScore.query(isNotNull(key: "name"))
let results1 = try query1.find()
print("Total found: \(results1.count)")
results1.forEach { score in
print("Found score with a name: \(score)")
}
//: Query all scores whose name is undefined.
let query2 = GameScore.query(exists(key: "name"))
let results2 = try query2.find()
print("Total found: \(results2.count)")
results2.forEach { score in
print("Found score with a name: \(score)")
}
//: You can also remove a value for a property using unset.
let unsetOperation = savedScore
.operation.unset(("points", \.points))
do {
let updatedScore = try unsetOperation.save()
print("Updated score: \(updatedScore). Check the new score on Parse Dashboard.")
} catch {
print(error)
}
//: There may be cases where you want to set/forceSet a value to null
//: instead of unsetting
let setToNullOperation = savedScore
.operation.set(("name", \.name), to: nil)
do {
let updatedScore = try setToNullOperation.save()
print("Updated score: \(updatedScore). Check the new score on Parse Dashboard.")
} catch {
print(error)
}
//: Query all scores whose name is null or undefined.
let query3 = GameScore.query(isNull(key: "name"))
let results3 = try query3.find()
print("Total found: \(results3.count)")
results3.forEach { score in
print("Found score with name is null: \(score)")
}
//: Query all scores whose name is undefined.
let query4 = GameScore.query(doesNotExist(key: "name"))
let results4 = try query4.find()
print("Total found: \(results4.count)")
results4.forEach { score in
print("Found score with name does not exist: \(score)")
}
//: There are other operations: set/forceSet/unset/add/remove, etc. objects from `ParseObject`s.
//: In fact, the `users` and `roles` relations from `ParseRoles` used the add/remove operations.
//: Multiple operations can be chained together. See:
//: https://github.com/parse-community/Parse-Swift/pull/268#issuecomment-955714414
let operations = savedScore.operation
//: Example: operations.add("hello", objects: ["test"]).
PlaygroundPage.current.finishExecution()
//: [Next](@next)
================================================
FILE: ParseSwift.playground/Pages/14 - Config.xcplaygroundpage/Contents.swift
================================================
//: [Previous](@previous)
//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting
//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`
//: in the `File Inspector` is `Platform = macOS`. This is because
//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should
//: be set to build for `macOS` unless specified.
import PlaygroundSupport
import Foundation
import ParseSwift
PlaygroundPage.current.needsIndefiniteExecution = true
initializeParse()
//: Create a value typed `ParseConfig` that matches your server config.
struct Config: ParseConfig {
//: If your server Config has any parameters their names and types should
//: match your ParseCondig properties:
var welcomeMessage: String?
var winningNumber: Int?
}
/*: Go to your Parse Dashboard and click `Config->Create a parameter`:
Now add the following parameters:
- Parameter Name: "welcomeMessage", Type: "String", Value: "Hello".
- Parameter Name: "winningNumber", Type: "Number", Value: "42".
*/
var config = Config()
config.fetch { result in
switch result {
case .success(let currentConfig):
print("The current config on the server: \(currentConfig)")
case .failure(let error):
assertionFailure("Error fetching the config: \(error)")
}
}
//: We can also update the config.
config.winningNumber = 50
//: Save the update.
config.save { result in
switch result {
case .success(let isUpdated):
if isUpdated {
print("The current config on the server has been updated.")
} else {
print("The current config on the server failed to update.")
}
case .failure(let error):
assertionFailure("Error updating the config: \(error)")
}
}
//: Fetch the updated config to make sure it is saved.
config.fetch { result in
switch result {
case .success(let currentConfig):
print("The current config on the server: \(currentConfig)")
case .failure(let error):
assertionFailure("Error fetching the config: \(error)")
}
}
//: Anytime you fetch or update your Config successfully, it is automatically saved to your Keychain.
print(Config.current ?? "No config")
PlaygroundPage.current.finishExecution()
//: [Next](@next)
================================================
FILE: ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift
================================================
//: [Previous](@previous)
//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting
//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`
//: in the `File Inspector` is `Platform = macOS`. This is because
//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should
//: be set to build for `macOS` unless specified.
import PlaygroundSupport
import Foundation
import ParseSwift
PlaygroundPage.current.needsIndefiniteExecution = true
/*:
start parse-server with
npm start -- --appId applicationId --clientKey clientKey --masterKey masterKey --mountPath /1
*/
/*:
In Xcode, make sure you are building the "ParseSwift (macOS)" framework.
*/
initializeParse(customObjectId: true)
//: Create your own value typed `ParseObject`.
struct GameScore: ParseObject {
//: These are required by ParseObject
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: Your own properties.
var points: Int?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
return updated
}
}
//: It's recommended to place custom initializers in an extension
//: to preserve the memberwise initializer.
extension GameScore {
//: Custom initializer.
init(objectId: String, points: Int) {
self.objectId = objectId
self.points = points
}
init(objectId: String) {
self.objectId = objectId
}
}
//: Define initial GameScore this time with custom `objectId`.
//: customObjectId has to be enabled on the server for this to work.
var score = GameScore(objectId: "myObjectId", points: 10)
/*: Save asynchronously (preferred way) - Performs work on background
queue and returns to specified callbackQueue.
If no callbackQueue is specified it returns to main queue.
*/
score.save { result in
switch result {
case .success(let savedScore):
assert(savedScore.objectId != nil)
assert(savedScore.createdAt != nil)
assert(savedScore.updatedAt != nil)
assert(savedScore.points == 10)
//: Now that this object has a `createdAt`, it is properly saved to the server.
//: Any changes to `createdAt` and `objectId` will not be saved to the server.
print("Saved score: \(savedScore)")
/*:
To modify, need to make it a var as the value type
was initialized as immutable. Using `.mergeable` or `set()`
allows you to only send the updated keys to the
parse server as opposed to the whole object.
*/
var changedScore = savedScore.mergeable
changedScore.points = 200
changedScore.save { result in
switch result {
case .success(let savedChangedScore):
assert(savedChangedScore.points == 200)
assert(savedScore.objectId == savedChangedScore.objectId)
print("Updated score: \(savedChangedScore)")
case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}
case .failure(let error):
assertionFailure("Error saving: \(error)")
}
}
//: Fetch object
score.fetch { result in
switch result {
case .success(let fetchedScore):
print("Successfully fetched: \(fetchedScore)")
case .failure(let error):
assertionFailure("Error fetching: \(error)")
}
}
//: Query object
let query = GameScore.query("objectId" == "myObjectId")
query.first { result in
switch result {
case .success(let found):
print(found)
case .failure(let error):
print(error)
}
}
//: Now we will attempt to fetch a ParseObject that is not saved.
let scoreToFetch = GameScore(objectId: "hello")
//: Asynchronously (preferred way) fetch this GameScore based on it is objectId alone.
scoreToFetch.fetch { result in
switch result {
case .success(let fetchedScore):
print("Successfully fetched: \(fetchedScore)")
case .failure(let error):
assertionFailure("Error fetching on purpose: \(error)")
}
}
PlaygroundPage.current.finishExecution()
//: [Next](@next)
================================================
FILE: ParseSwift.playground/Pages/16 - Analytics.xcplaygroundpage/Contents.swift
================================================
//: [Previous](@previous)
//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting
//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`
//: in the `File Inspector` is `Platform = macOS`. This is because
//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should
//: be set to build for `macOS` unless specified.
import PlaygroundSupport
import Foundation
import ParseSwift
PlaygroundPage.current.needsIndefiniteExecution = true
initializeParse()
//: To track when the app has been opened, do the following.
ParseAnalytics.trackAppOpened { result in
switch result {
case .success:
print("Saved analytics for app opened.")
case .failure(let error):
print(error)
}
}
//: To track any event, do the following.
var friendEvent = ParseAnalytics(name: "openedFriendList")
friendEvent.track { result in
switch result {
case .success:
print("Saved analytics for custom event.")
case .failure(let error):
print(error)
}
}
//: You can also add dimensions to your analytics.
friendEvent.track(dimensions: ["more": "info"]) { result in
switch result {
case .success:
print("Saved analytics for custom event with dimensions.")
case .failure(let error):
print(error)
}
}
PlaygroundPage.current.finishExecution()
//: [Next](@next)
================================================
FILE: ParseSwift.playground/Pages/17 - SwiftUI - Finding Objects.xcplaygroundpage/Contents.swift
================================================
//: [Previous](@previous)
//: If you are using Xcode 13+, ignore the comments below:
//: For this page, make sure your build target is set to ParseSwift (iOS) and targeting
//: an iPhone, iPod, or iPad. Also be sure your `Playground Settings`
//: in the `File Inspector` is `Platform = iOS`. This is because
//: SwiftUI in macOS Playgrounds does not seem to build correctly
//: Be sure to switch your target and `Playground Settings` back to
//: macOS after leaving this page.
import PlaygroundSupport
import Foundation
import ParseSwift
import SwiftUI
PlaygroundPage.current.needsIndefiniteExecution = true
initializeParse()
//: Create your own value typed ParseObject.
struct GameScore: ParseObject {
//: These are required by `ParseObject`.
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: Your own properties.
var points: Int?
var location: ParseGeoPoint?
var name: String?
var myFiles: [ParseFile]?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
if updated.shouldRestoreKey(\.name,
original: object) {
updated.name = object.name
}
if updated.shouldRestoreKey(\.myFiles,
original: object) {
updated.myFiles = object.myFiles
}
if updated.shouldRestoreKey(\.location,
original: object) {
updated.location = object.location
}
return updated
}
}
//: It's recommended to place custom initializers in an extension
//: to preserve the memberwise initializer.
extension GameScore {
//: Custom initializer.
init(name: String, points: Int) {
self.name = name
self.points = points
}
}
//: To use queries with SwiftUI
//: Create a SwiftUI view.
struct ContentView: View {
//: A view model in SwiftUI
@StateObject var viewModel = GameScore.query("points" > 2)
.order([.descending("points")])
.viewModel
@State var name = ""
@State var points = ""
@State var isShowingAction = false
@State var savedLabel = ""
var body: some View {
NavigationView {
VStack {
TextField("Name", text: $name)
TextField("Points", text: $points)
Button(action: {
guard let pointsValue = Int(points),
let linkToFile = URL(string: "https://parseplatform.org/img/logo.svg") else {
return
}
var score = GameScore(name: name,
points: pointsValue)
//: Create new `ParseFile` for saving.
let file1 = ParseFile(name: "file1.svg",
cloudURL: linkToFile)
let file2 = ParseFile(name: "file2.svg",
cloudURL: linkToFile)
score.myFiles = [file1, file2]
score.save { result in
switch result {
case .success:
savedLabel = "Saved score"
self.viewModel.find()
case .failure(let error):
savedLabel = "Error: \(error.message)"
}
isShowingAction = true
}
}, label: {
Text("Save score")
})
}
if let error = viewModel.error {
Text(error.description)
} else {
//: Warning - List seems to only work in Playgrounds Xcode 13+.
List(viewModel.results, id: \.id) { result in
VStack(alignment: .leading) {
Text("Points: \(String(describing: result.points))")
.font(.headline)
if let createdAt = result.createdAt {
Text("\(createdAt.description)")
}
}
}
}
Spacer()
}.onAppear(perform: {
viewModel.find()
}).alert(isPresented: $isShowingAction, content: {
Alert(title: Text("GameScore"),
message: Text(savedLabel),
dismissButton: .default(Text("Ok"), action: {
}))
})
}
}
PlaygroundPage.current.setLiveView(ContentView())
PlaygroundPage.current.finishExecution()
//: [Next](@next)
================================================
FILE: ParseSwift.playground/Pages/18 - SwiftUI - Finding Objects With Custom ViewModel.xcplaygroundpage/Contents.swift
================================================
//: [Previous](@previous)
//: If you are using Xcode 13+, ignore the comments below:
//: For this page, make sure your build target is set to ParseSwift (iOS) and targeting
//: an iPhone, iPod, or iPad. Also be sure your `Playground Settings`
//: in the `File Inspector` is `Platform = iOS`. This is because
//: SwiftUI in macOS Playgrounds does not seem to build correctly
//: Be sure to switch your target and `Playground Settings` back to
//: macOS after leaving this page.
import PlaygroundSupport
import Foundation
import ParseSwift
import SwiftUI
import Combine
PlaygroundPage.current.needsIndefiniteExecution = true
initializeParse()
//: Create your own value typed ParseObject.
struct GameScore: ParseObject {
//: These are required by `ParseObject`.
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: Your own properties.
var points: Int?
var location: ParseGeoPoint?
var name: String?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
if updated.shouldRestoreKey(\.name,
original: object) {
updated.name = object.name
}
if updated.shouldRestoreKey(\.location,
original: object) {
updated.location = object.location
}
return updated
}
}
//: It's recommended to place custom initializers in an extension
//: to preserve the memberwise initializer.
extension GameScore {
//: Custom initializer.
init(name: String, points: Int) {
self.name = name
self.points = points
}
}
//: To use queries with SwiftUI
//: To create a custom view model that queries GameScore's.
class ViewModel: ObservableObject {
@Published var objects = [GameScore]()
@Published var error: ParseError?
private var subscriptions = Set<AnyCancellable>()
init() {
fetchScores()
}
func fetchScores() {
let query = GameScore.query("points" > 2)
.order([.descending("points")])
let publisher = query
.findPublisher()
.sink(receiveCompletion: { result in
switch result {
case .failure(let error):
//: Publish error.
self.error = error
case .finished:
print("Successfully queried data")
}
},
receiveValue: {
//: Publish found objects
self.objects = $0
print("Found \(self.objects.count), objects: \(self.objects)")
})
publisher.store(in: &subscriptions)
}
}
//: Create a SwiftUI view.
struct ContentView: View {
//: A view model in SwiftUI
@StateObject var viewModel = ViewModel()
var body: some View {
NavigationView {
if let error = viewModel.error {
Text(error.description)
} else {
//: Warning - List seems to only work in Playgrounds Xcode 13+.
List(viewModel.objects, id: \.id) { object in
VStack(alignment: .leading) {
Text("Points: \(String(describing: object.points))")
.font(.headline)
if let createdAt = object.createdAt {
Text("\(createdAt.description)")
}
}
}
}
Spacer()
}
}
}
PlaygroundPage.current.setLiveView(ContentView())
PlaygroundPage.current.finishExecution()
//: [Next](@next)
================================================
FILE: ParseSwift.playground/Pages/19 - SwiftUI - LiveQuery.xcplaygroundpage/Contents.swift
================================================
//: [Previous](@previous)
//: If you are using Xcode 13+, ignore the comments below:
//: For this page, make sure your build target is set to ParseSwift (iOS) and targeting
//: an iPhone, iPod, or iPad. Also be sure your `Playground Settings`
//: in the `File Inspector` is `Platform = iOS`. This is because
//: SwiftUI in macOS Playgrounds does not seem to build correctly
//: Be sure to switch your target and `Playground Settings` back to
//: macOS after leaving this page.
import PlaygroundSupport
import Foundation
import ParseSwift
import SwiftUI
PlaygroundPage.current.needsIndefiniteExecution = true
initializeParse()
//: Create your own value typed ParseObject.
struct GameScore: ParseObject {
//: These are required by `ParseObject`.
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: Your own properties.
var points: Int? = 0
var location: ParseGeoPoint?
var name: String?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
if updated.shouldRestoreKey(\.name,
original: object) {
updated.name = object.name
}
if updated.shouldRestoreKey(\.location,
original: object) {
updated.location = object.location
}
return updated
}
}
//: It's recommended to place custom initializers in an extension
//: to preserve the memberwise initializer.
extension GameScore {
//: Custom initializer.
init(name: String, points: Int) {
self.name = name
self.points = points
}
}
//: Be sure you have LiveQuery enabled on your server.
//: Create a query just as you normally would.
var query = GameScore.query("points" < 11)
//: To use subscriptions inside of SwiftUI
struct ContentView: View {
//: A LiveQuery subscription can be used as a view model in SwiftUI
@StateObject var subscription = query.subscribe!
var body: some View {
VStack {
if subscription.subscribed != nil {
Text("Subscribed to query!")
} else if subscription.unsubscribed != nil {
Text("Unsubscribed from query!")
} else if let event = subscription.event {
//: This is how you register to receive notifications of events related to your LiveQuery.
switch event.event {
case .entered(let object):
Text("Entered with points: \(String(describing: object.points))")
case .left(let object):
Text("Left with points: \(String(describing: object.points))")
case .created(let object):
Text("Created with points: \(String(describing: object.points))")
case .updated(let object):
Text("Updated with points: \(String(describing: object.points))")
case .deleted(let object):
Text("Deleted with points: \(String(describing: object.points))")
}
} else {
Text("Not subscribed to a query")
}
Text("Update GameScore in Parse Dashboard to see changes here:")
Button(action: {
try? query.unsubscribe()
}, label: {
Text("Unsubscribe")
.font(.headline)
.background(Color.red)
.foregroundColor(.white)
.padding()
.cornerRadius(20.0)
})
Spacer()
}
}
}
PlaygroundPage.current.setLiveView(ContentView())
PlaygroundPage.current.finishExecution()
//: [Next](@next)
================================================
FILE: ParseSwift.playground/Pages/2 - Finding Objects.xcplaygroundpage/Contents.swift
================================================
//: [Previous](@previous)
//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting
//: `My Mac` or whatever the name of your mac is. Also be sure your `Playground Settings`
//: in the `File Inspector` is `Platform = macOS`. This is because
//: Keychain in iOS Playgrounds behaves differently. Every page in Playgrounds should
//: be set to build for `macOS` unless specified.
import PlaygroundSupport
import Foundation
import ParseSwift
PlaygroundPage.current.needsIndefiniteExecution = true
initializeParse()
struct GameScore: ParseObject {
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: Your own properties.
var points: Int?
var timeStamp: Date? = Date()
var oldScore: Int?
var isHighest: Bool?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
if updated.shouldRestoreKey(\.timeStamp,
original: object) {
updated.timeStamp = object.timeStamp
}
if updated.shouldRestoreKey(\.oldScore,
original: object) {
updated.oldScore = object.oldScore
}
if updated.shouldRestoreKey(\.isHighest,
original: object) {
updated.isHighest = object.isHighest
}
return updated
}
}
var score = GameScore()
score.points = 200
score.oldScore = 10
score.isHighest = true
do {
try score.save()
} catch {
print(error)
}
let afterDate = Date().addingTimeInterval(-300)
var query = GameScore.query("points" > 50,
"createdAt" > afterDate)
.order([.descending("points")])
//: Query asynchronously (preferred way) - Performs work on background
//: queue and returns to specified callbackQueue.
//: If no callbackQueue is specified it returns to main queue.
query.limit(2)
.order([.descending("points")])
.find(callbackQueue: .main) { results in
switch results {
case .success(let scores):
assert(scores.count >= 1)
scores.forEach { score in
guard let createdAt = score.createdAt else { fatalError() }
assert(createdAt.timeIntervalSince1970 > afterDate.timeIntervalSince1970, "date should be ok")
print("Found score: \(score)")
}
case .failure(let error):
if error.equalsTo(.objectNotFound) {
assertionFailure("Object not found for this query")
} else {
assertionFailure("Error querying: \(error)")
}
}
}
//: Query synchronously (not preferred - all operations on current queue).
let results = try query.find()
assert(results.count >= 1)
results.forEach { score in
guard let createdAt = score.createdAt else { fatalError() }
assert(createdAt.timeIntervalSince1970 > afterDate.timeIntervalSince1970, "date should be ok")
print("Found score: \(score)")
}
//: Query first asynchronously (preferred way) - Performs work on background
//: queue and returns to specified callbackQueue.
//: If no callbackQueue is specified it returns to main queue.
query.first { results in
switch results {
case .success(let score):
guard score.objectId != nil,
let createdAt = score.createdAt else { fatalError() }
assert(createdAt.timeIntervalSince1970 > afterDate.timeIntervalSince1970, "date should be ok")
print("Found score: \(score)")
case .failure(let error):
if error.containedIn([.objectNotFound, .invalidQuery]) {
assertionFailure("The query is invalid or the object is not found.")
} else {
assertionFailure("Error querying: \(error)")
}
}
}
//: Query first asynchronously (preferred way) - Performs work on background
//: queue and returns to specified callbackQueue.
//: If no callbackQueue is specified it returns to main queue.
query.withCount { results in
switch results {
case .success(let (score, count)):
print("Found scores: \(score) total amount: \(count)")
case .failure(let error):
if error.containedIn([.objectNotFound, .invalidQuery]) {
assertionFailure("The query is invalid or the object is not found.")
} else {
assertionFailure("Error querying: \(error)")
}
}
}
//: Query based on relative time.
let queryRelative = GameScore.query(relative("createdAt" < "in 10 minutes"))
queryRelative.find { results in
switch results {
case .success(let scores):
print("Found scores using relative time: \(scores)")
case .failure(let error):
print("Error querying: \(error)")
}
}
let querySelect = query.select("points")
querySelect.first { results in
switch results {
case .success(let score):
guard score.objectId != nil,
let createdAt = score.createdAt else { fatalError() }
assert(createdAt.timeIntervalSince1970 > afterDate.timeIntervalSince1970, "date should be ok")
print("Found score using select: \(score)")
case .failure(let error):
if let parseError = error.equalsTo(.objectNotFound) {
assertionFailure("Object not found: \(parseError)")
} else {
assertionFailure("Error querying: \(error)")
}
}
}
let queryExclude = query.exclude("points")
queryExclude.first { results in
switch results {
case .success(let score):
guard score.objectId != nil,
let createdAt = score.createdAt else { fatalError() }
assert(createdAt.timeIntervalSince1970 > afterDate.timeIntervalSince1970, "date should be ok")
print("Found score using exclude: \(score)")
case .failure(let error):
if let parseError = error.containedIn(.objectNotFound, .invalidQuery) {
assertionFailure("Matching error found: \(parseError)")
} else {
assertionFailure("Error querying: \(error)")
}
}
}
PlaygroundPage.current.finishExecution()
//: [Next](@next)
================================================
FILE: ParseSwift.playground/Pages/20 - Cloud Schemas.xcplaygroundpage/Contents.swift
================================================
//: [Previous](@previous)
/*:
The code in this Playground is intended to run at the
server level only. It is not intended to be run in client
applications as it requires the use of the master key.
*/
import PlaygroundSupport
import Foundation
import ParseSwift
PlaygroundPage.current.needsIndefiniteExecution = true
initializeParse()
//: Youe specific _User value type.
struct User: ParseUser {
//: These are required by `ParseObject`.
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: These are required by `ParseUser`.
var username: String?
var email: String?
var emailVerified: Bool?
var password: String?
var authData: [String: [String: String]?]?
//: Your custom keys.
var customKey: String?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.customKey,
original: object) {
updated.customKey = object.customKey
}
return updated
}
}
//: Create your own value typed `ParseObject`.
struct GameScore2: ParseObject {
//: These are required by ParseObject
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: Your own properties.
var points: Int?
var level: Int?
var data: ParseBytes?
var owner: User?
var rivals: [User]?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.points,
original: object) {
updated.points = object.points
}
if updated.shouldRestoreKey(\.level,
original: object) {
updated.level = object.level
}
if updated.shouldRestoreKey(\.data,
original: object) {
updated.data = object.data
}
if updated.shouldRestoreKey(\.owner,
original: object) {
updated.owner = object.owner
}
if updated.shouldRestoreKey(\.rivals,
original: object) {
updated.rivals = object.rivals
}
return updated
}
}
/*:
It's recommended to place custom initializers in an extension
to preserve the memberwise initializer.
*/
extension GameScore2 {
init(points: Int) {
self.points = points
}
init(objectId: String?) {
self.objectId = objectId
}
}
//: First lets create a new CLP for the new schema.
let clp = ParseCLP(requiresAuthentication: true, publicAccess: false)
.setAccessPublic(true, on: .get)
.setAccessPublic(true, on: .find)
//: Next we use the CLP to create the new schema and add fields to it.
var gameScoreSchema = ParseSchema<GameScore2>(classLevelPermissions: clp)
.addField("points",
type: .number,
options: ParseFieldOptions<Int>(required: false, defauleValue: nil))
.addField("level",
type: .number,
options: ParseFieldOptions<Int>(required: false, defauleValue: nil))
.addField("data",
type: .bytes,
options: ParseFieldOptions<String>(required: false, defauleValue: nil))
do {
gameScoreSchema = try gameScoreSchema
.addField("owner",
type: .pointer,
options: ParseFieldOptions<User>(required: false, defauleValue: nil))
.addField("rivals",
type: .array,
options: ParseFieldOptions<[User]>(required: false, defauleValue: nil))
} catch {
print("Cannot add field: \(gameScoreSchema)")
}
//: Now lets create the schema on the server.
gameScoreSchema.create { result in
switch result {
case .success(let savedSchema):
print("Check GameScore2 in Dashboard. \nThe created schema: \(savedSchema)")
case .failure(let error):
print("Could not save schema: \(error)")
}
}
//: We can update the CLP to only allow access to users specified in the "owner" field.
let clp2 = clp.setPointerFields(Set(["owner"]), on: .get)
gameScoreSchema.classLevelPermissions = clp2
//: In addition, we can add an index.
gameScoreSchema = gameScoreSchema.addIndex("myIndex", field: "level", index: 1)
//: Next, we need to update the schema on the server with the changes.
gameScoreSchema.update { result in
switch result {
case .success(let updatedSchema):
print("Check GameScore2 in Dashboard. \nThe updated schema: \(updatedSchema)")
/*:
Updated the current gameScoreSchema with the newest.
*/
gameScoreSchema = updatedSchema
case .failure(let error):
print("Could not update schema: \(error)")
}
}
//: Indexes can also be deleted.
gameScoreSchema = gameScoreSchema.deleteIndex("myIndex")
//: Next, we need to update the schema on the server with the changes.
gameScoreSchema.update { result in
switch result {
case .success(let updatedSchema):
print("Check GameScore2 in Dashboard. \nThe updated schema: \(updatedSchema)")
/*:
Updated the current gameScoreSchema with the newest.
*/
gameScoreSchema = updatedSchema
case .failure(let error):
print("Could not update schema: \(error)")
}
}
//: We can also fetch the schema.
gameScoreSchema.fetch { result in
switch result {
case .success(let fetchedGameScore):
print("The fetched GameScore2 schema is: \(fetchedGameScore)")
case .failure(let error):
print("Could not fetch schema: \(error)")
}
}
/*:
Fields can also be deleted on a schema. Lets remove
the **data** field since it is not going being used.
*/
gameScoreSchema = gameScoreSchema.deleteField("data")
//: Next, we need to update the schema on the server with the changes.
gameScoreSchema.update { result in
switch result {
case .success(let updatedSchema):
print("Check GameScore2 in Dashboard. \nThe updated schema: \(updatedSchema)")
/*:
Updated the current gameScoreSchema with the newest.
*/
gameScoreSchema = updatedSchema
case .failure(let error):
print("Could not update schema: \(error)")
}
}
/*:
Sets of fields can also be protected from access. Lets protect
some fields from access.
*/
var clp3 = gameScoreSchema.classLevelPermissions
clp3 = clp3?
.setProtectedFieldsPublic(["owner"])
.setProtectedFields(["level"], userField: "rivals")
gameScoreSchema.classLevelPermissions = clp3
//: Next, we need to update the schema on the server with the changes.
gameScoreSchema.update { result in
switch result {
case .success(let updatedSchema):
print("Check GameScore2 in Dashboard. \nThe updated schema: \(updatedSchema)")
/*:
Updated the current gameScoreSchema with the newest.
*/
gameScoreSchema = updatedSchema
case .failure(let error):
print("Could not update schema: \(error)")
}
}
//: Now lets save a new object to the new schema.
var gameScore = GameScore2()
gameScore.points = 120
gameScore.owner = User.current
gameScore.save { result in
switch result {
case .success(let savedGameScore):
print("The saved GameScore is: \(savedGameScore)")
case .failure(let error):
print("Could not save schema: \(error)")
}
}
//: You can delete all objects your schema by purging them.
gameScoreSchema.purge { result in
switch result {
case .success:
print("All objects have been purged from this schema.")
case .failure(let error):
print("Could not purge schema: \(error)")
}
}
/*:
As long as there is no data in your `ParseSchema` you can
delete the schema.
*/
gameScoreSchema.delete { result in
switch result {
case .success:
print("The schema has been deleted.")
case .failure(let error):
print("Could not delete the schema: \(error)")
}
}
PlaygroundPage.current.finishExecution()
//: [Next](@next)
================================================
FILE: ParseSwift.playground/Pages/21 - Cloud Push Notifications.xcplaygroundpage/Contents.swift
================================================
//: [Previous](@previous)
/*:
The code in this Playground is intended to run at the
server level only. It is not intended to be run in client
applications as it requires the use of the master key.
*/
import PlaygroundSupport
import Foundation
import ParseSwift
PlaygroundPage.current.needsIndefiniteExecution = true
initializeParse()
struct Installation: ParseInstallation {
//: These are required by `ParseObject`.
var objectId: String?
var createdAt: Date?
var updatedAt: Date?
var ACL: ParseACL?
var originalData: Data?
//: These are required by `ParseInstallation`.
var installationId: String?
var deviceType: String?
var deviceToken: String?
var badge: Int?
var timeZone: String?
var channels: [String]?
var appName: String?
var appIdentifier: String?
var appVersion: String?
var parseVersion: String?
var localeIdentifier: String?
//: Your custom keys
var customKey: String?
/*:
Optional - implement your own version of merge
for faster decoding after updating your `ParseObject`.
*/
func merge(with object: Self) throws -> Self {
var updated = try mergeParse(with: object)
if updated.shouldRestoreKey(\.customKey,
original: object) {
updated.customKey = object.customKey
}
return updated
}
}
/*:
We will begin by creating the payload information we want to
send in the push notification.
*/
let helloAlert = ParsePushAppleAlert(body: "Hello from ParseSwift!")
let applePayload = ParsePushPayloadApple(alert: helloAlert)
.setBadge(1)
/*:
We now crate a query where the `objectId`
is not null or undefined.
*/
let installationQuery = Installation.query(isNotNull(key: "objectId"))
//: Now create a new push notification using the payload and query.
let push = ParsePush(payload: applePayload, query: installationQuery)
//: Creating this property to use later in the playground.
var pushStatusId = ""
//: You can send the push notification whenever you are ready.
push.send { result in
switch result {
case .success(let statusId):
print("The push was created with id: \"\(statusId)\"")
//: Update the stored property with the lastest status id.
pushStatusId = statusId
case .failure(let error):
print("Could not create push: \(error)")
}
}
//: You can fetch the status of notificaiton if you know it is id.
push.fetchStatus(pushStatusId) { result in
switch result {
case .success(let pushStatus):
print("The push status is: \"\(pushStatus)\"")
case .failure(let error):
print("Could not fetch push status: \(error)")
}
}
/*:
Lets create another Push, this time by incrementing the badge
and using channels instead of a query.
*/
let helloAgainAlert = ParsePushAppleAlert(body: "Hello from ParseSwift again!")
let applePayload2 = ParsePushPayloadApple(alert: helloAgainAlert)
.incrementBadge()
var push2 = ParsePush(payload: applePayload2)
//: Set all channels the notificatioin should be published to.
push2.channels = Set(["newDevices"])
//: You can send the push notification whenever you are ready.
push2.send { result in
switch result {
case .success(let statusId):
print("The push was created with id: \"\(statusId)\"")
//: Update the stored property with the lastest status id.
pushStatusId = statusId
case .failure(let error):
print("Could not create push: \(error)")
}
}
/*:
Similar to before, you can fetch the status of notificaiton
if you know the id.
*/
push2.fetchStatus(pushStatusId) { result in
switch result {
case .success(let pushStatus):
print("The push status is: \"\(pushStatus)\"")
case .failure(let error):
print("Could not fetch push status: \(error)")
}
}
/*:
You can also send push notifications using Firebase Cloud Messanger.
*/
let helloNotification = ParsePushFirebaseNotification(body: "Hello from ParseSwift using FCM!")
let firebasePayload = ParsePushPayloadFirebase(notification: helloNotification)
let push3 = ParsePush(payload: firebasePayload, query: installationQuery)
//: You can send the push notification whenever you are ready.
push3.send { result in
switch result {
case .success(let statusId):
print("The Firebase push was created with id: \"\(statusId)\"")
//: Update the stored property with the lastest status id.
pushStatusId = statusId
case .failure(let error):
print("Could not create push: \(error)")
}
}
/*:
Similar to before, you can fetch the status of notificaiton
if you know the id.
*/
push3.fetchStatus(pushStatusId) { result in
switch result {
case .success(let pushStatus):
print("The Firebase push status is: \"\(pushStatus)\"")
case .failure(let error):
print("Could not fetch push status: \(error)")
}
}
/*:
If you have a mixed push environment and are querying
multiple ParsePushStatus's you will can use the any
payload, `ParsePushPayloadAny`.
*/
let query = ParsePushStatus<ParsePushPayloadAny>
.query(isNotNull(key: "objectId"))
/*:
Be sure to add the `.userMasterKey option when doing
anything with `ParsePushStatus` directly.
*/
query.findAll(options: [.useMasterKey]) { result in
switch result {
case .success(let pushStatus):
print("All matching statuses: \"\(pushStatus)\"")
case .failure(let error):
print("Could not perform query: \(error)")
}
}
PlaygroundPage.current.finishExecution()
//: [Next](@next)
================================================
FILE: ParseSwift.playground/Pages/22 - Cloud Hook Functions.xcplaygroundpage/Contents.swift
================================================
//: [Previous](@previous)
/*:
The code in this Playground is intended to run at the
server level only. It is not intended to be run in client
applications as it requires the use
gitextract_a915zrx1/
├── .codecov.yml
├── .github/
│ ├── ISSUE_TEMPLATE/
│ │ ├── ---1-report-an-issue.md
│ │ ├── ---2-feature-request.md
│ │ └── config.yml
│ ├── pull_request_template.md
│ └── workflows/
│ ├── ci.yml
│ └── release.yml
├── .gitignore
├── .spi.yml
├── .swiftlint.yml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── MIGRATION.md
├── Package.swift
├── Package@5.1.swift
├── Parse.xcworkspace/
│ ├── contents.xcworkspacedata
│ └── xcshareddata/
│ └── IDEWorkspaceChecks.plist
├── ParseSwift-iOS/
│ └── Info.plist
├── ParseSwift-macOS/
│ └── Info.plist
├── ParseSwift-tvOS/
│ ├── Info.plist
│ └── ParseSwift_tvOS.h
├── ParseSwift-watchOS/
│ ├── Info.plist
│ └── ParseSwift_watchOS.h
├── ParseSwift.playground/
│ ├── Pages/
│ │ ├── 1 - Your first Object.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 10 - Cloud Code.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 11 - LiveQuery.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 12 - Roles and Relations.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 13 - Operations.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 14 - Config.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 15 - Custom ObjectId.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 16 - Analytics.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 17 - SwiftUI - Finding Objects.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 18 - SwiftUI - Finding Objects With Custom ViewModel.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 19 - SwiftUI - LiveQuery.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 2 - Finding Objects.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 20 - Cloud Schemas.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 21 - Cloud Push Notifications.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 22 - Cloud Hook Functions.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 23 - Cloud Hook Triggers.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 3 - User - Sign Up.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 4 - User - Continued.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 5 - ACL.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 6 - Installation.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 7 - GeoPoint.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ ├── 8 - Pointers.xcplaygroundpage/
│ │ │ └── Contents.swift
│ │ └── 9 - Files.xcplaygroundpage/
│ │ └── Contents.swift
│ ├── Sources/
│ │ └── Common.swift
│ └── contents.xcplayground
├── ParseSwift.podtemplate
├── ParseSwift.xcodeproj/
│ ├── project.pbxproj
│ ├── project.xcworkspace/
│ │ ├── contents.xcworkspacedata
│ │ └── xcshareddata/
│ │ └── IDEWorkspaceChecks.plist
│ └── xcshareddata/
│ └── xcschemes/
│ ├── ParseSwift (iOS).xcscheme
│ ├── ParseSwift (macOS).xcscheme
│ ├── ParseSwift (tvOS).xcscheme
│ ├── ParseSwift (watchOS).xcscheme
│ ├── TestHost.xcscheme
│ └── TestHostTV.xcscheme
├── ParseSwiftTestsmacOS/
│ └── Info.plist
├── ParseSwiftTeststvOS/
│ └── Info.plist
├── README.md
├── Scripts/
│ ├── carthage.sh
│ ├── generate-documentation
│ ├── update-gh-pages-documentation-site
│ └── update_build
├── Sources/
│ └── ParseSwift/
│ ├── API/
│ │ ├── API+BatchCommand.swift
│ │ ├── API+Command+async.swift
│ │ ├── API+Command.swift
│ │ ├── API+NonParseBodyCommand+async.swift
│ │ ├── API+NonParseBodyCommand.swift
│ │ ├── API.swift
│ │ ├── BatchUtils.swift
│ │ ├── ParseURLSessionDelegate.swift
│ │ └── Responses.swift
│ ├── Authentication/
│ │ ├── 3rd Party/
│ │ │ ├── ParseApple/
│ │ │ │ ├── ParseApple+async.swift
│ │ │ │ ├── ParseApple+combine.swift
│ │ │ │ └── ParseApple.swift
│ │ │ ├── ParseFacebook/
│ │ │ │ ├── ParseFacebook+async.swift
│ │ │ │ ├── ParseFacebook+combine.swift
│ │ │ │ └── ParseFacebook.swift
│ │ │ ├── ParseGithub/
│ │ │ │ ├── ParseGitHub+async.swift
│ │ │ │ ├── ParseGitHub+combine.swift
│ │ │ │ └── ParseGitHub.swift
│ │ │ ├── ParseGoogle/
│ │ │ │ ├── ParseGoogle+async.swift
│ │ │ │ ├── ParseGoogle+combine.swift
│ │ │ │ └── ParseGoogle.swift
│ │ │ ├── ParseInstagram/
│ │ │ │ ├── ParseInstagram+async.swift
│ │ │ │ ├── ParseInstagram+combine.swift
│ │ │ │ └── ParseInstagram.swift
│ │ │ ├── ParseLDAP/
│ │ │ │ ├── ParseLDAP+async.swift
│ │ │ │ ├── ParseLDAP+combine.swift
│ │ │ │ └── ParseLDAP.swift
│ │ │ ├── ParseLinkedIn/
│ │ │ │ ├── ParseLinkedIn+async.swift
│ │ │ │ ├── ParseLinkedIn+combine.swift
│ │ │ │ └── ParseLinkedIn.swift
│ │ │ ├── ParseSpotify/
│ │ │ │ ├── ParseSpotify+async.swift
│ │ │ │ ├── ParseSpotify+combine.swift
│ │ │ │ └── ParseSpotify.swift
│ │ │ └── ParseTwitter/
│ │ │ ├── ParseTwitter+async.swift
│ │ │ ├── ParseTwitter+combine.swift
│ │ │ └── ParseTwitter.swift
│ │ ├── Internal/
│ │ │ ├── ParseAnonymous+async.swift
│ │ │ ├── ParseAnonymous+combine.swift
│ │ │ └── ParseAnonymous.swift
│ │ └── Protocols/
│ │ ├── ParseAuthentication+async.swift
│ │ ├── ParseAuthentication+combine.swift
│ │ └── ParseAuthentication.swift
│ ├── Coding/
│ │ ├── AnyCodable.swift
│ │ ├── AnyDecodable.swift
│ │ ├── AnyEncodable.swift
│ │ ├── ParseCoding.swift
│ │ └── ParseEncoder.swift
│ ├── Documentation.docc/
│ │ ├── ParseSwift.md
│ │ ├── ParseSwift.tutorial
│ │ └── Your First Object.tutorial
│ ├── Extensions/
│ │ ├── Data.swift
│ │ ├── Date.swift
│ │ ├── Dictionary.swift
│ │ ├── Encodable.swift
│ │ ├── URLCache.swift
│ │ └── URLSession.swift
│ ├── InternalObjects/
│ │ ├── BaseConfig.swift
│ │ ├── BaseParseInstallation.swift
│ │ ├── BaseParseUser.swift
│ │ └── NoBody.swift
│ ├── LiveQuery/
│ │ ├── LiveQueryConstants.swift
│ │ ├── LiveQuerySocket.swift
│ │ ├── Messages.swift
│ │ ├── Operations.swift
│ │ ├── ParseLiveQuery+async.swift
│ │ ├── ParseLiveQuery+combine.swift
│ │ ├── ParseLiveQuery.swift
│ │ ├── ParseLiveQueryConstants.swift
│ │ ├── Protocols/
│ │ │ ├── LiveQuerySocketDelegate.swift
│ │ │ ├── LiveQueryable.swift
│ │ │ ├── ParseLiveQueryDelegate.swift
│ │ │ └── QuerySubscribable.swift
│ │ ├── Subscription.swift
│ │ └── SubscriptionCallback.swift
│ ├── Objects/
│ │ ├── ParseCloudUser.swift
│ │ ├── ParseInstallation+async.swift
│ │ ├── ParseInstallation+combine.swift
│ │ ├── ParseInstallation.swift
│ │ ├── ParseObject+async.swift
│ │ ├── ParseObject+combine.swift
│ │ ├── ParseObject.swift
│ │ ├── ParsePushStatusable.swift
│ │ ├── ParseRole.swift
│ │ ├── ParseSession.swift
│ │ ├── ParseUser+async.swift
│ │ ├── ParseUser+combine.swift
│ │ └── ParseUser.swift
│ ├── Operations/
│ │ ├── Add.swift
│ │ ├── AddRelation.swift
│ │ ├── AddUnique.swift
│ │ ├── Delete.swift
│ │ ├── Increment.swift
│ │ ├── Operation.swift
│ │ ├── Remove.swift
│ │ └── RemoveRelation.swift
│ ├── Parse.h
│ ├── Parse.swift
│ ├── ParseConstants.swift
│ ├── Protocols/
│ │ ├── CloudObservable.swift
│ │ ├── Deletable.swift
│ │ ├── Fetchable.swift
│ │ ├── Fileable.swift
│ │ ├── Objectable.swift
│ │ ├── ParseCloudable+async.swift
│ │ ├── ParseCloudable+combine.swift
│ │ ├── ParseCloudable.swift
│ │ ├── ParseEncodable.swift
│ │ ├── ParseFileTransferable.swift
│ │ ├── ParseHookFunctionable+async.swift
│ │ ├── ParseHookFunctionable+combine.swift
│ │ ├── ParseHookFunctionable.swift
│ │ ├── ParseHookParametable.swift
│ │ ├── ParseHookRequestable+async.swift
│ │ ├── ParseHookRequestable+combine.swift
│ │ ├── ParseHookRequestable.swift
│ │ ├── ParseHookTriggerable+async.swift
│ │ ├── ParseHookTriggerable+combine.swift
│ │ ├── ParseHookTriggerable.swift
│ │ ├── ParseHookable.swift
│ │ ├── ParsePushApplePayloadable.swift
│ │ ├── ParsePushFirebasePayloadable.swift
│ │ ├── ParsePushPayloadable.swift
│ │ ├── ParseQueryScorable.swift
│ │ ├── ParseTypeable.swift
│ │ ├── QueryObservable.swift
│ │ ├── Queryable.swift
│ │ └── Savable.swift
│ ├── Storage/
│ │ ├── KeychainStore.swift
│ │ ├── ParseFileManager.swift
│ │ ├── ParseKeyValueStore.swift
│ │ ├── ParseStorage.swift
│ │ └── SecureStorage.swift
│ └── Types/
│ ├── CloudViewModel.swift
│ ├── Parse.h
│ ├── ParseACL.swift
│ ├── ParseAnalytics+async.swift
│ ├── ParseAnalytics+combine.swift
│ ├── ParseAnalytics.swift
│ ├── ParseBytes.swift
│ ├── ParseCLP.swift
│ ├── ParseConfig+async.swift
│ ├── ParseConfig+combine.swift
│ ├── ParseConfig.swift
│ ├── ParseConfiguration.swift
│ ├── ParseError.swift
│ ├── ParseField.swift
│ ├── ParseFieldOptions.swift
│ ├── ParseFile+async.swift
│ ├── ParseFile+combine.swift
│ ├── ParseFile.swift
│ ├── ParseFileDefaultTransfer.swift
│ ├── ParseGeoPoint.swift
│ ├── ParseHealth+async.swift
│ ├── ParseHealth+combine.swift
│ ├── ParseHealth.swift
│ ├── ParseHookFunctionRequest.swift
│ ├── ParseHookResponse.swift
│ ├── ParseHookTriggerRequest.swift
│ ├── ParseKeychainAccessGroup.swift
│ ├── ParseOperation+async.swift
│ ├── ParseOperation+combine.swift
│ ├── ParseOperation.swift
│ ├── ParsePolygon.swift
│ ├── ParsePush+async.swift
│ ├── ParsePush+combine.swift
│ ├── ParsePush.swift
│ ├── ParsePushPayload/
│ │ ├── Apple/
│ │ │ ├── ParsePushAppleAlert.swift
│ │ │ ├── ParsePushAppleSound.swift
│ │ │ └── ParsePushPayloadApple.swift
│ │ ├── Firebase/
│ │ │ ├── ParsePushFirebaseNotification.swift
│ │ │ └── ParsePushPayloadFirebase.swift
│ │ └── ParsePushPayloadAny.swift
│ ├── ParsePushStatus.swift
│ ├── ParseRelation.swift
│ ├── ParseSchema+async.swift
│ ├── ParseSchema+combine.swift
│ ├── ParseSchema.swift
│ ├── ParseVersion.swift
│ ├── Pointer+async.swift
│ ├── Pointer+combine.swift
│ ├── Pointer.swift
│ ├── Query+async.swift
│ ├── Query+combine.swift
│ ├── Query.swift
│ ├── QueryConstraint.swift
│ ├── QueryViewModel.swift
│ └── QueryWhere.swift
├── TestHost/
│ ├── AppDelegate.swift
│ ├── Assets.xcassets/
│ │ └── AppIcon.appiconset/
│ │ └── Contents.json
│ ├── Base.lproj/
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ └── Info.plist
├── TestHostTV/
│ ├── AppDelegate.swift
│ ├── Assets.xcassets/
│ │ ├── AccentColor.colorset/
│ │ │ └── Contents.json
│ │ ├── App Icon & Top Shelf Image.brandassets/
│ │ │ ├── App Icon - App Store.imagestack/
│ │ │ │ ├── Back.imagestacklayer/
│ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Contents.json
│ │ │ │ ├── Front.imagestacklayer/
│ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Middle.imagestacklayer/
│ │ │ │ ├── Content.imageset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ ├── App Icon.imagestack/
│ │ │ │ ├── Back.imagestacklayer/
│ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Contents.json
│ │ │ │ ├── Contents.json
│ │ │ │ ├── Front.imagestacklayer/
│ │ │ │ │ ├── Content.imageset/
│ │ │ │ │ │ └── Contents.json
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Middle.imagestacklayer/
│ │ │ │ ├── Content.imageset/
│ │ │ │ │ └── Contents.json
│ │ │ │ └── Contents.json
│ │ │ ├── Contents.json
│ │ │ ├── Top Shelf Image Wide.imageset/
│ │ │ │ └── Contents.json
│ │ │ └── Top Shelf Image.imageset/
│ │ │ └── Contents.json
│ │ └── Contents.json
│ ├── Base.lproj/
│ │ ├── LaunchScreen.storyboard
│ │ └── Main.storyboard
│ ├── Info.plist
│ └── ViewController.swift
└── Tests/
├── LinuxMain.swift
└── ParseSwiftTests/
├── APICommandTests.swift
├── AnyCodableTests/
│ ├── AnyCodableTests.swift
│ ├── AnyDecodableTests.swift
│ └── AnyEncodableTests.swift
├── BatchUtilsTests.swift
├── ExtensionsTests.swift
├── IOS13Tests.swift
├── Info.plist
├── InitializeSDKTests.swift
├── KeychainStoreTests.swift
├── MigrateObjCSDKCombineTests.swift
├── MigrateObjCSDKTests.swift
├── NetworkMocking/
│ ├── MockURLProtocol.swift
│ └── MockURLResponse.swift
├── ParseACLTests.swift
├── ParseAnalyticsAsyncTests.swift
├── ParseAnalyticsCombineTests.swift
├── ParseAnalyticsTests.swift
├── ParseAnonymousAsyncTests.swift
├── ParseAnonymousCombineTests.swift
├── ParseAnonymousTests.swift
├── ParseAppleAsyncTests.swift
├── ParseAppleCombineTests.swift
├── ParseAppleTests.swift
├── ParseAuthenticationAsyncTests.swift
├── ParseAuthenticationCombineTests.swift
├── ParseAuthenticationTests.swift
├── ParseBytesTests.swift
├── ParseCLPTests.swift
├── ParseCloudViewModelTests.swift
├── ParseCloudableAsyncTests.swift
├── ParseCloudableCombineTests.swift
├── ParseCloudableTests.swift
├── ParseConfigAsyncTests.swift
├── ParseConfigCombineTests.swift
├── ParseConfigTests.swift
├── ParseEncoderTests/
│ ├── ParseEncoderExtraTests.swift
│ └── TestParseEncoder.swift
├── ParseErrorTests.swift
├── ParseFacebookAsyncTests.swift
├── ParseFacebookCombineTests.swift
├── ParseFacebookTests.swift
├── ParseFileAsyncTests.swift
├── ParseFileCombineTests.swift
├── ParseFileManagerTests.swift
├── ParseFileTests.swift
├── ParseFileTransferableTests.swift
├── ParseGeoPointTests.swift
├── ParseGitHubCombineTests.swift
├── ParseGitHubTests.swift
├── ParseGoogleCombineTests.swift
├── ParseGoogleTests.swift
├── ParseHealthAsyncTests.swift
├── ParseHealthCombineTests.swift
├── ParseHealthTests.swift
├── ParseHookFunctionCombineTests.swift
├── ParseHookFunctionRequestCombineTests.swift
├── ParseHookFunctionRequestTests.swift
├── ParseHookFunctionTests.swift
├── ParseHookResponseTests.swift
├── ParseHookTriggerCombineTests.swift
├── ParseHookTriggerRequestCombineTests.swift
├── ParseHookTriggerRequestTests.swift
├── ParseHookTriggerTests.swift
├── ParseInstagramAsyncTests.swift
├── ParseInstagramCombineTests.swift
├── ParseInstagramTests.swift
├── ParseInstallationAsyncTests.swift
├── ParseInstallationCombineTests.swift
├── ParseInstallationTests.swift
├── ParseKeychainAccessGroupTests.swift
├── ParseLDAPAsyncTests.swift
├── ParseLDAPCombineTests.swift
├── ParseLDAPTests.swift
├── ParseLinkedInCombineTests.swift
├── ParseLinkedInTests.swift
├── ParseLiveQueryAsyncTests.swift
├── ParseLiveQueryCombineTests.swift
├── ParseLiveQueryTests.swift
├── ParseObjectAsyncTests.swift
├── ParseObjectBatchTests.swift
├── ParseObjectCombineTests.swift
├── ParseObjectCustomObjectIdTests.swift
├── ParseObjectTests.swift
├── ParseOperationAsyncTests.swift
├── ParseOperationCombineTests.swift
├── ParseOperationTests.swift
├── ParsePointerAsyncTests.swift
├── ParsePointerCombineTests.swift
├── ParsePointerTests.swift
├── ParsePolygonTests.swift
├── ParsePushAsyncTests.swift
├── ParsePushCombineTests.swift
├── ParsePushPayloadAnyTests.swift
├── ParsePushPayloadAppleTests.swift
├── ParsePushPayloadFirebaseTests.swift
├── ParsePushTests.swift
├── ParseQueryAsyncTests.swift
├── ParseQueryCacheTests.swift
├── ParseQueryCombineTests.swift
├── ParseQueryTests.swift
├── ParseQueryViewModelTests.swift
├── ParseRelationTests.swift
├── ParseRoleTests.swift
├── ParseSchemaAsyncTests.swift
├── ParseSchemaCombineTests.swift
├── ParseSchemaTests.swift
├── ParseSessionTests.swift
├── ParseSpotifyAsyncTests.swift
├── ParseSpotifyCombineTests.swift
├── ParseSpotifyTests.swift
├── ParseTwitterAsyncTests.swift
├── ParseTwitterCombineTests.swift
├── ParseTwitterTests.swift
├── ParseUserAsyncTests.swift
├── ParseUserCombineTests.swift
├── ParseUserTests.swift
└── ParseVersionTests.swift
Condensed preview — 401 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (4,715K chars).
[
{
"path": ".codecov.yml",
"chars": 243,
"preview": "coverage:\n ignore:\n - Tests/ParseSwiftTests/.*\n - TestHost/*\n - TestHostTV/*\n status:\n patch:\n defaul"
},
{
"path": ".github/ISSUE_TEMPLATE/---1-report-an-issue.md",
"chars": 1902,
"preview": "---\nname: \"\\U0001F41B Report an issue\"\nabout: A feature is not working as expected.\ntitle: ''\nlabels: ''\nassignees: ''\n\n"
},
{
"path": ".github/ISSUE_TEMPLATE/---2-feature-request.md",
"chars": 1246,
"preview": "---\nname: \"\\U0001F4A1 Request a feature\"\nabout: Suggest new functionality or an enhancement of existing functionality.\nt"
},
{
"path": ".github/ISSUE_TEMPLATE/config.yml",
"chars": 357,
"preview": "blank_issues_enabled: false\ncontact_links:\n - name: 🙋🏽♀️ Getting help with code\n url: https://stackoverflow.com/que"
},
{
"path": ".github/pull_request_template.md",
"chars": 897,
"preview": "### New Pull Request Checklist\n<!--\n Please check the following boxes [x] before submitting your issue.\n Click the"
},
{
"path": ".github/workflows/ci.yml",
"chars": 9838,
"preview": "name: ci\non:\n push:\n branches: [ main ]\n pull_request:\n branches: '*'\nenv:\n CI_XCODE_OLDEST: '/Applications/Xco"
},
{
"path": ".github/workflows/release.yml",
"chars": 1440,
"preview": "name: release\non:\n release:\n types: [published]\nenv:\n CI_XCODE_13: '/Applications/Xcode_13.4.1.app/Contents/Develop"
},
{
"path": ".gitignore",
"chars": 1473,
"preview": "# Xcode\n#\n# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore\n\n"
},
{
"path": ".spi.yml",
"chars": 384,
"preview": "version: 1\nbuilder:\n configs:\n - platform: ios\n scheme: \"ParseSwift (iOS)\"\n - platform: macos-spm\n documentatio"
},
{
"path": ".swiftlint.yml",
"chars": 334,
"preview": "disabled_rules:\n - file_length\n - cyclomatic_complexity\n - function_body_length\n - type_body_length\n - inclusive_la"
},
{
"path": "CHANGELOG.md",
"chars": 68923,
"preview": "# Parse-Swift Changelog\n\n### main\n[Full Changelog](https://github.com/parse-community/Parse-Swift/compare/4.14.2...main)"
},
{
"path": "CONTRIBUTING.md",
"chars": 8594,
"preview": "# Contributing to the ParseSwift SDK <!-- omit in toc -->\n\n## Table of Contents <!-- omit in toc -->\n- [Contributing](#c"
},
{
"path": "LICENSE",
"chars": 1072,
"preview": "MIT License\n\nCopyright (c) 2021 Parse Community\n\nPermission is hereby granted, free of charge, to any person obtaining a"
},
{
"path": "MIGRATION.md",
"chars": 6594,
"preview": "# Migration from Parse ObjC SDK <!-- omit in toc -->\n\nThis document describes how to migrate from the [Parse ObjC SDK](h"
},
{
"path": "Package.swift",
"chars": 610,
"preview": "// swift-tools-version:5.5\n\nimport PackageDescription\n\nlet package = Package(\n name: \"ParseSwift\",\n platforms: [.i"
},
{
"path": "Package@5.1.swift",
"chars": 610,
"preview": "// swift-tools-version:5.1\n\nimport PackageDescription\n\nlet package = Package(\n name: \"ParseSwift\",\n platforms: [.i"
},
{
"path": "Parse.xcworkspace/contents.xcworkspacedata",
"chars": 160,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"container:ParseSwift"
},
{
"path": "Parse.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ParseSwift-iOS/Info.plist",
"chars": 852,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ParseSwift-macOS/Info.plist",
"chars": 901,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ParseSwift-tvOS/Info.plist",
"chars": 769,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ParseSwift-tvOS/ParseSwift_tvOS.h",
"chars": 551,
"preview": "//\n// ParseSwift_tvOS.h\n// ParseSwift-tvOS\n//\n// Created by Corey Baker on 7/30/20.\n// Copyright © 2020 Parse Commun"
},
{
"path": "ParseSwift-watchOS/Info.plist",
"chars": 769,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ParseSwift-watchOS/ParseSwift_watchOS.h",
"chars": 572,
"preview": "//\n// ParseSwift_watchOS.h\n// ParseSwift-watchOS\n//\n// Created by Corey Baker on 7/30/20.\n// Copyright © 2020 Parse "
},
{
"path": "ParseSwift.playground/Pages/1 - Your first Object.xcplaygroundpage/Contents.swift",
"chars": 12417,
"preview": "//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//: `My Mac` or whatever the n"
},
{
"path": "ParseSwift.playground/Pages/10 - Cloud Code.xcplaygroundpage/Contents.swift",
"chars": 5837,
"preview": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//:"
},
{
"path": "ParseSwift.playground/Pages/11 - LiveQuery.xcplaygroundpage/Contents.swift",
"chars": 7696,
"preview": "//: [Previous](@previous)\n\nimport PlaygroundSupport\nimport Foundation\nimport ParseSwift\nimport SwiftUI\n\nPlaygroundPage.c"
},
{
"path": "ParseSwift.playground/Pages/12 - Roles and Relations.xcplaygroundpage/Contents.swift",
"chars": 11907,
"preview": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//:"
},
{
"path": "ParseSwift.playground/Pages/13 - Operations.xcplaygroundpage/Contents.swift",
"chars": 4796,
"preview": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//:"
},
{
"path": "ParseSwift.playground/Pages/14 - Config.xcplaygroundpage/Contents.swift",
"chars": 2323,
"preview": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//:"
},
{
"path": "ParseSwift.playground/Pages/15 - Custom ObjectId.xcplaygroundpage/Contents.swift",
"chars": 4529,
"preview": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//:"
},
{
"path": "ParseSwift.playground/Pages/16 - Analytics.xcplaygroundpage/Contents.swift",
"chars": 1415,
"preview": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//:"
},
{
"path": "ParseSwift.playground/Pages/17 - SwiftUI - Finding Objects.xcplaygroundpage/Contents.swift",
"chars": 5027,
"preview": "//: [Previous](@previous)\n\n//: If you are using Xcode 13+, ignore the comments below:\n//: For this page, make sure your "
},
{
"path": "ParseSwift.playground/Pages/18 - SwiftUI - Finding Objects With Custom ViewModel.xcplaygroundpage/Contents.swift",
"chars": 4009,
"preview": "//: [Previous](@previous)\n\n//: If you are using Xcode 13+, ignore the comments below:\n//: For this page, make sure your "
},
{
"path": "ParseSwift.playground/Pages/19 - SwiftUI - LiveQuery.xcplaygroundpage/Contents.swift",
"chars": 4082,
"preview": "//: [Previous](@previous)\n\n//: If you are using Xcode 13+, ignore the comments below:\n//: For this page, make sure your "
},
{
"path": "ParseSwift.playground/Pages/2 - Finding Objects.xcplaygroundpage/Contents.swift",
"chars": 6382,
"preview": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//:"
},
{
"path": "ParseSwift.playground/Pages/20 - Cloud Schemas.xcplaygroundpage/Contents.swift",
"chars": 8456,
"preview": "//: [Previous](@previous)\n\n/*:\n The code in this Playground is intended to run at the\n server level only. It is not inte"
},
{
"path": "ParseSwift.playground/Pages/21 - Cloud Push Notifications.xcplaygroundpage/Contents.swift",
"chars": 5605,
"preview": "//: [Previous](@previous)\n\n/*:\n The code in this Playground is intended to run at the\n server level only. It is not inte"
},
{
"path": "ParseSwift.playground/Pages/22 - Cloud Hook Functions.xcplaygroundpage/Contents.swift",
"chars": 2612,
"preview": "//: [Previous](@previous)\n\n/*:\n The code in this Playground is intended to run at the\n server level only. It is not inte"
},
{
"path": "ParseSwift.playground/Pages/23 - Cloud Hook Triggers.xcplaygroundpage/Contents.swift",
"chars": 3697,
"preview": "//: [Previous](@previous)\n\n/*:\n The code in this Playground is intended to run at the\n server level only. It is not inte"
},
{
"path": "ParseSwift.playground/Pages/3 - User - Sign Up.xcplaygroundpage/Contents.swift",
"chars": 2836,
"preview": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//:"
},
{
"path": "ParseSwift.playground/Pages/4 - User - Continued.xcplaygroundpage/Contents.swift",
"chars": 8292,
"preview": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//:"
},
{
"path": "ParseSwift.playground/Pages/5 - ACL.xcplaygroundpage/Contents.swift",
"chars": 2464,
"preview": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//:"
},
{
"path": "ParseSwift.playground/Pages/6 - Installation.xcplaygroundpage/Contents.swift",
"chars": 3469,
"preview": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//:"
},
{
"path": "ParseSwift.playground/Pages/7 - GeoPoint.xcplaygroundpage/Contents.swift",
"chars": 9956,
"preview": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//:"
},
{
"path": "ParseSwift.playground/Pages/8 - Pointers.xcplaygroundpage/Contents.swift",
"chars": 12000,
"preview": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//:"
},
{
"path": "ParseSwift.playground/Pages/9 - Files.xcplaygroundpage/Contents.swift",
"chars": 6913,
"preview": "//: [Previous](@previous)\n\n//: For this page, make sure your build target is set to ParseSwift (macOS) and targeting\n//:"
},
{
"path": "ParseSwift.playground/Sources/Common.swift",
"chars": 524,
"preview": "import Foundation\nimport ParseSwift\n\npublic func initializeParse(customObjectId: Bool = false) {\n ParseSwift.initiali"
},
{
"path": "ParseSwift.playground/contents.xcplayground",
"chars": 1212,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n<playground version='6.0' target-platform='macos' display-mode='"
},
{
"path": "ParseSwift.podtemplate",
"chars": 1742,
"preview": "Pod::Spec.new do |s|\n s.name = \"ParseSwift\"\n s.version = \"[[VERSION]]\"\n s.summary = \"Parse Pure Swift SDK\"\n s."
},
{
"path": "ParseSwift.xcodeproj/project.pbxproj",
"chars": 390766,
"preview": "// !$*UTF8*$!\n{\n\tarchiveVersion = 1;\n\tclasses = {\n\t};\n\tobjectVersion = 54;\n\tobjects = {\n\n/* Begin PBXBuildFile section *"
},
{
"path": "ParseSwift.xcodeproj/project.xcworkspace/contents.xcworkspacedata",
"chars": 135,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Workspace\n version = \"1.0\">\n <FileRef\n location = \"self:\">\n </FileRef"
},
{
"path": "ParseSwift.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist",
"chars": 238,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ParseSwift.xcodeproj/xcshareddata/xcschemes/ParseSwift (iOS).xcscheme",
"chars": 3685,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1400\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "ParseSwift.xcodeproj/xcshareddata/xcschemes/ParseSwift (macOS).xcscheme",
"chars": 3323,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1400\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "ParseSwift.xcodeproj/xcshareddata/xcschemes/ParseSwift (tvOS).xcscheme",
"chars": 2939,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1400\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "ParseSwift.xcodeproj/xcshareddata/xcschemes/ParseSwift (watchOS).xcscheme",
"chars": 2453,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1400\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "ParseSwift.xcodeproj/xcshareddata/xcschemes/TestHost.xcscheme",
"chars": 2855,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1400\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "ParseSwift.xcodeproj/xcshareddata/xcschemes/TestHostTV.xcscheme",
"chars": 2867,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<Scheme\n LastUpgradeVersion = \"1400\"\n version = \"1.3\">\n <BuildAction\n "
},
{
"path": "ParseSwiftTestsmacOS/Info.plist",
"chars": 1062,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "ParseSwiftTeststvOS/Info.plist",
"chars": 1062,
"preview": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/P"
},
{
"path": "README.md",
"chars": 12444,
"preview": " 2022, Apple Inc. All rights reserved.\n# \n# Redistribution and use in source and binary for"
},
{
"path": "Scripts/update-gh-pages-documentation-site",
"chars": 3406,
"preview": "#!/bin/bash\n#\n# Copyright (c) 2022, Apple Inc. All rights reserved.\n# \n# Redistribution and use in source and binary for"
},
{
"path": "Scripts/update_build",
"chars": 286,
"preview": "#!/bin/bash\n\n# Prepare podspec update\nTEMPLATE_FILE_NAME=\"ParseSwift.podtemplate\"\nOUT_FILE_NAME=\"ParseSwift.podspec\"\n\n# "
},
{
"path": "Sources/ParseSwift/API/API+BatchCommand.swift",
"chars": 987,
"preview": "//\n// API+BatchCommand.swift\n// ParseSwift\n//\n// Created by Corey Baker on 9/12/21.\n// Copyright © 2021 Parse Commun"
},
{
"path": "Sources/ParseSwift/API/API+Command+async.swift",
"chars": 1590,
"preview": "//\n// API+Command+async.swift\n// ParseSwift\n//\n// Created by Corey Baker on 9/17/22.\n// Copyright © 2022 Parse Commu"
},
{
"path": "Sources/ParseSwift/API/API+Command.swift",
"chars": 28176,
"preview": "//\n// API+Command.swift\n// ParseSwift\n//\n// Created by Florent Vilmart on 17-09-24.\n// Copyright © 2020 Parse Commun"
},
{
"path": "Sources/ParseSwift/API/API+NonParseBodyCommand+async.swift",
"chars": 754,
"preview": "//\n// API+NonParseBodyCommand+async.swift\n// ParseSwift\n//\n// Created by Corey Baker on 9/17/22.\n// Copyright © 2022"
},
{
"path": "Sources/ParseSwift/API/API+NonParseBodyCommand.swift",
"chars": 9112,
"preview": "//\n// API+NonParseBodyCommand.swift\n// ParseSwift\n//\n// Created by Corey Baker on 9/12/21.\n// Copyright © 2021 Parse"
},
{
"path": "Sources/ParseSwift/API/API.swift",
"chars": 9151,
"preview": "//\n// API.swift\n// ParseSwift\n//\n// Created by Florent Vilmart on 17-08-19.\n// Copyright © 2017 Parse. All rights re"
},
{
"path": "Sources/ParseSwift/API/BatchUtils.swift",
"chars": 2221,
"preview": "//\n// RESTBatchCommand.swift\n// ParseSwift\n//\n// Created by Florent Vilmart on 17-08-19.\n// Copyright © 2020 Parse C"
},
{
"path": "Sources/ParseSwift/API/ParseURLSessionDelegate.swift",
"chars": 6653,
"preview": "//\n// ParseURLSessionDelegate.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/4/21.\n// Copyright © 2021 Parse "
},
{
"path": "Sources/ParseSwift/API/Responses.swift",
"chars": 5142,
"preview": "//\n// Responses.swift\n// ParseSwift\n//\n// Created by Florent Vilmart on 17-08-20.\n// Copyright © 2020 Parse Communit"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseApple/ParseApple+async.swift",
"chars": 3455,
"preview": "//\n// ParseApple+async.swift\n// ParseApple+async\n//\n// Created by Corey Baker on 8/7/21.\n// Copyright © 2021 Parse C"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseApple/ParseApple+combine.swift",
"chars": 3422,
"preview": "//\n// ParseApple+combine.swift\n// ParseApple+combine\n//\n// Created by Corey Baker on 8/7/21.\n// Copyright © 2021 Par"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseApple/ParseApple.swift",
"chars": 6987,
"preview": "//\n// ParseApple.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/14/21.\n// Copyright © 2021 Parse Community. A"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseFacebook/ParseFacebook+async.swift",
"chars": 5809,
"preview": "//\n// ParseFacebook+async.swift\n// ParseFacebook+async\n//\n// Created by Corey Baker on 8/7/21.\n// Copyright © 2021 P"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseFacebook/ParseFacebook+combine.swift",
"chars": 5729,
"preview": "//\n// ParseFacebook+combine.swift\n// ParseFacebook+combine\n//\n// Created by Corey Baker on 8/7/21.\n// Copyright © 20"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseFacebook/ParseFacebook.swift",
"chars": 10673,
"preview": "//\n// ParseFacebook.swift\n// ParseSwift\n//\n// Created by Abdulaziz Alhomaidhi on 3/18/21.\n// Copyright © 2021 Parse "
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseGithub/ParseGitHub+async.swift",
"chars": 3323,
"preview": "//\n// ParseGitHub+async.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/1/22.\n// Copyright © 2022 Parse Commun"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseGithub/ParseGitHub+combine.swift",
"chars": 3201,
"preview": "//\n// ParseGitHub+combine.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/1/22.\n// Copyright © 2022 Parse Comm"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseGithub/ParseGitHub.swift",
"chars": 6238,
"preview": "//\n// ParseGitHub.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/1/22.\n// Copyright © 2022 Parse Community. A"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseGoogle/ParseGoogle+async.swift",
"chars": 3625,
"preview": "//\n// ParseGoogle+async.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/1/22.\n// Copyright © 2022 Parse Commun"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseGoogle/ParseGoogle+combine.swift",
"chars": 3521,
"preview": "//\n// ParseGoogle+combine.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/1/22.\n// Copyright © 2022 Parse Comm"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseGoogle/ParseGoogle.swift",
"chars": 6989,
"preview": "//\n// ParseGoogle.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/1/22.\n// Copyright © 2022 Parse Community. A"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseInstagram/ParseInstagram+async.swift",
"chars": 3676,
"preview": "//\n// ParseInstagram+async.swift\n// ParseSwift\n//\n// Created by Ulaş Sancak on 06/19/22.\n// Copyright © 2022 Parse C"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseInstagram/ParseInstagram+combine.swift",
"chars": 3572,
"preview": "//\n// ParseInstagram+combine.swift\n// ParseSwift\n//\n// Created by Ulaş Sancak on 06/19/22.\n// Copyright © 2022 Parse"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseInstagram/ParseInstagram.swift",
"chars": 7047,
"preview": "//\n// ParseInstagram.swift\n// ParseSwift\n//\n// Created by Ulaş Sancak on 06/19/22.\n// Copyright © 2022 Parse Communi"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseLDAP/ParseLDAP+async.swift",
"chars": 3259,
"preview": "//\n// ParseLDAP+async.swift\n// ParseLDAP+async\n//\n// Created by Corey Baker on 8/7/21.\n// Copyright © 2021 Parse Com"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseLDAP/ParseLDAP+combine.swift",
"chars": 3225,
"preview": "//\n// ParseLDAP+combine.swift\n// ParseLDAP+combine\n//\n// Created by Corey Baker on 8/7/21.\n// Copyright © 2021 Parse"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseLDAP/ParseLDAP.swift",
"chars": 5677,
"preview": "//\n// ParseLDAP.swift\n// ParseSwift\n//\n// Created by Corey Baker on 2/14/21.\n// Copyright © 2021 Parse Community. Al"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseLinkedIn/ParseLinkedIn+async.swift",
"chars": 3509,
"preview": "//\n// ParseLinkedIn+async.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/1/22.\n// Copyright © 2022 Parse Comm"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseLinkedIn/ParseLinkedIn+combine.swift",
"chars": 3405,
"preview": "//\n// ParseLinkedIn+combine.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/1/22.\n// Copyright © 2022 Parse Co"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseLinkedIn/ParseLinkedIn.swift",
"chars": 6787,
"preview": "//\n// ParseLinkedIn.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/1/22.\n// Copyright © 2022 Parse Community."
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseSpotify/ParseSpotify+async.swift",
"chars": 3954,
"preview": "//\n// ParseSpotify+async.swift\n// ParseSwift\n//\n// Created by Ulaş Sancak on 06/20/22.\n// Copyright © 2022 Parse Com"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseSpotify/ParseSpotify+combine.swift",
"chars": 3868,
"preview": "//\n// ParseSpotify+combine.swift\n// ParseSwift\n//\n// Created by Ulaş Sancak on 06/20/22.\n// Copyright © 2022 Parse C"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseSpotify/ParseSpotify.swift",
"chars": 7910,
"preview": "//\n// ParseSpotify.swift\n// ParseSwift\n//\n// Created by Ulaş Sancak on 06/20/22.\n// Copyright © 2022 Parse Community"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseTwitter/ParseTwitter+async.swift",
"chars": 4687,
"preview": "//\n// ParseTwitter+async.swift\n// ParseTwitter+async\n//\n// Created by Corey Baker on 8/7/21.\n// Copyright © 2021 Par"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseTwitter/ParseTwitter+combine.swift",
"chars": 4726,
"preview": "//\n// ParseTwitter+combine.swift\n// ParseTwitter+combine\n//\n// Created by Corey Baker on 8/7/21.\n// Copyright © 2021"
},
{
"path": "Sources/ParseSwift/Authentication/3rd Party/ParseTwitter/ParseTwitter.swift",
"chars": 9480,
"preview": "//\n// ParseTwitter.swift\n// ParseSwift\n//\n// Created by Abdulaziz Alhomaidhi on 3/17/21.\n// Copyright © 2021 Parse C"
},
{
"path": "Sources/ParseSwift/Authentication/Internal/ParseAnonymous+async.swift",
"chars": 1986,
"preview": "//\n// ParseAnonymous+async.swift\n// ParseAnonymous+async\n//\n// Created by Corey Baker on 8/7/21.\n// Copyright © 2021"
},
{
"path": "Sources/ParseSwift/Authentication/Internal/ParseAnonymous+combine.swift",
"chars": 1981,
"preview": "//\n// ParseAnonymous+combine.swift\n// ParseAnonymous+combine\n//\n// Created by Corey Baker on 8/7/21.\n// Copyright © "
},
{
"path": "Sources/ParseSwift/Authentication/Internal/ParseAnonymous.swift",
"chars": 5282,
"preview": "//\n// ParseAnonymous.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/14/21.\n// Copyright © 2021 Parse Communit"
},
{
"path": "Sources/ParseSwift/Authentication/Protocols/ParseAuthentication+async.swift",
"chars": 3649,
"preview": "//\n// ParseAuthentication+async.swift\n// ParseAuthentication+async\n//\n// Created by Corey Baker on 8/7/21.\n// Copyri"
},
{
"path": "Sources/ParseSwift/Authentication/Protocols/ParseAuthentication+combine.swift",
"chars": 3679,
"preview": "//\n// ParseAuthentication+combine.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/30/21.\n// Copyright © 2021 P"
},
{
"path": "Sources/ParseSwift/Authentication/Protocols/ParseAuthentication.swift",
"chars": 22875,
"preview": "//\n// ParseAuthentication.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/14/21.\n// Copyright © 2021 Parse Com"
},
{
"path": "Sources/ParseSwift/Coding/AnyCodable.swift",
"chars": 3654,
"preview": "import Foundation\n\n/**\n A type-erased `Codable` value.\n \n The `AnyCodable` type forwards encoding and decoding responsib"
},
{
"path": "Sources/ParseSwift/Coding/AnyDecodable.swift",
"chars": 4562,
"preview": "import Foundation\n\n/**\n A type-erased `Decodable` value.\n \n The `AnyDecodable` type forwards decoding responsibilities\n "
},
{
"path": "Sources/ParseSwift/Coding/AnyEncodable.swift",
"chars": 8621,
"preview": "import Foundation\n\n/**\n A type-erased `Encodable` value.\n \n The `AnyEncodable` type forwards encoding responsibilities\n "
},
{
"path": "Sources/ParseSwift/Coding/ParseCoding.swift",
"chars": 4673,
"preview": "//\n// ParseCoding.swift\n// ParseSwift\n//\n// Created by Florent Vilmart on 17-07-24.\n// Copyright © 2017 Parse. All r"
},
{
"path": "Sources/ParseSwift/Coding/ParseEncoder.swift",
"chars": 52824,
"preview": "//\n// ParseEncoder.swift\n// ParseSwift\n//\n// Created by Pranjal Satija on 7/20/20.\n// Copyright © 2020 Parse. All ri"
},
{
"path": "Sources/ParseSwift/Documentation.docc/ParseSwift.md",
"chars": 3488,
"preview": "# ``ParseSwift``\nA pure Swift library that gives you access to the powerful Parse Server backend from your Swift applica"
},
{
"path": "Sources/ParseSwift/Documentation.docc/ParseSwift.tutorial",
"chars": 288,
"preview": "@Tutorials(name: \"ParseSwift\") {\n @Intro(title: \"Welcome to ParseSwift\") {\n \n }\n \n @Chapter(name: \"Yo"
},
{
"path": "Sources/ParseSwift/Documentation.docc/Your First Object.tutorial",
"chars": 251,
"preview": "@Tutorial(time: 1) {\n @Intro(title: \"Your First Object\") {\n \n }\n \n @Section(title: \"Check server heal"
},
{
"path": "Sources/ParseSwift/Extensions/Data.swift",
"chars": 1517,
"preview": "//\n// Data.swift\n// ParseSwift\n//\n// Created by Corey Baker on 2/14/21.\n// Copyright © 2021 Parse Community. All rig"
},
{
"path": "Sources/ParseSwift/Extensions/Date.swift",
"chars": 396,
"preview": "//\n// Date.swift\n// ParseSwift\n//\n// Created by Corey Baker on 11/4/21.\n// Copyright © 2021 Parse Community. All rig"
},
{
"path": "Sources/ParseSwift/Extensions/Dictionary.swift",
"chars": 422,
"preview": "//\n// Dictionary.swift\n// ParseSwift\n//\n// Created by Corey Baker on 7/14/22.\n// Copyright © 2022 Parse Community. A"
},
{
"path": "Sources/ParseSwift/Extensions/Encodable.swift",
"chars": 647,
"preview": "//\n// Encodable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 11/4/21.\n// Copyright © 2021 Parse Community. Al"
},
{
"path": "Sources/ParseSwift/Extensions/URLCache.swift",
"chars": 1280,
"preview": "//\n// URLCache.swift\n// ParseSwift\n//\n// Created by Corey Baker on 7/17/21.\n// Copyright © 2021 Parse Community. All"
},
{
"path": "Sources/ParseSwift/Extensions/URLSession.swift",
"chars": 15861,
"preview": "//\n// URLSession.swift\n// ParseSwift\n//\n// Original file, URLSession+sync.swift, created by Florent Vilmart on 17-09-"
},
{
"path": "Sources/ParseSwift/InternalObjects/BaseConfig.swift",
"chars": 197,
"preview": "//\n// BaseConfig.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/22/21.\n// Copyright © 2021 Parse Community. A"
},
{
"path": "Sources/ParseSwift/InternalObjects/BaseParseInstallation.swift",
"chars": 1231,
"preview": "//\n// BaseParseInstallation.swift\n// ParseSwift\n//\n// Created by Corey Baker on 9/7/20.\n// Copyright © 2020 Parse Co"
},
{
"path": "Sources/ParseSwift/InternalObjects/BaseParseUser.swift",
"chars": 493,
"preview": "//\n// BaseParseUser.swift\n// \n//\n// Created by Pranjal Satija on 7/19/20.\n//\n\nimport Foundation\n\n/// Used internally "
},
{
"path": "Sources/ParseSwift/InternalObjects/NoBody.swift",
"chars": 188,
"preview": "//\n// NoBody.swift\n// ParseSwift\n//\n// Created by Florent Vilmart on 17-07-24.\n// Copyright © 2020 Parse. All rights"
},
{
"path": "Sources/ParseSwift/LiveQuery/LiveQueryConstants.swift",
"chars": 2031,
"preview": "//\n// LiveQueryConstants.swift\n// ParseSwift\n//\n// Created by Corey Baker on 11/3/21.\n// Copyright © 2021 Parse Comm"
},
{
"path": "Sources/ParseSwift/LiveQuery/LiveQuerySocket.swift",
"chars": 5907,
"preview": "//\n// LiveQuerySocket.swift\n// ParseSwift\n//\n// Created by Corey Baker on 12/31/20.\n// Copyright © 2020 Parse Commun"
},
{
"path": "Sources/ParseSwift/LiveQuery/Messages.swift",
"chars": 3507,
"preview": "//\n// Messages.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/2/21.\n// Copyright © 2021 Parse Community. All "
},
{
"path": "Sources/ParseSwift/LiveQuery/Operations.swift",
"chars": 705,
"preview": "//\n// Operations.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/2/21.\n// Copyright © 2021 Parse Community. Al"
},
{
"path": "Sources/ParseSwift/LiveQuery/ParseLiveQuery+async.swift",
"chars": 1697,
"preview": "//\n// ParseLiveQuery+async.swift\n// ParseLiveQuery+async\n//\n// Created by Corey Baker on 8/6/21.\n// Copyright © 2021"
},
{
"path": "Sources/ParseSwift/LiveQuery/ParseLiveQuery+combine.swift",
"chars": 1557,
"preview": "//\n// ParseLiveQuery+combine.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/24/21.\n// Copyright © 2021 Parse "
},
{
"path": "Sources/ParseSwift/LiveQuery/ParseLiveQuery.swift",
"chars": 40350,
"preview": "//\n// ParseLiveQuery.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/2/21.\n// Copyright © 2021 Parse Community"
},
{
"path": "Sources/ParseSwift/LiveQuery/ParseLiveQueryConstants.swift",
"chars": 250,
"preview": "//\n// ParseLiveQueryConstants.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/9/21.\n// Copyright © 2021 Parse "
},
{
"path": "Sources/ParseSwift/LiveQuery/Protocols/LiveQuerySocketDelegate.swift",
"chars": 957,
"preview": "//\n// LiveQuerySocketDelegate.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/4/21.\n// Copyright © 2021 Parse "
},
{
"path": "Sources/ParseSwift/LiveQuery/Protocols/LiveQueryable.swift",
"chars": 191,
"preview": "//\n// LiveQueryable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/2/21.\n// Copyright © 2021 Parse Community."
},
{
"path": "Sources/ParseSwift/LiveQuery/Protocols/ParseLiveQueryDelegate.swift",
"chars": 3793,
"preview": "//\n// ParseLiveQueryDelegate.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/4/21.\n// Copyright © 2021 Parse C"
},
{
"path": "Sources/ParseSwift/LiveQuery/Protocols/QuerySubscribable.swift",
"chars": 1440,
"preview": "//\n// QuerySubscribable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/2/21.\n// Copyright © 2021 Parse Commun"
},
{
"path": "Sources/ParseSwift/LiveQuery/Subscription.swift",
"chars": 2731,
"preview": "//\n// Subscription.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/2/21.\n// Copyright © 2021 Parse Community. "
},
{
"path": "Sources/ParseSwift/LiveQuery/SubscriptionCallback.swift",
"chars": 3932,
"preview": "//\n// SubscriptionCallback.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/24/21.\n// Copyright © 2021 Parse Co"
},
{
"path": "Sources/ParseSwift/Objects/ParseCloudUser.swift",
"chars": 389,
"preview": "//\n// ParseCloudUser.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/14/22.\n// Copyright © 2022 Parse Communit"
},
{
"path": "Sources/ParseSwift/Objects/ParseInstallation+async.swift",
"chars": 27602,
"preview": "//\n// ParseInstallation+async.swift\n// ParseInstallation+async\n//\n// Created by Corey Baker on 8/6/21.\n// Copyright "
},
{
"path": "Sources/ParseSwift/Objects/ParseInstallation+combine.swift",
"chars": 21540,
"preview": "//\n// ParseInstallation+combine.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/29/21.\n// Copyright © 2021 Par"
},
{
"path": "Sources/ParseSwift/Objects/ParseInstallation.swift",
"chars": 89392,
"preview": "//\n// ParseInstallation.swift\n// ParseSwift\n//\n// Created by Corey Baker on 9/6/20.\n// Copyright © 2020 Parse Commun"
},
{
"path": "Sources/ParseSwift/Objects/ParseObject+async.swift",
"chars": 25200,
"preview": "//\n// ParseObject+async.swift\n// ParseObject+async\n//\n// Created by Corey Baker on 8/6/21.\n// Copyright © 2021 Parse"
},
{
"path": "Sources/ParseSwift/Objects/ParseObject+combine.swift",
"chars": 15255,
"preview": "//\n// ParseObject+combine.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/29/21.\n// Copyright © 2021 Parse Com"
},
{
"path": "Sources/ParseSwift/Objects/ParseObject.swift",
"chars": 77785,
"preview": "//\n// ParseObject.swift\n// ParseSwift\n//\n// Created by Florent Vilmart on 17-07-24.\n// Copyright © 2020 Parse. All r"
},
{
"path": "Sources/ParseSwift/Objects/ParsePushStatusable.swift",
"chars": 2359,
"preview": "//\n// ParsePushStatus.swift\n// ParseSwift\n//\n// Created by Corey Baker on 5/30/22.\n// Copyright © 2022 Parse Communi"
},
{
"path": "Sources/ParseSwift/Objects/ParseRole.swift",
"chars": 5446,
"preview": "//\n// ParseRole.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/17/21.\n// Copyright © 2021 Parse Community. Al"
},
{
"path": "Sources/ParseSwift/Objects/ParseSession.swift",
"chars": 1378,
"preview": "//\n// ParseSession.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/17/21.\n// Copyright © 2021 Parse Community."
},
{
"path": "Sources/ParseSwift/Objects/ParseUser+async.swift",
"chars": 33388,
"preview": "//\n// ParseUser+async.swift\n// ParseUser+async\n//\n// Created by Corey Baker on 8/6/21.\n// Copyright © 2021 Parse Com"
},
{
"path": "Sources/ParseSwift/Objects/ParseUser+combine.swift",
"chars": 27584,
"preview": "//\n// ParseUser+publisher.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/28/21.\n// Copyright © 2021 Parse Com"
},
{
"path": "Sources/ParseSwift/Objects/ParseUser.swift",
"chars": 102945,
"preview": "import Foundation\n\n/**\n Objects that conform to the `ParseUser` protocol have a local representation of a user persisted"
},
{
"path": "Sources/ParseSwift/Operations/Add.swift",
"chars": 297,
"preview": "//\n// Add.swift\n// Parse\n//\n// Created by Florent Vilmart on 17-07-24.\n// Copyright © 2017 Parse. All rights reserve"
},
{
"path": "Sources/ParseSwift/Operations/AddRelation.swift",
"chars": 450,
"preview": "//\n// AddRelation.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/17/21.\n// Copyright © 2021 Parse Community. "
},
{
"path": "Sources/ParseSwift/Operations/AddUnique.swift",
"chars": 315,
"preview": "//\n// AddUnique.swift\n// Parse\n//\n// Created by Florent Vilmart on 17-07-24.\n// Copyright © 2017 Parse. All rights r"
},
{
"path": "Sources/ParseSwift/Operations/Delete.swift",
"chars": 263,
"preview": "//\n// Delete.swift\n// Parse\n//\n// Created by Florent Vilmart on 17-07-24.\n// Copyright © 2017 Parse. All rights rese"
},
{
"path": "Sources/ParseSwift/Operations/Increment.swift",
"chars": 301,
"preview": "//\n// IncrementOperation.swift\n// Parse\n//\n// Created by Florent Vilmart on 17-07-24.\n// Copyright © 2017 Parse. All"
},
{
"path": "Sources/ParseSwift/Operations/Operation.swift",
"chars": 419,
"preview": "//\n// Operation.swift\n// ParseSwift\n//\n// Created by Corey Baker on 5/21/22.\n// Copyright © 2022 Parse Community. Al"
},
{
"path": "Sources/ParseSwift/Operations/Remove.swift",
"chars": 306,
"preview": "//\n// Remove.swift\n// Parse\n//\n// Created by Florent Vilmart on 17-07-24.\n// Copyright © 2017 Parse. All rights rese"
},
{
"path": "Sources/ParseSwift/Operations/RemoveRelation.swift",
"chars": 459,
"preview": "//\n// RemoveRelation.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/17/21.\n// Copyright © 2021 Parse Communit"
},
{
"path": "Sources/ParseSwift/Parse.h",
"chars": 474,
"preview": "//\n// Parse.h\n// Parse\n//\n// Created by Florent Vilmart on 17-07-23.\n// Copyright © 2017 Parse. All rights reserved."
},
{
"path": "Sources/ParseSwift/Parse.swift",
"chars": 32012,
"preview": "import Foundation\n#if canImport(FoundationNetworking)\nimport FoundationNetworking\n#endif\n\n// swiftlint:disable line_leng"
},
{
"path": "Sources/ParseSwift/ParseConstants.swift",
"chars": 2101,
"preview": "//\n// ParseConstants.swift\n// ParseSwift\n//\n// Created by Corey Baker on 9/7/20.\n// Copyright © 2020 Parse Community"
},
{
"path": "Sources/ParseSwift/Protocols/CloudObservable.swift",
"chars": 1255,
"preview": "//\n// CloudObservable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 7/11/21.\n// Copyright © 2021 Parse Communi"
},
{
"path": "Sources/ParseSwift/Protocols/Deletable.swift",
"chars": 430,
"preview": "//\n// Deletable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 9/27/20.\n// Copyright © 2020 Parse Community. Al"
},
{
"path": "Sources/ParseSwift/Protocols/Fetchable.swift",
"chars": 529,
"preview": "//\n// Fetchable.swift\n// ParseSwift\n//\n// Created by Florent Vilmart on 17-07-24.\n// Copyright © 2020 Parse. All rig"
},
{
"path": "Sources/ParseSwift/Protocols/Fileable.swift",
"chars": 796,
"preview": "//\n// Fileable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 12/27/20.\n// Copyright © 2020 Parse Community. Al"
},
{
"path": "Sources/ParseSwift/Protocols/Objectable.swift",
"chars": 2482,
"preview": "//\n// Objectable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 10/4/20.\n// Copyright © 2020 Parse Community. A"
},
{
"path": "Sources/ParseSwift/Protocols/ParseCloudable+async.swift",
"chars": 1404,
"preview": "//\n// ParseCloudable+async.swift\n// ParseCloudable+async\n//\n// Created by Corey Baker on 8/6/21.\n// Copyright © 2021"
},
{
"path": "Sources/ParseSwift/Protocols/ParseCloudable+combine.swift",
"chars": 1405,
"preview": "//\n// ParseCloudable+combine.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/29/21.\n// Copyright © 2021 Parse "
},
{
"path": "Sources/ParseSwift/Protocols/ParseCloudable.swift",
"chars": 4594,
"preview": "//\n// ParseCloudable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 12/29/20.\n// Copyright © 2020 Parse Communi"
},
{
"path": "Sources/ParseSwift/Protocols/ParseEncodable.swift",
"chars": 815,
"preview": "//\n// ParseEncodable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 12/31/20.\n// Copyright © 2020 Parse Communi"
},
{
"path": "Sources/ParseSwift/Protocols/ParseFileTransferable.swift",
"chars": 5127,
"preview": "//\n// ParseFileAdaptable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 9/12/22.\n// Copyright © 2022 Parse Comm"
},
{
"path": "Sources/ParseSwift/Protocols/ParseHookFunctionable+async.swift",
"chars": 4207,
"preview": "//\n// ParseHookFunctionable+async.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/19/22.\n// Copyright © 2022 P"
},
{
"path": "Sources/ParseSwift/Protocols/ParseHookFunctionable+combine.swift",
"chars": 3817,
"preview": "//\n// ParseHookFunctionable+combine.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/19/22.\n// Copyright © 2022"
},
{
"path": "Sources/ParseSwift/Protocols/ParseHookFunctionable.swift",
"chars": 11866,
"preview": "//\n// ParseHookFunction.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/14/22.\n// Copyright © 2022 Parse Commu"
},
{
"path": "Sources/ParseSwift/Protocols/ParseHookParametable.swift",
"chars": 367,
"preview": "//\n// ParseHookParametable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/14/22.\n// Copyright © 2022 Parse Co"
},
{
"path": "Sources/ParseSwift/Protocols/ParseHookRequestable+async.swift",
"chars": 1024,
"preview": "//\n// ParseHookRequestable+async.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/14/22.\n// Copyright © 2022 Pa"
},
{
"path": "Sources/ParseSwift/Protocols/ParseHookRequestable+combine.swift",
"chars": 816,
"preview": "//\n// ParseHookRequestable+combine.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/14/22.\n// Copyright © 2022 "
},
{
"path": "Sources/ParseSwift/Protocols/ParseHookRequestable.swift",
"chars": 3956,
"preview": "//\n// ParseHookRequestable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/14/22.\n// Copyright © 2022 Parse Co"
},
{
"path": "Sources/ParseSwift/Protocols/ParseHookTriggerable+async.swift",
"chars": 4104,
"preview": "//\n// ParseHookTriggerable+async.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/19/22.\n// Copyright © 2022 Pa"
},
{
"path": "Sources/ParseSwift/Protocols/ParseHookTriggerable+combine.swift",
"chars": 3615,
"preview": "//\n// ParseHookTriggerable+combine.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/19/22.\n// Copyright © 2022 "
},
{
"path": "Sources/ParseSwift/Protocols/ParseHookTriggerable.swift",
"chars": 13549,
"preview": "//\n// ParseHookTriggerable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/14/22.\n// Copyright © 2022 Parse Co"
},
{
"path": "Sources/ParseSwift/Protocols/ParseHookable.swift",
"chars": 391,
"preview": "//\n// ParseHookable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/15/22.\n// Copyright © 2022 Parse Community"
},
{
"path": "Sources/ParseSwift/Protocols/ParsePushApplePayloadable.swift",
"chars": 3992,
"preview": "//\n// ParsePushApplePayloadable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/8/22.\n// Copyright © 2022 Pars"
},
{
"path": "Sources/ParseSwift/Protocols/ParsePushFirebasePayloadable.swift",
"chars": 2254,
"preview": "//\n// ParsePushFirebasePayloadable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/8/22.\n// Copyright © 2022 P"
},
{
"path": "Sources/ParseSwift/Protocols/ParsePushPayloadable.swift",
"chars": 409,
"preview": "//\n// ParsePushPayloadDatable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/5/22.\n// Copyright © 2022 Parse "
},
{
"path": "Sources/ParseSwift/Protocols/ParseQueryScorable.swift",
"chars": 1459,
"preview": "//\n// ParseQueryScorable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 1/16/22.\n// Copyright © 2022 Parse Comm"
},
{
"path": "Sources/ParseSwift/Protocols/ParseTypeable.swift",
"chars": 917,
"preview": "//\n// ParseTypeable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 6/19/22.\n// Copyright © 2022 Parse Community"
},
{
"path": "Sources/ParseSwift/Protocols/QueryObservable.swift",
"chars": 2815,
"preview": "//\n// QueryObservable.swift\n// ParseSwift\n//\n// Created by Corey Baker on 7/3/21.\n// Copyright © 2021 Parse Communit"
},
{
"path": "Sources/ParseSwift/Protocols/Queryable.swift",
"chars": 3818,
"preview": "//\n// Queryable.swift\n// ParseSwift\n//\n// Created by Florent Vilmart on 17-07-24.\n// Copyright © 2020 Parse. All rig"
},
{
"path": "Sources/ParseSwift/Protocols/Savable.swift",
"chars": 405,
"preview": "//\n// Savable.swift\n// ParseSwift\n//\n// Created by Florent Vilmart on 17-07-24.\n// Copyright © 2020 Parse. All right"
},
{
"path": "Sources/ParseSwift/Storage/KeychainStore.swift",
"chars": 17465,
"preview": "//\n// KeychainStore.swift\n// ParseSwift\n//\n// Created by Florent Vilmart on 17-09-25.\n// Copyright © 2017 Parse. All"
},
{
"path": "Sources/ParseSwift/Storage/ParseFileManager.swift",
"chars": 9412,
"preview": "//\n// ParseFileManager.swift\n// ParseSwift\n//\n// Created by Corey Baker on 12/20/20.\n// Copyright © 2020 Parse Commu"
},
{
"path": "Sources/ParseSwift/Storage/ParseKeyValueStore.swift",
"chars": 3114,
"preview": "//\n// ParsePrimitiveStorable.swift\n// \n//\n// Created by Pranjal Satija on 7/19/20.\n//\n\nimport Foundation\n\n/**\n A stor"
},
{
"path": "Sources/ParseSwift/Storage/ParseStorage.swift",
"chars": 1689,
"preview": "//\n// ParseStorage.swift\n// \n//\n// Created by Pranjal Satija on 7/19/20.\n//\n\n// MARK: ParseStorage\nstruct ParseStorag"
},
{
"path": "Sources/ParseSwift/Storage/SecureStorage.swift",
"chars": 494,
"preview": "//\n// SecureStorage.swift\n// ParseSwift\n//\n// Created by Florent Vilmart on 17-09-25.\n// Copyright © 2017 Parse. All"
},
{
"path": "Sources/ParseSwift/Types/CloudViewModel.swift",
"chars": 2829,
"preview": "//\n// CloudViewModel.swift\n// ParseSwift\n//\n// Created by Corey Baker on 7/11/21.\n// Copyright © 2021 Parse Communit"
},
{
"path": "Sources/ParseSwift/Types/Parse.h",
"chars": 476,
"preview": "//\n// Parse.h\n// Parse\n//\n// Created by Florent Vilmart on 17-07-23.\n// Copyright © 2017 Parse. All rights reserved."
}
]
// ... and 201 more files (download for full content)
About this extraction
This page contains the full source code of the parse-community/Parse-Swift GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 401 files (4.3 MB), approximately 1.2M tokens. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.