Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Update] Bump version to Xcode 16 #508

Merged
merged 25 commits into from
Sep 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f2e1cd5
Validated settings for Xcode 16.
yo1995 Sep 20, 2024
b257c76
Bump Xcode requirement in README.
yo1995 Sep 20, 2024
e3e8793
Upgrade Xcode project version.
yo1995 Sep 20, 2024
4b52704
Make ID conformance nonisolated.
yo1995 Sep 23, 2024
56f860c
Add `@retroactive` to silence protocol related warnings.
yo1995 Sep 23, 2024
28683f3
Bump Swift Version to 6.0.
yo1995 Sep 23, 2024
5186c7c
Merge branch 'v.next' into Ting/BumpXcode16
yo1995 Sep 23, 2024
5705754
any Sendable.
yo1995 Sep 23, 2024
2db484f
Change deinit cleanup method to nonisolated Task.
yo1995 Sep 23, 2024
2cf826b
Do FileDocument on main actor to ensure single access.
yo1995 Sep 23, 2024
0784edc
Use sendable closure for taskgroups.
yo1995 Sep 23, 2024
858fbd3
Swift 6 concurrency upgrade.
yo1995 Sep 23, 2024
bed2c63
Blindly unchecked Sendable.
yo1995 Sep 23, 2024
3cf2a63
Apply suggestions from code review.
yo1995 Sep 24, 2024
2f49637
Move deinit stopping logics to onDisappear.
yo1995 Sep 24, 2024
d4e7483
Refactor `KMZFile` to make it Sendable.
yo1995 Sep 25, 2024
c4ed988
Inline openURL method.
yo1995 Sep 25, 2024
f54c9db
Move the sentence reader to run on main actor.
yo1995 Sep 25, 2024
7935e77
Refactor animation logic to not use Timer block.
yo1995 Sep 25, 2024
bf91bf6
Apply suggestions from code review.
yo1995 Sep 25, 2024
2336429
Get rid of redundant Sendable conformance
yo1995 Sep 25, 2024
1d207ee
Make app storage not array but string.
yo1995 Sep 25, 2024
c660138
Apply suggestions from code review.
yo1995 Sep 25, 2024
73725b6
Rename extension file in project.
yo1995 Sep 25, 2024
25058a0
Merge branch 'v.next' into Ting/BumpXcode16
yo1995 Sep 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,9 @@ This repository contains Swift sample code demonstrating the capabilities of the

## Requirements

