导入 XuXuCheck 工程(iOS 干化学尿液试纸分析 App)

从桌面工程复制而来,作为本仓库的 Xuxucheck/ 子目录。

为控制仓库体积做了两处删减:
- 移除 Frameworks/opencv2.xcframework 下的两个 visionOS 切片
  (xros-arm64、xros-arm64-simulator,合计约 106 MB),并同步删掉该
  xcframework 内 Info.plist 里对应的两条 AvailableLibraries 记录,
  只保留 ios-arm64 与 ios-arm64_x86_64-simulator。
- 移除全部 .DS_Store 与 xcuserdata/。

已用 xcodebuild 从本目录完整编译验证:BUILD SUCCEEDED,
ProcessXCFramework 以 --platform ios 成功选中框架,产物含 3699 个 cv:: 符号
(OpenCV 确实链入),嵌入 framework 3 个,与移除无用 pod 之后的状态一致。

仓库约 206 MB,其中 OpenCV 203 MB、其余源码与依赖约 3 MB。
This commit is contained in:
2026-09-23 14:17:31 +08:00
commit d6aeede2bc
901 changed files with 327267 additions and 0 deletions
@@ -0,0 +1,205 @@
//
// Request.swift
// AlamofireObjectMapper
//
// Created by Tristan Himmelman on 2015-04-30.
//
// The MIT License (MIT)
//
// Copyright (c) 2014-2015 Tristan Himmelman
//
// 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.
import Foundation
import Alamofire
import ObjectMapper
extension DataRequest {
enum ErrorCode: Int {
case noData = 1
case dataSerializationFailed = 2
}
internal static func newError(_ code: ErrorCode, failureReason: String) -> NSError {
let errorDomain = "com.alamofireobjectmapper.error"
let userInfo = [NSLocalizedFailureReasonErrorKey: failureReason]
let returnError = NSError(domain: errorDomain, code: code.rawValue, userInfo: userInfo)
return returnError
}
/// Utility function for checking for errors in response
internal static func checkResponseForError(request: URLRequest?, response: HTTPURLResponse?, data: Data?, error: Error?) -> Error? {
if let error = error {
return error
}
guard let _ = data else {
let failureReason = "Data could not be serialized. Input data was nil."
let error = newError(.noData, failureReason: failureReason)
return error
}
return nil
}
/// Utility function for extracting JSON from response
internal static func processResponse(request: URLRequest?, response: HTTPURLResponse?, data: Data?, keyPath: String?) -> Any? {
let jsonResponseSerializer = DataRequest.jsonResponseSerializer(options: .allowFragments)
let result = jsonResponseSerializer.serializeResponse(request, response, data, nil)
let JSON: Any?
if let keyPath = keyPath , keyPath.isEmpty == false {
JSON = (result.value as AnyObject?)?.value(forKeyPath: keyPath)
} else {
JSON = result.value
}
return JSON
}
/// BaseMappable Object Serializer
public static func ObjectMapperSerializer<T: BaseMappable>(_ keyPath: String?, mapToObject object: T? = nil, context: MapContext? = nil) -> DataResponseSerializer<T> {
return DataResponseSerializer { request, response, data, error in
if let error = checkResponseForError(request: request, response: response, data: data, error: error){
return .failure(error)
}
let JSONObject = processResponse(request: request, response: response, data: data, keyPath: keyPath)
if let object = object {
_ = Mapper<T>(context: context, shouldIncludeNilValues: false).map(JSONObject: JSONObject, toObject: object)
return .success(object)
} else if let parsedObject = Mapper<T>(context: context, shouldIncludeNilValues: false).map(JSONObject: JSONObject){
return .success(parsedObject)
}
let failureReason = "ObjectMapper failed to serialize response."
let error = newError(.dataSerializationFailed, failureReason: failureReason)
return .failure(error)
}
}
/// ImmutableMappable Array Serializer
public static func ObjectMapperImmutableSerializer<T: ImmutableMappable>(_ keyPath: String?, context: MapContext? = nil) -> DataResponseSerializer<T> {
return DataResponseSerializer { request, response, data, error in
if let error = checkResponseForError(request: request, response: response, data: data, error: error){
return .failure(error)
}
let JSONObject = processResponse(request: request, response: response, data: data, keyPath: keyPath)
if let JSONObject = JSONObject,
let parsedObject = (try? Mapper<T>(context: context, shouldIncludeNilValues: false).map(JSONObject: JSONObject)){
return .success(parsedObject)
}
let failureReason = "ObjectMapper failed to serialize response."
let error = newError(.dataSerializationFailed, failureReason: failureReason)
return .failure(error)
}
}
/**
Adds a handler to be called once the request has finished.
- parameter queue: The queue on which the completion handler is dispatched.
- parameter keyPath: The key path where object mapping should be performed
- parameter object: An object to perform the mapping on to
- parameter completionHandler: A closure to be executed once the request has finished and the data has been mapped by ObjectMapper.
- returns: The request.
*/
@discardableResult
public func responseObject<T: BaseMappable>(queue: DispatchQueue? = nil, keyPath: String? = nil, mapToObject object: T? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse<T>) -> Void) -> Self {
return response(queue: queue, responseSerializer: DataRequest.ObjectMapperSerializer(keyPath, mapToObject: object, context: context), completionHandler: completionHandler)
}
@discardableResult
public func responseObject<T: ImmutableMappable>(queue: DispatchQueue? = nil, keyPath: String? = nil, mapToObject object: T? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse<T>) -> Void) -> Self {
return response(queue: queue, responseSerializer: DataRequest.ObjectMapperImmutableSerializer(keyPath, context: context), completionHandler: completionHandler)
}
/// BaseMappable Array Serializer
public static func ObjectMapperArraySerializer<T: BaseMappable>(_ keyPath: String?, context: MapContext? = nil) -> DataResponseSerializer<[T]> {
return DataResponseSerializer { request, response, data, error in
if let error = checkResponseForError(request: request, response: response, data: data, error: error){
return .failure(error)
}
let JSONObject = processResponse(request: request, response: response, data: data, keyPath: keyPath)
if let parsedObject = Mapper<T>(context: context, shouldIncludeNilValues: false).mapArray(JSONObject: JSONObject){
return .success(parsedObject)
}
let failureReason = "ObjectMapper failed to serialize response."
let error = newError(.dataSerializationFailed, failureReason: failureReason)
return .failure(error)
}
}
/// ImmutableMappable Array Serializer
public static func ObjectMapperImmutableArraySerializer<T: ImmutableMappable>(_ keyPath: String?, context: MapContext? = nil) -> DataResponseSerializer<[T]> {
return DataResponseSerializer { request, response, data, error in
if let error = checkResponseForError(request: request, response: response, data: data, error: error){
return .failure(error)
}
if let JSONObject = processResponse(request: request, response: response, data: data, keyPath: keyPath){
if let parsedObject = try? Mapper<T>(context: context, shouldIncludeNilValues: false).mapArray(JSONObject: JSONObject){
return .success(parsedObject)
}
}
let failureReason = "ObjectMapper failed to serialize response."
let error = newError(.dataSerializationFailed, failureReason: failureReason)
return .failure(error)
}
}
/**
Adds a handler to be called once the request has finished. T: BaseMappable
- parameter queue: The queue on which the completion handler is dispatched.
- parameter keyPath: The key path where object mapping should be performed
- parameter completionHandler: A closure to be executed once the request has finished and the data has been mapped by ObjectMapper.
- returns: The request.
*/
@discardableResult
public func responseArray<T: BaseMappable>(queue: DispatchQueue? = nil, keyPath: String? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse<[T]>) -> Void) -> Self {
return response(queue: queue, responseSerializer: DataRequest.ObjectMapperArraySerializer(keyPath, context: context), completionHandler: completionHandler)
}
/**
Adds a handler to be called once the request has finished. T: ImmutableMappable
- parameter queue: The queue on which the completion handler is dispatched.
- parameter keyPath: The key path where object mapping should be performed
- parameter completionHandler: A closure to be executed once the request has finished and the data has been mapped by ObjectMapper.
- returns: The request.
*/
@discardableResult
public func responseArray<T: ImmutableMappable>(queue: DispatchQueue? = nil, keyPath: String? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse<[T]>) -> Void) -> Self {
return response(queue: queue, responseSerializer: DataRequest.ObjectMapperImmutableArraySerializer(keyPath, context: context), completionHandler: completionHandler)
}
}
+22
View File
@@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 Tristan Himmelman
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.
+193
View File
@@ -0,0 +1,193 @@
AlamofireObjectMapper
============
[![Build Status](https://travis-ci.org/tristanhimmelman/AlamofireObjectMapper.svg?branch=master)](https://travis-ci.org/tristanhimmelman/AlamofireObjectMapper)
[![CocoaPods](https://img.shields.io/cocoapods/v/AlamofireObjectMapper.svg)](https://github.com/tristanhimmelman/AlamofireObjectMapper)
[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)
An extension to [Alamofire](https://github.com/Alamofire/Alamofire) which automatically converts JSON response data into swift objects using [ObjectMapper](https://github.com/Hearst-DD/ObjectMapper/).
# Usage
Given a URL which returns weather data in the following form:
```
{
"location": "Toronto, Canada",
"three_day_forecast": [
{
"conditions": "Partly cloudy",
"day" : "Monday",
"temperature": 20
},
{
"conditions": "Showers",
"day" : "Tuesday",
"temperature": 22
},
{
"conditions": "Sunny",
"day" : "Wednesday",
"temperature": 28
}
]
}
```
You can use the extension as the follows:
```swift
import AlamofireObjectMapper
let URL = "https://raw.githubusercontent.com/tristanhimmelman/AlamofireObjectMapper/d8bb95982be8a11a2308e779bb9a9707ebe42ede/sample_json"
Alamofire.request(URL).responseObject { (response: DataResponse<WeatherResponse>) in
let weatherResponse = response.result.value
print(weatherResponse?.location)
if let threeDayForecast = weatherResponse?.threeDayForecast {
for forecast in threeDayForecast {
print(forecast.day)
print(forecast.temperature)
}
}
}
```
The `WeatherResponse` object in the completion handler is a custom object which you define. The only requirement is that the object must conform to [ObjectMapper's](https://github.com/Hearst-DD/ObjectMapper/) `Mappable` protocol. In the above example, the `WeatherResponse` object looks like the following:
```swift
import ObjectMapper
class WeatherResponse: Mappable {
var location: String?
var threeDayForecast: [Forecast]?
required init?(map: Map){
}
func mapping(map: Map) {
location <- map["location"]
threeDayForecast <- map["three_day_forecast"]
}
}
class Forecast: Mappable {
var day: String?
var temperature: Int?
var conditions: String?
required init?(map: Map){
}
func mapping(map: Map) {
day <- map["day"]
temperature <- map["temperature"]
conditions <- map["conditions"]
}
}
```
The extension uses Generics to allow you to create your own custom response objects. Below is the `responseObject` function definition. Just replace `T` in the completionHandler with your custom response object and the extension handles the rest:
```swift
public func responseObject<T: BaseMappable>(queue: DispatchQueue? = nil, keyPath: String? = nil, mapToObject object: T? = nil, context: MapContext? = nil, completionHandler: @escaping (DataResponse<T>) -> Void) -> Self
```
The `responseObject` function has 4 optional parameters and a required completionHandler:
- `queue`: The queue on which the completion handler is dispatched.
- `keyPath`: The key path of the JSON where object mapping should be performed.
- `mapToObject`: An object to perform the mapping on to.
- `context`: A [context object](https://github.com/Hearst-DD/ObjectMapper/#mapping-context) that is passed to the mapping function.
- `completionHandler`: A closure to be executed once the request has finished and the data has been mapped by ObjectMapper.
### Easy Mapping of Nested Objects
AlamofireObjectMapper supports dot notation within keys for easy mapping of nested objects. Given the following JSON String:
```json
"distance" : {
"text" : "102 ft",
"value" : 31
}
```
You can access the nested objects as follows:
```swift
func mapping(map: Map) {
distance <- map["distance.value"]
}
```
[See complete documentation](https://github.com/Hearst-DD/ObjectMapper#easy-mapping-of-nested-objects)
### KeyPath
The `keyPath` variable is used to drill down into a JSON response and only map the data found at that `keyPath`. It supports nested values such as `data.weather` to drill down several levels in a JSON response.
```swift
let URL = "https://raw.githubusercontent.com/tristanhimmelman/AlamofireObjectMapper/2ee8f34d21e8febfdefb2b3a403f18a43818d70a/sample_keypath_json"
let expectation = expectationWithDescription("\(URL)")
Alamofire.request(URL).responseObject(keyPath: "data") { (response: DataResponse<WeatherResponse>) in
expectation.fulfill()
let weatherResponse = response.result.value
print(weatherResponse?.location)
if let threeDayForecast = weatherResponse?.threeDayForecast {
for forecast in threeDayForecast {
print(forecast.day)
print(forecast.temperature)
}
}
}
```
# Array Responses
If you have an endpoint that returns data in `Array` form you can map it with the following function:
```swift
public func responseArray<T: Mappable>(queue queue: dispatch_queue_t? = nil, keyPath: String? = nil, completionHandler: DataResponse<[T]> -> Void) -> Self
```
For example, if your endpoint returns the following:
```
[
{
"conditions": "Partly cloudy",
"day" : "Monday",
"temperature": 20
},
{
"conditions": "Showers",
"day" : "Tuesday",
"temperature": 22
},
{
"conditions": "Sunny",
"day" : "Wednesday",
"temperature": 28
}
]
```
You can request and map it as follows:
```swift
let URL = "https://raw.githubusercontent.com/tristanhimmelman/AlamofireObjectMapper/f583be1121dbc5e9b0381b3017718a70c31054f7/sample_array_json"
Alamofire.request(URL).responseArray { (response: DataResponse<[Forecast]>) in
let forecastArray = response.result.value
if let forecastArray = forecastArray {
for forecast in forecastArray {
print(forecast.day)
print(forecast.temperature)
}
}
}
```
# Installation
AlamofireObjectMapper can be added to your project using [CocoaPods](https://cocoapods.org/) by adding the following line to your Podfile:
```
pod 'AlamofireObjectMapper', '~> 5.0'
```
If you're using [Carthage](https://github.com/Carthage/Carthage) you can add a dependency on AlamofireObjectMapper by adding it to your Cartfile:
```
github "tristanhimmelman/AlamofireObjectMapper" ~> 5.0
```