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

Pose #56

Open
wants to merge 33 commits into
base: main
Choose a base branch
from
Open

Pose #56

Show file tree
Hide file tree
Changes from 21 commits
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
43c8f8b
Add human feature.
john-rocky May 21, 2024
1c72a52
Add human feature.
john-rocky May 21, 2024
0cef67b
Edit porstprocessing.
john-rocky May 22, 2024
a7fcb2b
Merge branch 'main' into human
glenn-jocher May 29, 2024
51b6226
Merge branch 'main' into human
john-rocky Jun 3, 2024
09c6447
simple swift tracking
john-rocky Jun 4, 2024
cbfd8c5
hide a tracking toggle in detect mode
john-rocky Jun 4, 2024
b73291e
Fix feature value order.
john-rocky Jun 4, 2024
22eec3d
updated human features every frame
john-rocky Jun 5, 2024
16c668f
add landscape mode
john-rocky Jun 14, 2024
a35e1c3
Merge branch 'main' into humantraking
glenn-jocher Jun 16, 2024
018d4fb
Merge remote-tracking branch 'refs/remotes/origin/humantraking'
john-rocky Jun 17, 2024
9822362
add segment.
john-rocky Jul 3, 2024
133a6ab
add description for PostProcessSegment.swift
john-rocky Jul 3, 2024
4777065
Auto-format by https://ultralytics.com/actions
UltralyticsAssistant Jul 3, 2024
ea4eb81
Use Ultralytics branding color palette.
john-rocky Jul 13, 2024
bab5afd
Merge remote-tracking branch 'refs/remotes/origin/segmentation'
john-rocky Jul 13, 2024
502f85c
Fixed landscape mode layout
john-rocky Jul 17, 2024
f976a35
dev
john-rocky Aug 6, 2024
985ad70
add pose feature.
john-rocky Aug 12, 2024
cdafd21
Auto-format by https://ultralytics.com/actions
UltralyticsAssistant Aug 12, 2024
127475b
Add only pause function
john-rocky Aug 24, 2024
ed7e45b
add model reference
john-rocky Aug 24, 2024
2a7ce49
Auto-format by https://ultralytics.com/actions
UltralyticsAssistant Aug 24, 2024
47d0d8b
Update README.md
john-rocky Aug 24, 2024
74ea665
Merge branch 'main' into pose
john-rocky Aug 24, 2024
bfbcc60
resolve conflicts
john-rocky Aug 24, 2024
5288ce0
Auto-format by https://ultralytics.com/actions
UltralyticsAssistant Aug 24, 2024
0ee3921
fix storyboard
john-rocky Aug 24, 2024
50602ed
Merge remote-tracking branch 'refs/remotes/origin/pose'
john-rocky Aug 24, 2024
f93b576
Update Info.plist
john-rocky Aug 24, 2024
e5124ce
add comments and rename overlay layer.
john-rocky Aug 30, 2024
c6eabce
fix comment
john-rocky Aug 31, 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
44 changes: 22 additions & 22 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,43 +46,43 @@ Ensure you have the following before you start:

1. **Clone the Repository:**

```sh
git clone https://github.com/ultralytics/yolo-ios-app.git
```
```sh
git clone https://github.com/ultralytics/yolo-ios-app.git
```

2. **Open the Project in Xcode:**

Navigate to the cloned directory and open the `YOLO.xcodeproj` file.
Navigate to the cloned directory and open the `YOLO.xcodeproj` file.

<p align="center">
<img width="50%" src="https://github.com/ultralytics/ultralytics/assets/26833433/e0053238-4a7c-4d18-8720-6ce24c73dea0" alt="XCode load project screenshot">
</p>
<p align="center">
<img width="50%" src="https://github.com/ultralytics/ultralytics/assets/26833433/e0053238-4a7c-4d18-8720-6ce24c73dea0" alt="XCode load project screenshot">
</p>

In Xcode, go to the project's target settings and choose your Apple Developer account under the "Signing & Capabilities" tab.
In Xcode, go to the project's target settings and choose your Apple Developer account under the "Signing & Capabilities" tab.