* [ArcGIS Maps SDK for Swift](https://developers.arcgis.com/swift/) 200.5 (or newer)
* [ArcGIS Maps SDK for Swift](https://developers.arcgis.com/swift/) 200.5.1 (or newer)
* [ArcGIS Maps SDK for Swift Toolkit](https://github.com/Esri/arcgis-maps-sdk-swift-toolkit) 200.5 (or newer)
* Xcode 15.0 (or newer)
* Xcode 16.0 (or newer)

The *ArcGIS Maps SDK for Swift Samples app* has a *Target SDK* version of *16.0*, meaning that it can run on devices with *iOS 16.0* or newer.

Expand Down
18 changes: 9 additions & 9 deletions Samples.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
archiveVersion = 1;
classes = {
};
objectVersion = 60;
objectVersion = 77;
objects = {

/* Begin PBXBuildFile section */
Expand Down Expand Up @@ -409,7 +409,7 @@
D7BA38922BFBC4F0009954F5 /* EditFeaturesWithFeatureLinkedAnnotationView.Model.swift in Copy Source Code Files */ = {isa = PBXBuildFile; fileRef = D7BA38902BFBC476009954F5 /* EditFeaturesWithFeatureLinkedAnnotationView.Model.swift */; };
D7BA38972BFBFC0F009954F5 /* QueryRelatedFeaturesView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7BA38932BFBFC0F009954F5 /* QueryRelatedFeaturesView.swift */; };
D7BA389A2BFBFC2E009954F5 /* QueryRelatedFeaturesView.swift in Copy Source Code Files */ = {isa = PBXBuildFile; fileRef = D7BA38932BFBFC0F009954F5 /* QueryRelatedFeaturesView.swift */; };
D7BA8C442B2A4DAA00018633 /* Array+RawRepresentable.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7BA8C432B2A4DAA00018633 /* Array+RawRepresentable.swift */; };
D7BA8C442B2A4DAA00018633 /* Array.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7BA8C432B2A4DAA00018633 /* Array.swift */; };
D7BA8C462B2A8ACA00018633 /* String.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7BA8C452B2A8ACA00018633 /* String.swift */; };
D7BB3DD22C5D781800FFCD56 /* SaveTheBay.geodatabase in Resources */ = {isa = PBXBuildFile; fileRef = D7BB3DD02C5D781800FFCD56 /* SaveTheBay.geodatabase */; settings = {ASSET_TAGS = (EditGeodatabaseWithTransactions, ); }; };
D7C16D1B2AC5F95300689E89 /* Animate3DGraphicView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D7C16D1A2AC5F95300689E89 /* Animate3DGraphicView.swift */; };
Expand Down Expand Up @@ -977,7 +977,7 @@
D7B759B22B1FFBE300017FDD /* FavoritesView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FavoritesView.swift; sourceTree = "<group>"; };
D7BA38902BFBC476009954F5 /* EditFeaturesWithFeatureLinkedAnnotationView.Model.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = EditFeaturesWithFeatureLinkedAnnotationView.Model.swift; sourceTree = "<group>"; };
D7BA38932BFBFC0F009954F5 /* QueryRelatedFeaturesView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = QueryRelatedFeaturesView.swift; sourceTree = "<group>"; };
D7BA8C432B2A4DAA00018633 /* Array+RawRepresentable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Array+RawRepresentable.swift"; sourceTree = "<group>"; };
D7BA8C432B2A4DAA00018633 /* Array.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Array.swift; sourceTree = "<group>"; };
D7BA8C452B2A8ACA00018633 /* String.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = String.swift; sourceTree = "<group>"; };
D7BB3DD02C5D781800FFCD56 /* SaveTheBay.geodatabase */ = {isa = PBXFileReference; lastKnownFileType = file; path = SaveTheBay.geodatabase; sourceTree = "<group>"; };
D7C16D1A2AC5F95300689E89 /* Animate3DGraphicView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animate3DGraphicView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1084,7 +1084,7 @@
00181B442846AD3900654571 /* Extensions */ = {
isa = PBXGroup;
children = (
D7BA8C432B2A4DAA00018633 /* Array+RawRepresentable.swift */,
D7BA8C432B2A4DAA00018633 /* Array.swift */,
D7BA8C452B2A8ACA00018633 /* String.swift */,
00181B452846AD7100654571 /* View+ErrorAlert.swift */,
);
Expand Down Expand Up @@ -2951,7 +2951,7 @@
StyleSymbolsFromMobileStyleFile,
);
LastSwiftUpdateCheck = 1330;
LastUpgradeCheck = 1500;
LastUpgradeCheck = 1600;
ORGANIZATIONNAME = Esri;
TargetAttributes = {
00E5401227F3CCA200CF66D5 = {
Expand All @@ -2960,7 +2960,6 @@
};
};
buildConfigurationList = 00E5400A27F3CCA100CF66D5 /* Build configuration list for PBXProject "Samples" */;
compatibilityVersion = "Xcode 15.0";
philium marked this conversation as resolved.
Show resolved Hide resolved
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
Expand All @@ -2971,6 +2970,7 @@
packageReferences = (
00C43AEB2947DC350099AE34 /* XCRemoteSwiftPackageReference "arcgis-maps-sdk-swift-toolkit" */,
);
preferredProjectObjectVersion = 77;
productRefGroup = 00E5401427F3CCA200CF66D5 /* Products */;
projectDirPath = "";
projectRoot = "";
Expand Down Expand Up @@ -3188,7 +3188,7 @@
D79482D42C35D872006521CD /* CreateDynamicBasemapGalleryView.swift in Sources */,
D77570C02A2942F800F490CD /* AnimateImagesWithImageOverlayView.swift in Sources */,
D7054AE92ACCCB6C007235BA /* Animate3DGraphicView.SettingsView.swift in Sources */,
D7BA8C442B2A4DAA00018633 /* Array+RawRepresentable.swift in Sources */,
D7BA8C442B2A4DAA00018633 /* Array.swift in Sources */,
D78FA4942C3C88880079313E /* CreateDynamicBasemapGalleryView.Views.swift in Sources */,
E0EA0B772866390E00C9621D /* ProjectGeometryView.swift in Sources */,
D74C8BFE2ABA5605007C76B8 /* StyleSymbolsFromMobileStyleFileView.swift in Sources */,
Expand Down Expand Up @@ -3490,7 +3490,7 @@
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_STRICT_CONCURRENCY = targeted;
SWIFT_VERSION = 5.0;
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2,6";
};
name = Debug;
Expand Down Expand Up @@ -3522,7 +3522,7 @@
SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_STRICT_CONCURRENCY = targeted;
SWIFT_VERSION = 5.0;
SWIFT_VERSION = 6.0;
TARGETED_DEVICE_FAMILY = "1,2,6";
VALIDATE_PRODUCT = YES;
};
Expand Down
2 changes: 1 addition & 1 deletion Samples.xcodeproj/xcshareddata/xcschemes/Samples.xcscheme
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
LastUpgradeVersion = "1600"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct AnalyzeNetworkWithSubnetworkTraceView: View {
@State private var selectedComparison: UtilityNetworkAttributeComparison.Operator?

/// The value selected by the user.
@State private var selectedValue: Any?
@State private var selectedValue: (any Sendable)?

/// A Boolean value indicating if the add condition menu is presented.
@State private var isConditionMenuPresented = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,6 @@ extension Animate3DGraphicView {
animation.setup(displayLink: displayLink)
}

deinit {
Task { await animation.displayLink?.invalidate() }
}

// MARK: Methods

/// Monitors the camera controller's properties to update the associated text when they change.
Expand Down
4 changes: 4 additions & 0 deletions Shared/Samples/Animate 3D graphic/Animate3DGraphicView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,10 @@ struct Animate3DGraphicView: View {
} label: {
Image(systemName: model.animation.isPlaying ? "pause.fill" : "play.fill")
}
.onDisappear {
model.animation.displayLink?.invalidate()
}

Spacer()

SettingsView(label: "Camera") {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ struct AugmentRealityToNavigateRouteView: View {
.onSingleTapGesture { _, mapPoint in
tapLocation = mapPoint
}
.onDisappear {
Task {
await model.locationDisplay.dataSource.stop()
}
}
.task(id: tapLocation) {
guard let tapLocation else { return }

Expand Down Expand Up @@ -161,13 +166,6 @@ private extension AugmentRealityToNavigateRouteView {
/// The status text displayed to the user.
@Published var statusText = "Tap to place a start point."

deinit {
Task {
/// Stop the location data source.
await locationDisplay.dataSource.stop()
}
}

/// Performs important tasks including setting up the location display, creating route parameters,
/// and loading the scene elevation source.
func setUp() async throws {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,13 @@ extension CreateAndSaveKMLView {
private let document: KMLDocument

/// The temporary directory where the KMZ file will be stored.
private var temporaryDirectory: URL?
private let temporaryDirectory = FileManager.createTemporaryDirectory()

/// The temporary URL to the KMZ file.
private var temporaryDocumentURL: URL?
private var temporaryDocumentURL: URL? {
temporaryDirectory
.appendingPathComponent("\(document.name).kmz")
}

static var readableContentTypes: [UTType] { [.kmz] }

Expand All @@ -101,21 +104,15 @@ extension CreateAndSaveKMLView {

/// Deletes the temporarily stored KMZ file.
func deleteFile() {
guard let url = temporaryDirectory else { return }
try? FileManager.default.removeItem(at: url)
try? FileManager.default.removeItem(at: temporaryDirectory)
}

/// Saves the KML document as a KMZ file to a temporary location.
@MainActor
func saveFile() async throws {
temporaryDirectory = FileManager.createTemporaryDirectory()

if document.name.isEmpty {
document.name = "Untitled"
}

temporaryDocumentURL = temporaryDirectory?.appendingPathComponent("\(document.name).kmz")

try await document.save(to: temporaryDocumentURL!)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ extension CreateMobileGeodatabaseView {
// MARK: GeodatabaseFile

/// A geodatabase file that can be used with the native file exporter.
@MainActor
final class GeodatabaseFile {
/// The mobile geodatabase used to create the geodatabase file.
private(set) var geodatabase: Geodatabase?
Expand Down Expand Up @@ -168,15 +169,15 @@ extension CreateMobileGeodatabaseView {

extension CreateMobileGeodatabaseView.GeodatabaseFile: FileDocument {
/// The file and data types that the document reads from.
static var readableContentTypes: [UTType] { [.geodatabase] }
nonisolated static var readableContentTypes: [UTType] { [.geodatabase] }

/// Creates a document and initializes it with the contents of a file.
convenience init(configuration: ReadConfiguration) throws {
nonisolated convenience init(configuration: ReadConfiguration) throws {
fatalError("Loading geodatabase files is not supported by this sample.")
}

/// Serializes a document snapshot to a file wrapper.
func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
nonisolated func fileWrapper(configuration: WriteConfiguration) throws -> FileWrapper {
return try FileWrapper(url: geodatabaseURL)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ extension DownloadPreplannedMapAreaView {
await withTaskGroup(of: Void.self) { group in
for model in allOfflineMapModels {
if model.isDownloading {
group.addTask { @MainActor in
group.addTask { @MainActor @Sendable in
await model.cancelDownloading()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,15 +100,15 @@ struct NavigateRouteWithReroutingView: View {
guard model.isNavigating, let routeTracker = model.routeTracker else { return }

await withTaskGroup(of: Void.self) { group in
group.addTask { @MainActor in
group.addTask { @MainActor @Sendable in
// Handle new tracking statuses from the route tracker.
for await trackingStatus in routeTracker.$trackingStatus {
guard let trackingStatus else { continue }
await model.updateProgress(using: trackingStatus)
}
}

group.addTask { @MainActor in
group.addTask { @MainActor @Sendable in
// Speak new voice guidances from the route tracker.
for await voiceGuidance in routeTracker.voiceGuidances {
model.speakVoiceGuidance(voiceGuidance)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ struct SetUpLocationDrivenGeotriggersView: View {
private func startGeotriggerMonitors(_ geotriggerMonitors: [GeotriggerMonitor]) async throws {
await withThrowingTaskGroup(of: Void.self) { group in
for monitor in geotriggerMonitors {
group.addTask { @MainActor in
group.addTask { @MainActor @Sendable in
try await monitor.start()
for await newNotification in monitor.notifications where newNotification is FenceGeotriggerNotificationInfo {
model.handleGeotriggerNotification(newNotification as! FenceGeotriggerNotificationInfo)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import Foundation

extension ShowDeviceLocationWithNMEADataSourcesView {
/// A data source simulating a hardware that emits NMEA data.
@MainActor
class FileNMEASentenceReader {
/// The playback time interval.
private let interval: TimeInterval
Expand Down Expand Up @@ -79,9 +80,11 @@ extension ShowDeviceLocationWithNMEADataSourcesView {
withTimeInterval: interval,
repeats: true
) { [weak self] _ in
guard let self = self else { return }
let data = self.nmeaDataIterator.next()!
continuation.yield(data)
Task { @MainActor in
guard let self else { return }
let data = self.nmeaDataIterator.next()!
continuation.yield(data)
}
}
}
}
Expand All @@ -93,10 +96,6 @@ extension ShowDeviceLocationWithNMEADataSourcesView {
timer = nil
messages = nil
}

deinit {
stop()
yo1995 marked this conversation as resolved.
Show resolved Hide resolved
}
}

/// A generic circular iterator.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ struct ShowViewshedFromGeoelementInSceneView: View {
/// The view model for the sample.
@StateObject private var model = Model()

/// A timer to trigger waypoint movement animation.
let timer = Timer.publish(every: 0.1, on: .main, in: .common).autoconnect()

var body: some View {
SceneView(
scene: model.scene,
Expand All @@ -29,7 +32,13 @@ struct ShowViewshedFromGeoelementInSceneView: View {
.onSingleTapGesture { _, scenePoint in
// Move the tank to the scene point on a screen tap.
guard let scenePoint else { return }
model.move(toWaypoint: scenePoint)
model.waypoint = scenePoint
}
.onReceive(timer) { _ in
// Use a timer to animate the tank moving towards the new waypoint.
if model.waypoint != nil {
model.animate()
}
}
.overlay(alignment: .top) {
// Instruction text.
Expand All @@ -38,9 +47,6 @@ struct ShowViewshedFromGeoelementInSceneView: View {
.frame(maxWidth: .infinity, alignment: .leading)
.background(.thinMaterial, ignoresSafeAreaEdges: .horizontal)
}
.onDisappear {
model.stopMoving()
}
}
}

Expand Down Expand Up @@ -100,16 +106,7 @@ private extension ShowViewshedFromGeoelementInSceneView {
}()

/// The point for the tank to move toward.
private var waypoint: Point? {
didSet {
if waypoint == nil {
stopMoving()
}
}
}

/// The timer for the moving tank animation.
private var animationTimer: Timer?
var waypoint: Point?

init() {
// Create camera controller.
Expand Down Expand Up @@ -139,24 +136,8 @@ private extension ShowViewshedFromGeoelementInSceneView {
analysisOverlay.addAnalysis(geoElementViewshed)
}

/// Moves the tank to a point.
/// - Parameter waypoint: The `Point` to move the tank to.
func move(toWaypoint waypoint: Point) {
self.waypoint = waypoint

// Start a timer to animate the tank moving towards the new waypoint.
animationTimer = Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { _ in
self.animate()
}
}

/// Stops moving the tank.
func stopMoving() {
animationTimer?.invalidate()
}

/// Animates the tank moving from its current point to the waypoint.
private func animate() {
func animate() {
// Get point from the current tank position.
guard let tankLocation = tankGraphic.geometry as? Point,
let point = waypoint else { return }
Expand Down
Loading
Loading