介紹

iPerfman-iPhone-screenshot

iPerfman-iPad-screenshot

iPerfman-mac-screenshot

iPerfman-tv-screenshot

iPerfman 是一個 iPerf3工具,支持所有蘋果平台:iOS、iPadOS、macOS和tvOS。

iPerf 系列工具執行測量 IP 網絡上可實現的最大帶寬。

具有漂亮速度儀和速度圖表。

您可以測試局域網網絡速度以找到最佳的WIFI路由器位置。

您可以通過手動設置測試參數來測試更多複雜的網絡,例如可以測試 UDP 模式的性能,並使用帶寬限制功能來模擬具有帶寬限制的網絡環境。

iPerfman 支持中文和英文兩種語言,您可以在設置中選擇您喜歡的語言,便於使用。

總之,iPerfman 是一款強大的網絡測速工具,可以幫助您評估網絡性能,為您提供更優質的網絡體驗。

App Store下載 iPerfman Pro

App Store下載 iPerfman

有任何疑問或者建議,可以通過 Email 聯繫。

隱私政策

本App不進行任何隱私信息收集或上傳。

介绍Introducing

iPerfman-iPhone-screenshot

iPerfman-iPad-screenshot

iPerfman-mac-screenshot

iPerfman-tv-screenshot

iPerfman 是一个 iPerf3工具,支持所有苹果平台:iOS、iPadOS、macOS和tvOS。

iPerf 系列工具执行测量 IP 网络上可实现的最大带宽。

具有漂亮速度仪和速度图表。

您可以测试局域网网络速度以找到最佳的WIFI路由器位置。

您可以通过手动设置测试参数来测试更多复杂的网络,例如可以测试 UDP 模式的性能,并使用带宽限制功能来模拟具有带宽限制的网络环境。

iPerfman 支持中文和英文两种语言,您可以在设置中选择您喜欢的语言,便于使用。

总之,iPerfman 是一款强大的网络测速工具,可以帮助您评估网络性能,为您提供更优质的网络体验。

iPerfman is an iPerf3 tool that supports all apple platforms: iOS, iPadOS, macOS, and tvOS.

The iperf series of tools perform active measurements to determine the maximum achievable bandwidth on IP networks.

Beautiful speedometer and speed chart.

You can test the LAN network speed to find the best WIFI router location.

You can test more complex networks by manually setting test parameters, for example to test the performance of UDP mode, and use the bandwidth-limiting functionality to simulate a bandwidth-constrained network environment.

iPerfman supports both Chinese and English, and you can choose your preferred language in the settings for ease of use.

Overall, iPerfman is a powerful network speed measurement tool that helps you evaluate network performance and provides you with a better network experience.

App Store下载
Download on the App Store

有任何疑问或者建议,可以通过 Email 联系。

If you have any questions or suggestions, you can contact them through Email.

隐私政策Privacy policy

本App不进行任何隐私信息收集或上传。

This App does not collect or upload any private information.

UserDefaults 和 AppStorage 混用时,默认值不统一的问题。因为AppStorage持久化时机不确定,UserDefaults先调用时可能获取的值仍是系统默认值。

解决方案有两种:

1. UserDefaults.standard.object(forKey:) == nil 判断。

1
2
3
if UserDefaults.standard.object(forKey: "hasHapticFeedback") == nil {
UserDefaults.standard.set(true, forKey: "hasHapticFeedback")
}

2. 借助SwiftyUserDefaults,但是对于纯SwiftUI项目,没必要。

1
2
3
4
5
extension DefaultsKeys {
var userColorScheme: DefaultsKey<String> { .init("userColorScheme", defaultValue: "default") }
var userThemeName: DefaultsKey<String?> { .init("userThemeName") }
var userLastLoginDate: DefaultsKey<Date?> { .init("userLastLoginDate") }
}

水平布局时,滚动正常,回车键也能正常退出编辑。底层是UITextField
垂直布局时,底层是UITextView,表现不一致,出现问题。

  1. 焦点问题需要我们滚动时,锚点设为顶部,proxy.scrollTo($0, anchor: .top)
  2. 回车键,退出编辑失效的问题,需要借助toolbar

完整代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import SwiftUI