3. **Add YOLOv8 Models to the Project:**

Export CoreML INT8 models using the `ultralytics` Python package (with `pip install ultralytics`), or download them from our [GitHub release assets](https://github.com/ultralytics/yolo-ios-app/releases). You should have 5 YOLOv8 models in total. Place these in the `YOLO/Models` directory as seen in the Xcode screenshot below.
Export CoreML INT8 models using the `ultralytics` Python package (with `pip install ultralytics`), or download them from our [GitHub release assets](https://github.com/ultralytics/yolo-ios-app/releases). You should have 5 YOLOv8 models in total. Place these in the `YOLO/Models` directory as seen in the Xcode screenshot below.

```python
from ultralytics import YOLO
```python
from ultralytics import YOLO

# Loop through all YOLOv8 model sizes
for size in ("n", "s", "m", "l", "x"):
# Load a YOLOv8 PyTorch model
model = YOLO(f"yolov8{size}.pt")
# Loop through all YOLOv8 model sizes
for size in ("n", "s", "m", "l", "x"):
# Load a YOLOv8 PyTorch model
model = YOLO(f"yolov8{size}.pt")

# Export the PyTorch model to CoreML INT8 format with NMS layers
model.export(format="coreml", int8=True, nms=True, imgsz=[640, 384])
```
# Export the PyTorch model to CoreML INT8 format with NMS layers
model.export(format="coreml", int8=True, nms=True, imgsz=[640, 384])
```

4. **Run the Ultralytics YOLO iOS App:**

Connect your iOS device and select it as the run target. Press the Run button to install the app on your device.
Connect your iOS device and select it as the run target. Press the Run button to install the app on your device.

<p align="center">
<img width="100%" src="https://github.com/ultralytics/ultralytics/assets/26833433/d2c6a7b7-fa8b-4130-a57f-4241f7a42ff2" alt="Ultralytics YOLO XCode screenshot">
</p>
<p align="center">
<img width="100%" src="https://github.com/ultralytics/ultralytics/assets/26833433/d2c6a7b7-fa8b-4130-a57f-4241f7a42ff2" alt="Ultralytics YOLO XCode screenshot">
</p>

## 🚀 Usage

Expand Down
56 changes: 30 additions & 26 deletions YOLO.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,15 @@
636EFCAF21E62DD300DE43BC /* VideoCapture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 636EFCA221E62DD300DE43BC /* VideoCapture.swift */; };
636EFCB321E62DD300DE43BC /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 636EFCA721E62DD300DE43BC /* AppDelegate.swift */; };
636EFCB921E62E3900DE43BC /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 636EFCB821E62E3900DE43BC /* Assets.xcassets */; };
6381D2182B7817C200ABA4E8 /* yolov8l.mlpackage in Sources */ = {isa = PBXBuildFile; fileRef = 6381D2132B7817C200ABA4E8 /* yolov8l.mlpackage */; };
6381D2192B7817C200ABA4E8 /* yolov8x.mlpackage in Sources */ = {isa = PBXBuildFile; fileRef = 6381D2142B7817C200ABA4E8 /* yolov8x.mlpackage */; };
6381D21A2B7817C200ABA4E8 /* yolov8s.mlpackage in Sources */ = {isa = PBXBuildFile; fileRef = 6381D2152B7817C200ABA4E8 /* yolov8s.mlpackage */; };
6381D21B2B7817C200ABA4E8 /* yolov8m.mlpackage in Sources */ = {isa = PBXBuildFile; fileRef = 6381D2162B7817C200ABA4E8 /* yolov8m.mlpackage */; };
6381D21C2B7817C200ABA4E8 /* yolov8n.mlpackage in Sources */ = {isa = PBXBuildFile; fileRef = 6381D2172B7817C200ABA4E8 /* yolov8n.mlpackage */; };
63CF371F2514455300E2DEA1 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6323C44D22186177008AE681 /* LaunchScreen.storyboard */; };
63CF37202514455300E2DEA1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 6323C44F22186177008AE681 /* Main.storyboard */; };
63CF37212514455300E2DEA1 /* ultralytics_yolo_logotype.png in Resources */ = {isa = PBXBuildFile; fileRef = 6323C45122186177008AE681 /* ultralytics_yolo_logotype.png */; };
730E72CD2BFC43BF000E1F45 /* PostProcessing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 730E72CC2BFC43BF000E1F45 /* PostProcessing.swift */; };
7333105F2C69CE95001D647B /* Colors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7333105E2C69CE95001D647B /* Colors.swift */; };
73A4E7752C0EA36D00218E8F /* HumanModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73A4E7742C0EA36D00218E8F /* HumanModel.swift */; };
73A4E7772C0EA37300218E8F /* TrackingModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73A4E7762C0EA37300218E8F /* TrackingModel.swift */; };
73B6CD452C5DA43E008A9CEC /* PostProcessPose.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73B6CD442C5DA43E008A9CEC /* PostProcessPose.swift */; };
73FE95F32C3500AC00C6C806 /* PostProcessSegment.swift in Sources */ = {isa = PBXBuildFile; fileRef = 73FE95F22C3500AC00C6C806 /* PostProcessSegment.swift */; };
8EDAA33950796844333D60A7 /* BoundingBoxView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8EDAA633C1F2B50286D16008 /* BoundingBoxView.swift */; };
/* End PBXBuildFile section */

