- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
我终于从 Objective-C 转向了 Swift。我正在为我的客户创建一个 View 布局系统,使他们的应用程序在布局上更加灵活,而不使用自动布局,因为他们想远程设计他们的屏幕,而自动布局对他们来说太复杂了。我尝试使用 structs
和 protocols
来做到这一点,但我发现它很笨拙,所以我怀疑我没有以正确的方式思考它。
对于类,结构如下:
class ViewModel {
var frame: CGRect = .zero
}
class ViewGroupModel: ViewModel {
var weight: Int = 1
var children:[ViewModel] = [ViewModel]()
}
class HorizontalViewGroupModel: ViewGroupModel {
}
class VerticalViewGroupModel: ViewGroupModel {
}
我试图通过定义一个 ViewModel
协议(protocol)和一个 ViewGroupModel
协议(protocol)来使用协议(protocol)来处理它,但我发现它创建了很多重复(属性)。有更好的方法吗?在这种情况下使用类会被认为是一种好的做法吗?
编辑:如果不使用类会更好,我正在寻找一个答案,在 structs
和 protocols
方面给我一个具体的解决方案。
最佳答案
如果问题仅仅是如何实现协议(protocol)的属性,我不一定会让那影响我在 struct
与 class
之间的选择。如果您的 struct
类型必须实现各种属性,您有两个基本选择:
如果您谈论的是几个属性,只需在符合该协议(protocol)的 struct
类型中实现这几个属性即可。我们一直这样做。例如。在定义符合 MKAnnotation
的自定义类型时,我们只需实现三个必需的属性。
当然,如果我们讨论的是一组更大的属性,这会变得乏味,但编译器会在整个过程中牵着我们的手,确保我们不会遗漏任何东西。所以挑战相当小。
虽然我不喜欢这种方法,https://stackoverflow.com/a/38885813/1271826表明您可以将共享属性实现为一个组件,其中您有 struct
来包装所有这些属性,然后在扩展中为您的协议(protocol)实现默认计算属性:
enum SubviewArrangement {
case none
case horizontal
case vertical
case flow
}
struct ViewComponent {
var frame = CGRect.zero
var weight = 1
var subviews = [ViewModel]()
var subviewArrangement = SubviewArrangement.none
}
protocol HasViewComponent {
var viewComponent: ViewComponent { get set }
}
protocol ViewModel: HasViewComponent { }
extension ViewModel {
var frame: CGRect {
get { return viewComponent.frame }
set { viewComponent.frame = newValue }
}
var weight: Int {
get { return viewComponent.weight }
set { viewComponent.weight = newValue }
}
var subviews: [ViewModel] {
get { return viewComponent.subviews }
set { viewComponent.subviews = newValue }
}
var subviewArrangement: SubviewArrangement {
get { return viewComponent.subviewArrangement }
set { viewComponent.subviewArrangement = newValue }
}
}
在那里,您可以创建一个符合 ViewModel
的实例,如下所示:
struct LabelModel: ViewModel {
var viewComponent = ViewComponent()
}
var label = LabelModel()
label.weight = 2
print(label.weight)
我必须承认,这不是最优雅的方法。 (我什至不愿展示它。)但它避免了必须在符合 ViewModel
的类型中单独实现所有这些属性。
所以,让我们把属性问题放在一边。真正的问题是您应该使用值类型 (struct
) 还是引用类型 (class
)。我认为在 Protocol-Oriented Programming in Swift 接近尾声 (@42:15) 时考虑 Apple 关于值(value)与引用语义的讨论很有启发性。视频。他们触及了您实际上可能仍想使用类的那些情况。例如,他们建议您可能希望在“复制或比较实例没有意义”时使用引用类型。他们建议在处理“Window”实例时可以应用此规则。这同样适用于此。
最重要的是,在我看来,使用值类型来表示 View 层次结构并没有多大好处, View 层次结构是引用类型对象的集合。这只会让人更加困惑。我会坚持使用 class
类型,因为它会准确地反射(reflect)它所代表的 View 层次结构。
不要误会我的意思:我们已经习惯使用引用类型,所以我认为挑战我们先入为主的观念并仔细研究值类型是否可以更好地解决这种情况总是好的。不过,在这种情况下,我根本不会担心它,只是坚持使用反射(reflect)您正在建模的那些对象的层次结构的 class
层次结构。
话虽如此,您在问题中提出的类层次结构也感觉不太对。感觉很奇怪,你实际上可以实例化一个 ViewModel
,你以后不能添加 subview (而所有 UIView
对象都有 subview
属性)。此外,您的水平和垂直组类型也感觉不正确。例如,它是否应该是具有某些“轴”属性的单一类型,如 UIStackView
或其他一些“排列”属性,以扩大捕获 UICollectionView
布局的概念?。正如您将在我上面的 ViewComponent
示例中看到的那样,考虑到这两个注意事项,我将其扁平化了一点,但是您可以按照自己认为合适的方式进行操作。
关于ios - Swift:构建还是不构建,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45376913/
有没有办法在 .swift 文件(编译成 .swift 模块)中声明函数,如下所示: 你好.swift func hello_world() { println("hello world")
我正在尝试使用 xmpp_messenger_ios 和 XMPPFramework 在 iOS 上执行 MUC 这是加入房间的代码。 func createOrJoinRoomOnXMPP()
我想在我的应用程序上创建一个 3D Touch 快捷方式,我已经完成了有关快捷方式本身的所有操作,它显示正确,带有文本和图标。 当我运行这个快捷方式时,我的应用程序崩溃了,因为 AppDelegate
我的代码如下: let assetTag = Expression("asset_tag") let query2 = mdm.select(mdm[assetTag],os, mac, lastRe
我的 swift 代码如下所示 Family.arrayTuple:[(String,String)]? = [] Family.arrayTupleStorage:String? Family.ar
这是我的 JSON,当我读取 ord 和 uniq 数据时出现错误 let response2 : [String: Any] = ["Response":["status":"SUCCESS","
我想将 swift 扩展文件移动到 swift 包中。但是,将文件移动到 swift 包后,我遇到了这种错误: "Type 'NSAttributedString' has no member 'ma
使用CocoaPods,我们可以设置以下配置: pod 'SourceModel', :configurations => ['Debug'] 有什么方法可以用 Swift Package Manag
我正在 Xcode 中开发一个 swift 项目。我将其称为主要项目。我大部分都在工作。我在日期选择器、日期范围和日期数学方面遇到了麻烦,因此我开始了另一个名为 StarEndDate 的项目,其中只
这是 ObjectiveC 代码: CCSprite *progress = [CCSprite spriteWithImageNamed:@"progress.png"]; mProgressBar
我正在创建一个命令行工具,在 Xcode 中使用 Swift。我想使用一个类似于 grunt 的配置文件确实如此,但我希望它是像 Swift 包管理器的 package.swift 文件那样的快速代码
我假设这意味着使用系统上安装的任何 swift 运行脚本:#!/usr/bin/swift 如何指定脚本适用的解释器版本? 最佳答案 Cato可用于此: #!/usr/bin/env cato 1.2
代码说完全没问题,没有错误,但是当我去运行模拟器的时候,会出现这样的字样: (Swift.LazyMapCollection (_base:[ ] 我正在尝试创建一个显示报价的报价应用。 这是导入
是否可以在运行 Swift(例如 Perfect、Vapor、Kitura 等)的服务器上使用 RealmSwift 并使用它来存储数据? (我正在考虑尝试将其作为另一种解决方案的替代方案,例如 no
我刚开始学习编程,正在尝试完成 Swift 编程书中的实验。 它要求““编写一个函数,通过比较两个 Rank 值的原始值来比较它们。” enum Rank: Int { case Ace = 1 ca
在您将此问题标记为重复之前,我检查了 this question 它对我不起作用。 如何修复这个错误: error: SWIFT_VERSION '5.0' is unsupported, suppo
从 Xcode 9.3 开始,我在我的模型中使用“Swift.ImplicitlyUnwrappedOptional.some”包裹了我的字符串变量 我不知道这是怎么发生的,但它毁了我的应用程序! 我
这个问题在这里已经有了答案: How to include .swift file from other .swift file in an immediate mode? (2 个答案) 关闭 6
我正在使用 Swift Package Manager 创建一个应用程序,我需要知道构建项目的配置,即 Debug 或 Release。我试图避免使用 .xcodeproj 文件。请有人让我知道这是否
有一个带有函数定义的文件bar.swift: func bar() { println("bar") } 以及一个以立即模式运行的脚本foo.swift: #!/usr/bin/xcrun s
我是一名优秀的程序员,十分优秀!