struct TestNextTextFieldFocus: View {
@State var inputsValues: [String] = (0..<30).map { i in
"test \(i) TextField axis is \(i % 2 == 0 ? ".vertical" : ".horizontal")"
}

@FocusState var focusedInput: Int?

var body: some View {
ScrollViewReader { proxy in
ScrollView {
LazyVStack {
ForEach(0..<inputsValues.count, id: \.self) { i in
TextField("Value", text: $inputsValues[i], axis: i % 2 == 0 ? .vertical : .horizontal)
.focused($focusedInput, equals: i)
.submitLabel(.return)
.id(i)
.onSubmit {
print("submit \(i)")
// update state here !!
if (i + 1) < inputsValues.count {
focusedInput = i + 1
} else {
focusedInput = nil
}
}
}
}
.onChange(of: focusedInput) {
print("onChange focusedInput:\(String(describing: focusedInput))")
// react on state change here !!
proxy.scrollTo($0, anchor: .top)
}
}
.toolbar {
ToolbarItemGroup(placement: .keyboard) {
Spacer()
Button {
focusedInput = nil
} label: {
Text("Done")
}
}
}
}
}
}

struct TestNextTextFieldFocus_Previews: PreviewProvider {
static var previews: some View {
TestNextTextFieldFocus()
}
}

介绍Introducing

Mountpaper-iPhone-screenshot1
Mountpaper-iPad-screenshot1
Mountpaper-mac-screenshot1

裱纸是装裱壁纸的意思。提供许多高质量壁纸。

Mountpaper is meaning of mount wallpaper. Offer a lot of high quality wallpapers.

下载地址 Download on:App Store

有任何疑问或者建议,可以通过 Email 联系。

If you have any questions or suggestions, you can contact them through Email.

隐私政策Privacy policy

本App不进行任何隐私信息收集或上传。

This App does not collect or upload any private information.

SwiftyModel-mac-preview

介绍Introducing

使用 SwiftyJSON 生成在 Swift 语言中支持 SwiftyJSON 的 Model(模型)。

一键复制和分享代码。

Use SwiftyJSON to generate models that support SwiftyJSON in Swift Language.

One-click to copy or share code.

例如输入以下JSON:

For example, enter the following JSON:

1
2
3
4
5
6
7
8
9
10
{
"id" : 1,
"name" : "Jacky",
"notifications" : false,
"pets" : [
"cat",
"dog"
]
}

输出Swift Model:

Output Swift Model:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
import Foundation
import SwiftyJSON

struct NewModel {
let id: Int
let name: String
let notifications: Bool
let pets: [String]

init(json: JSON) {
id = json["id"].intValue
name = json["name"].stringValue
notifications = json["notifications"].boolValue
pets = json["pets"].arrayValue.map { $0.stringValue }
}
}

下载地址:App Store

App Store下载
Download on the App Store

有任何疑问或者建议,可以通过 Email 联系。

If you have any questions or suggestions, you can contact them through Email.

隐私政策Privacy policy

本App不进行任何隐私信息收集或上传。

This App does not collect or upload any private information.

subscriptions-mac-preview

介绍

  1. 轻松记录全部订阅账单。

  2. 统计平均每日、每周、每月和每年花费。

  3. 支持iCloud同步全设备。

下载地址:App Store

有任何疑问或者建议,可以通过 Email 联系。

隐私政策

本隐私政策描述了我们如何收集,使用和披露与服务有关的个人信息,您通过访问服务即表示同意。“个人信息”是指有关可识别个人的信息,但不包括商业信息。

收集哪些信息

阅账希望使您与我们的体验令人满意且安全。我们的数据收集政策使您可以选择向我们提供多少个人信息,并控制我们如何使用这些信息。我们的目标是为您提供满意的体验,同时让您控制自己的隐私。阅账收集和使用信息主要是为了使您使用我们的服务更轻松,更有意义。如果您选择向我们注册,则可能会在不同时间要求您提供信息,我们将竭尽所能使阅账满足您的服务并只为您提供所需的内容。

收集的信息与用途

为识别您的设备 ID 并预防恶意程序、提高服务安全性、保障运营质量及效率,我们使用的第三方平台包括Firebase 会收集您的设备信息(包括IMEI、MEID、IMSI、GUID、MAC地址)、您安装的应用信息或运行中的进程信息。

匿名信息是指无法与特定个人联系在一起的信息,我们不知道您的姓名,住处或出生日期。匿名信息可能以多种方式收集,包括通过使用 Cookie,网络信标或从您使用的设备中收集。

第三方分析工具