Expand All @@ -35,12 +36,13 @@
636EFCA221E62DD300DE43BC /* VideoCapture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = VideoCapture.swift; sourceTree = "<group>"; };
636EFCA721E62DD300DE43BC /* AppDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
636EFCB821E62E3900DE43BC /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
6381D2132B7817C200ABA4E8 /* yolov8l.mlpackage */ = {isa = PBXFileReference; lastKnownFileType = folder.mlpackage; path = yolov8l.mlpackage; sourceTree = "<group>"; };
6381D2142B7817C200ABA4E8 /* yolov8x.mlpackage */ = {isa = PBXFileReference; lastKnownFileType = folder.mlpackage; path = yolov8x.mlpackage; sourceTree = "<group>"; };
6381D2152B7817C200ABA4E8 /* yolov8s.mlpackage */ = {isa = PBXFileReference; lastKnownFileType = folder.mlpackage; path = yolov8s.mlpackage; sourceTree = "<group>"; };
6381D2162B7817C200ABA4E8 /* yolov8m.mlpackage */ = {isa = PBXFileReference; lastKnownFileType = folder.mlpackage; path = yolov8m.mlpackage; sourceTree = "<group>"; };
6381D2172B7817C200ABA4E8 /* yolov8n.mlpackage */ = {isa = PBXFileReference; lastKnownFileType = folder.mlpackage; path = yolov8n.mlpackage; sourceTree = "<group>"; };
63B8B0A821E62A890026FBC3 /* .gitignore */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = .gitignore; sourceTree = "<group>"; };
730E72CC2BFC43BF000E1F45 /* PostProcessing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostProcessing.swift; sourceTree = "<group>"; };
7333105E2C69CE95001D647B /* Colors.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Colors.swift; sourceTree = "<group>"; };
73A4E7742C0EA36D00218E8F /* HumanModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HumanModel.swift; sourceTree = "<group>"; };
73A4E7762C0EA37300218E8F /* TrackingModel.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TrackingModel.swift; sourceTree = "<group>"; };
73B6CD442C5DA43E008A9CEC /* PostProcessPose.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PostProcessPose.swift; sourceTree = "<group>"; };
73FE95F22C3500AC00C6C806 /* PostProcessSegment.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PostProcessSegment.swift; sourceTree = "<group>"; };
7BCB411721C3096100BFC4D0 /* YOLO.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = YOLO.app; sourceTree = BUILT_PRODUCTS_DIR; };
8EDAA633C1F2B50286D16008 /* BoundingBoxView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = BoundingBoxView.swift; sourceTree = "<group>"; };
8EDAAA4507D2D23D7FAB827F /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
Expand All @@ -60,8 +62,14 @@
636166E72514438D0054FA7E /* Utilities */ = {
isa = PBXGroup;
children = (
73FE95F22C3500AC00C6C806 /* PostProcessSegment.swift */,
73A4E7762C0EA37300218E8F /* TrackingModel.swift */,
73A4E7742C0EA36D00218E8F /* HumanModel.swift */,
730E72CC2BFC43BF000E1F45 /* PostProcessing.swift */,
636166E9251443B20054FA7E /* ThresholdProvider.swift */,
8EDAA633C1F2B50286D16008 /* BoundingBoxView.swift */,
73B6CD442C5DA43E008A9CEC /* PostProcessPose.swift */,
7333105E2C69CE95001D647B /* Colors.swift */,
);
path = Utilities;
sourceTree = "<group>";
Expand All @@ -87,11 +95,6 @@
63A946D8271800E20001C3ED /* Models */ = {
isa = PBXGroup;
children = (
6381D2132B7817C200ABA4E8 /* yolov8l.mlpackage */,
6381D2162B7817C200ABA4E8 /* yolov8m.mlpackage */,
6381D2172B7817C200ABA4E8 /* yolov8n.mlpackage */,
6381D2152B7817C200ABA4E8 /* yolov8s.mlpackage */,
6381D2142B7817C200ABA4E8 /* yolov8x.mlpackage */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -210,16 +213,17 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
6381D21B2B7817C200ABA4E8 /* yolov8m.mlpackage in Sources */,
6381D21C2B7817C200ABA4E8 /* yolov8n.mlpackage in Sources */,
73B6CD452C5DA43E008A9CEC /* PostProcessPose.swift in Sources */,
7333105F2C69CE95001D647B /* Colors.swift in Sources */,
73FE95F32C3500AC00C6C806 /* PostProcessSegment.swift in Sources */,
730E72CD2BFC43BF000E1F45 /* PostProcessing.swift in Sources */,
636EFCAF21E62DD300DE43BC /* VideoCapture.swift in Sources */,
636166EA251443B20054FA7E /* ThresholdProvider.swift in Sources */,
6381D2182B7817C200ABA4E8 /* yolov8l.mlpackage in Sources */,
6381D21A2B7817C200ABA4E8 /* yolov8s.mlpackage in Sources */,
6381D2192B7817C200ABA4E8 /* yolov8x.mlpackage in Sources */,
636EFCB321E62DD300DE43BC /* AppDelegate.swift in Sources */,
73A4E7772C0EA37300218E8F /* TrackingModel.swift in Sources */,
636EFCAA21E62DD300DE43BC /* ViewController.swift in Sources */,
8EDAA33950796844333D60A7 /* BoundingBoxView.swift in Sources */,
73A4E7752C0EA36D00218E8F /* HumanModel.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down Expand Up @@ -350,8 +354,8 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 0;
DEVELOPMENT_TEAM = 3MR4P6CL3X;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = YOLO/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Ultralytics YOLO";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
Expand All @@ -360,7 +364,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 8.2.0;
MARKETING_VERSION = 8.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.ultralytics.iDetection;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
Expand All @@ -378,8 +382,8 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_INCLUDE_ALL_APPICON_ASSETS = NO;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 0;
DEVELOPMENT_TEAM = 3MR4P6CL3X;
CURRENT_PROJECT_VERSION = 2;
DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = YOLO/Info.plist;
INFOPLIST_KEY_CFBundleDisplayName = "Ultralytics YOLO";
INFOPLIST_KEY_LSApplicationCategoryType = "public.app-category.developer-tools";
Expand All @@ -388,7 +392,7 @@
"$(inherited)",
"@executable_path/Frameworks",
);
MARKETING_VERSION = 8.2.0;
MARKETING_VERSION = 8.3.0;
PRODUCT_BUNDLE_IDENTIFIER = com.ultralytics.iDetection;
PRODUCT_NAME = "$(TARGET_NAME)";
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
Expand Down
78 changes: 78 additions & 0 deletions YOLO.xcodeproj/xcshareddata/xcschemes/YOLO.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1540"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7BCB411621C3096100BFC4D0"
BuildableName = "YOLO.app"
BlueprintName = "YOLO"
ReferencedContainer = "container:YOLO.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7BCB411621C3096100BFC4D0"
BuildableName = "YOLO.app"
BlueprintName = "YOLO"
ReferencedContainer = "container:YOLO.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7BCB411621C3096100BFC4D0"
BuildableName = "YOLO.app"
BlueprintName = "YOLO"
ReferencedContainer = "container:YOLO.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
70 changes: 37 additions & 33 deletions YOLO/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,49 +17,53 @@ import UIKit
/// The main application delegate, handling global app behavior and configuration.
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
var window: UIWindow?

/// Called when the app finishes launching, used here to set global app settings.
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Disable screen dimming and auto-lock to keep the app active during long operations.
UIApplication.shared.isIdleTimerDisabled = true
/// Called when the app finishes launching, used here to set global app settings.
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {
// Disable screen dimming and auto-lock to keep the app active during long operations.
UIApplication.shared.isIdleTimerDisabled = true

// Enable battery monitoring to allow the app to adapt its behavior based on battery level.
UIDevice.current.isBatteryMonitoringEnabled = true
// Enable battery monitoring to allow the app to adapt its behavior based on battery level.
UIDevice.current.isBatteryMonitoringEnabled = true

// Store the app version and build version in UserDefaults for easy access elsewhere in the app.
if let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String,
let buildVersion = Bundle.main.infoDictionary?["CFBundleVersion"] as? String {
UserDefaults.standard.set("\(appVersion) (\(buildVersion))", forKey: "app_version")
}
// Store the app version and build version in UserDefaults for easy access elsewhere in the app.
if let appVersion = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String,
let buildVersion = Bundle.main.infoDictionary?["CFBundleVersion"] as? String
{
UserDefaults.standard.set("\(appVersion) (\(buildVersion))", forKey: "app_version")
}

// Store the device's UUID in UserDefaults for identification purposes.
if let uuid = UIDevice.current.identifierForVendor?.uuidString {
UserDefaults.standard.set(uuid, forKey: "uuid")
}
// Store the device's UUID in UserDefaults for identification purposes.
if let uuid = UIDevice.current.identifierForVendor?.uuidString {
UserDefaults.standard.set(uuid, forKey: "uuid")
}

// Ensure UserDefaults changes are immediately saved.
UserDefaults.standard.synchronize()
// Ensure UserDefaults changes are immediately saved.
UserDefaults.standard.synchronize()

return true
}
return true
}
}

/// Extension to CALayer to add functionality for generating screenshots of any layer.
extension CALayer {
var screenShot: UIImage? {
// Begin a new image context, using the device's screen scale to ensure high-resolution output.
UIGraphicsBeginImageContextWithOptions(frame.size, false, UIScreen.main.scale)
defer {
UIGraphicsEndImageContext()
} // Ensure the image context is cleaned up correctly.
var screenShot: UIImage? {
// Begin a new image context, using the device's screen scale to ensure high-resolution output.
UIGraphicsBeginImageContextWithOptions(frame.size, false, UIScreen.main.scale)
defer {
UIGraphicsEndImageContext()
} // Ensure the image context is cleaned up correctly.

if let context = UIGraphicsGetCurrentContext() {
// Render the layer into the current context.
render(in: context)
// Attempt to generate an image from the current context.
return UIGraphicsGetImageFromCurrentImageContext()
}
return nil // Return nil if the operation fails.
if let context = UIGraphicsGetCurrentContext() {
// Render the layer into the current context.
render(in: context)
// Attempt to generate an image from the current context.
return UIGraphicsGetImageFromCurrentImageContext()
}
return nil // Return nil if the operation fails.
}
}
Loading
Loading