我们的服务可能包含来自我们服务提供商的第三方跟踪以及数据收集和分析工具,例如 Google Analytics(分析)和 Google Firebase 。此类第三方可以在我们的服务中使用 Cookie,API 和 SDK,以使他们能够代表我们收集和分析与用户和设备相关的数据和信息。第三方可能会访问并收集有关您的数据和信息,例如您的设备标识符(包括IMEI、MEID、IMSI、GUID、MAC地址及其他相关信息),语言环境(使用特定语言的特定位置),地理位置信息,IP 地址,应用程序使用情况,访问权限和会话时间,传感器数据,设备上存在的或在设备上特定时间使用的应用程序以及您对广告的观看和互动,以提供其服务,包括例如启用,提供和投放广告在下面有更详细的说明。

我们的服务提供商的隐私政策可能包括有关其数据收集和使用惯例以及跟踪技术的其他条款和披露,我们鼓励您检查这些隐私政策以了解有关其数据收集和使用惯例以及 Cookie 的使用的更多信息以及其他类似的跟踪技术。

为识别您的设备 ID 并预防恶意程序、提高服务安全性、保障运营质量及效率,我们使用的第三方平台将获取设备序列号。

第三方广告合作伙伴

我们与各种广告商,广告网络,广告服务器和分析公司合作。这些广告商,广告网络,广告服务器和分析公司使用各种技术以及第三方公司的技术来收集数据,以便向您和其他用户发送(或投放)相关广告。这些技术可能包括放置Cookie或网络信标,使用唯一或非唯一的非个人标识符,或在我们的服务上使用其他技术,并且这些技术可用于跟踪用户行为,跟踪我们如何服务正在使用中,有可能为您提供更多相关的广告。这些目标广告可能会出现在我们的服务或您访问的其他服务上。本隐私政策不涵盖广告商,广告网络,广告服务器和分析公司对各种技术的使用。这些公司还可能从您从其他公司使用的服务中获取信息,这些服务包括但不限于其他网站,移动网站,可移动下载的应用程序和可下载的桌面应用程序,并将这些信息与他们通过我们的服务通过这些第三方技术获取的信息结合在一起。您应该意识到,我们无法控制这些第三方技术或其中包含的信息。

更新

阅账可以随时修改本隐私政策。请经常检查是否有任何更改。继续使用服务,即表示您接受本隐私政策的所有更新。此版本于 2023 年 02 月 01 日更新。

联系我们

我们希望此声明能为您提供丰富而清晰的信息。如果您有任何疑问或进一步的信息,请给我们发送电子邮件。

App 与服务反馈: 531sunlight@gmail.com

机器配置

主板:微星 MSI MPG Z390 GAMING PRO CARBON AC

CPU:Intel i9 9900K

内存:科赋 DDR4 3200 16G*4

显卡:华硕 ASUS AREZ-STRIX-RXVEGA64-O8G-GAMING

电源:EVGA SuperNOVA 750 G+

散热:MASTERLIQUID ML240R RGB

固态:三星 970 EVO 500G

板载声卡:ALC S1220A

板载有线网卡:Intel I219V7

无线网卡和蓝牙:BCM94360CD

显示器:戴尔 P2715Q 4K显示器

机箱:追风者 PK-515ETG

具体步骤

  1. 替换Clover为Open Core v0.6.2,感谢 pOH7/hackintosh-z390-h-9700kuzh 的EFI。
  2. 下载并升级Big Sur,重启几次后,无法进入Big Sur的安装界面。
  3. 升级Open Core v0.6.3,感谢 Ryzentosh Big Sur Updating OpenCore From 0.6.2 to 0.6.3
    1. 打开OpenCore Sanity Checker ,拖进config.plist,根据建议修改。
    2. 下载OpenCorePkgWhateverGreenVirtualSMCLilu 并替换。其中OpenCore只需要替换EFI/OC/OpenCore.efiEFI/BOOT/BOOTx64.efi
  4. 顺利进入Big Sur的安装界面,升级成功🎉
  5. EFI下载地址: [Big Sur Open Core 0.6.3 EFI 20201114.zip](https://github.com/gewill/Hackintosh-Installation-with-MSI-Z390-and-i9-9900K/blob/master/Big Sur Open Core 0.6.3 EFI 20201114.zip)

Hackintosh-Big-Sur

已知问题

  1. USB 2.0 不可用,需USB定制。
  2. 硬件加速不可用,BIOS集成显卡打开即可硬件加速。

Hardware-Acceleration-On-Big-Sur

Array.swift

Using a negative number or an index equal to or greater than count triggers a runtime error.

使用负数或大于等于count的索引会触发运行时错误。

1
print(emptyDoubles[0])

ClosedRange.swift

An equivalent range must be representable as a closed range. For example, passing an empty range as other triggers a runtime error, because an empty range cannot be represented by a closed range instance.

等效范围必须可以表示为闭合范围。例如,将空范围作为 other 传递会触发运行时错误,因为空范围不能由封闭范围实例表示。

1
2
let emptyRange = 0..<0
ClosedRange(emptyRange)

Dictionary.swift

Passing a sequence with duplicate keys to this initializer results in a runtime error. If your sequence might have duplicate keys, use the Dictionary(_:uniquingKeysWith:) initializer instead.

向此构造器传递具有重复键的序列会导致运行时错误。如果序列可能有重复的键,则使用Dictionary(_:uniquingKeysWith:) 初始化。

1
2
3
let digitWords = ["one", "two", "three", "four", "five"]
let wordToValue = Dictionary(uniqueKeysWithValues: zip(digitWords, 1 ... 5))
let wordToValueAndRemoveDuplicateKeys = Dictionary(zip(["one", "one", "three", "four", "five"], 1 ... 5)) { max($0, $1) }

DictionaryCasting.swift

1
2
var dic: [String: Any] = ["name": "li", "age": 18]
dic as! [String: String]

Integers.swift

When the additive inverse of a value is unrepresentable in a conforming type, the operation should either trap or return an exceptional value. For example, using the negation operator (prefix -) with Int.min results in a runtime error.

当一个值的负值在一个符合类型中不可表示时,操作应该捕获或返回一个异常值。例如,将否定运算符(前缀-)与 Int.min一起使用会导致运行时错误。

1
2
3
4
5
6
7
8
9
10
11
12
13
let x = Int.min
let y = -x
// Overflow error

let z = -Int8.min
// Overflow error

var y = Int8.min
y.negate()
// Overflow error

let z = UInt32(-500)
// Error

Optional.swift

In debug builds (-Onone), the unsafelyUnwrapped property has the same behavior as using the postfix ! operator and triggers a runtime error if the instance is nil.

在调试版本(-Onone)中,unsafelyUnwrapped属性的行为与使用后缀的行为相同!如果实例为 nil ,则触发运行时错误。谨慎使用

1
2
3
let optionalInt: Int? = nil
optionalInt.unsafelyUnwrapped
optionalInt!

Policy.swift

If you have prior knowledge that an AnyObject instance has a particular type, you can use the unconditional downcast operator (as!). Performing an invalid cast triggers a runtime error.

如果您事先知道AnyObject实例具有特定的类型,则可以使用无条件向下转换运算符(as)。 执行无效强制转换会触发运行时错误。

1
2
3
4
5
let message = s as! String
print("Successful cast to String: \(message)")
// Prints "Successful cast to String: This is a bridged string."
let badCase = v as! String
// Runtime error

Range.swift

An equivalent range must be representable as an instance of Range. For example, passing a closed range with an upper bound of Int.max triggers a runtime error, because the resulting half-open range would require an upper bound of Int.max + 1, which is not representable as

范围边界值越界会触发运行时错误,如设置最大值为Int.max时。

1
Range(0 ... Int.max)

Always use the slice’s startIndex property instead of assuming that its indices start at a particular value. Attempting to access an element by using an index outside the bounds of the slice’s indices may result in a runtime error, even if that index is valid for the original collection.

始终使用 slice 的startIndex属性,而不是假设它的索引以特定的值开始。试图通过在slice索引的边界之外使用索引来访问元素可能会导致运行时错误,即使该索引对原始集合有效。

1
2
3
4
5
6
7
8
9
10
11
let streets = ["Adams", "Bryant", "Channing", "Douglas", "Evarts"]
let streetsSlice = streets[2...]
print(streetsSlice)
// ["Channing", "Douglas", "Evarts"]

print(streetsSlice.startIndex)
// 2
print(streetsSlice[2])
// "Channing"
print(streetsSlice[0])
// error: Index out of bounds

RangeReplaceableCollection.swift

Attempting to remove more elements than exist in the collection triggers a runtime error.

尝试移除集合中存在的元素数目多于存在的元素会触发运行时错误。

1
2
3
var array = Array(0 ..< 5)
array.removeFirst(6)
array.removeLast(6)

SetCasting.swift

We can’t just delegate to _setDownCastConditional here because we rely on as! to generate nice runtime errors when the downcast fails.

Set 向下强制转换失败时,会产生运行时错误。

1
2
var s: Set<AnyHashable> = [1, 2, "3"]
s as! Set<Int>

StaticString.swift

1
2
3
4
5
6
7
8
9
10
11
// * a pointer to a null-terminated sequence of UTF-8 code units:
let emoji: StaticString = "\u{1F600}"
emoji.hasPointerRepresentation // -> true
emoji.isASCII // -> false
// emoji.unicodeScalar // -> Fatal error!
emoji.utf8CodeUnitCount // -> 4
emoji.utf8Start[0] // -> 0xF0
emoji.utf8Start[1] // -> 0x9F
emoji.utf8Start[2] // -> 0x98
emoji.utf8Start[3] // -> 0x80
emoji.utf8Start[4] // -> 0x00
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// * a single Unicode scalar value, under very limited circumstances:
struct MyStaticScalar: ExpressibleByUnicodeScalarLiteral {
typealias UnicodeScalarLiteralType = StaticString
let value: StaticString
init(unicodeScalarLiteral value: StaticString) {
self.value = value
}
}

let emoji: StaticString = MyStaticScalar("\u{1F600}").value
emoji.hasPointerRepresentation // -> false
emoji.isASCII // -> false
emoji.unicodeScalar.value // -> 0x1F600
emoji.utf8CodeUnitCount // -> Fatal error!
emoji.utf8Start // -> Fatal error!

hasPointerRepresentation 一个布尔值,表示静态字符串是否存储指向以 null 结尾的 UTF-8代码单元序列的指针。

  • true:这时访问unicodeScalar会触发运行时错误;
  • false:静态字符串存储单个 Unicode 标量值。这时访问utf8开头的属性会触发运行时错误;

第三部分:树

第十章:树

树在数据结构中相当重要。它用于解决软件开发中的许多反复出现的挑战:

  • 表示层次关系。

  • 管理排序的数据。

  • 促进快速查找操作。

相关术语

  • 节点(Node)
  • 父子(Parent and child)
  • 根(Root)
  • 叶子(Leaf)

实现

1
2
3
4
5
6
7
8
9
10
11
12
13
public class TreeNode<T> {

public var value: T
public var children: [TreeNode] = []

public init(_ value: T) {
self.value = value
}

public func add(_ child: TreeNode) {
children.append(child)
}
}

遍历算法

遍历线性的集合(如:数组和链表)是非常直接的。因为有直接的首尾。

但是遍历树就复杂了。是左边优先,还是深度优先,要看具体解决的问题。

深度优先遍历(Depth-first traversal)
1
2
3
4
5
6
7
8
extension TreeNode {
public func forEachDepthFirst(visit: (TreeNode) -> Void) {
visit(self)
children.forEach {
$0.forEachDepthFirst(visit: visit)
}
}
}
层级优先遍历(Level-order traversal)
1
2
3
4
5
6
7
8
9
10
11
extension TreeNode {
public func forEachLevelOrder(visit: (TreeNode) -> Void) {
visit(self)
var queue = Queue<TreeNode>()
children.forEach { queue.enqueue($0) }
while let node = queue.dequeue() {
visit(node)
node.children.forEach { queue.enqueue($0) }
}
}
}
搜索
1
2
3
4
5
6
7
8
9
10
11
extension TreeNode where T: Equatable {
public func search(_ value: T) -> TreeNode? {
var result: TreeNode?
forEachDepthFirst { node in
if node.value == value {
result = node
}
}
return result
}
}

总结

  1. 树与链接列表具有一些相似之处,但是,链接列表节点只能链接到另一个节点,而树节点可以链接到无限多个节点。
  2. 熟悉树的术语,例如父,子,叶子和根。 这些术语中有许多是其他程序员常用的语言,将用于帮助解释其他树形结构。
  3. 遍历(例如深度优先遍历和层级遍历)不是特定于常规树的。 它们也可以在其他树上工作,尽管根据树的结构,它们的实现会略有不同。

第十一章:树挑战

打印所有的值,按照他们层级的顺序。同意层级应该打印在一行

例如:

1
2
3
15 
1 17 20
1 5 0 2 5 7

实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
func printEachLevel<T>(for tree: TreeNode<T>) {
var queue = Queue<TreeNode<T>>()

/// 加入每层的节点计数,当打印完时,换行
var nodesLeftInCurrentLevel = 0

queue.enqueue(tree)
while !queue.isEmpty {
nodesLeftInCurrentLevel = queue.count
while nodesLeftInCurrentLevel > 0 {
guard let node = queue.dequeue() else { break }
print("\(node.value) ", terminator: "")
node.children.forEach { queue.enqueue($0) }
nodesLeftInCurrentLevel -= 1
}
print()
}
}
0%