从RxSwift4开始,Variable
移动到Deprecated.swift
标记Variable
未来可能的弃用.建议的替代方案Variable
是BehaviorRelay
.在发布这个问题时,由于我在网上找不到太多的教程,BehaviorRelay
我在SO中发布了这样一个基本问题.
假设我正在进行webService调用,并且我收到一块JSONArray数据,在逐个解析JSON对象时我更新了我的Variable的value属性
这是我的变量声明
var myFilter = Variable<[MyFilterModel]>([MyFilterModel(data: "{:}")])
Run Code Online (Sandbox Code Playgroud)
每次我将变量更新为获取新元素时
myFilter.value.append(newModel)
Run Code Online (Sandbox Code Playgroud)
当Variable绑定到CollectionView时,collectionVie将立即使用新添加的对象更新其UI.
使用BehaviorRelay的问题
现在我的声明看起来像
var myFilter = BehaviorRelay<[MyFilterModel]>(value: [MyFilterModel(data: "{:}")])
Run Code Online (Sandbox Code Playgroud)
但最大的问题myFilter.value
是readOnly.很明显
myFilter.value.append(newModel)
Run Code Online (Sandbox Code Playgroud)
不是解决方案.我发现我可以使用accept
.
但是现在当我尝试解析响应中的每个元素并更新myFilter的值时
self?.expertsFilter.accept(newModel)
Run Code Online (Sandbox Code Playgroud)
上面的陈述给出了错误引用
无法将NewModel的值转换为预期的争论类型[NewModel]
显然,它期待一个数组而不是一个单独的元素.
解决方法:
解决方案1:
因此,一个解决方案是在临时数组中累积所有响应并且一旦完成触发 self?.expertsFilter.accept(temporary_array)
解决方案2:
如果我必须onNext
在解析每个元素时向订阅者发送事件,我需要将self?.expertsFilter的值复制到new Array,将新解析的元素添加到它并返回新数组.
解决方案3:
摆脱BehaviorRelay
并使用BehaviorSubject
/PublishSubject
前两个声音令人沮丧,因为可能需要在解析每个元素时触发UI我不能等到解析整个响应.因此,解决方案1显然没有多大用处.
第二种解决方案更加可怕,因为它每次发送onNext事件时都会创建一个新数组(我知道它是临时的并且将被释放).
题:
因为BehaviorRelay
被提议作为Variable
进入两难的替代方案,我accept
正确使用?有没有更好的方法来解决它?
请帮忙
我从url下载视频文件并使用以下路径将其保存在文档目录中:
let destination: DownloadRequest.DownloadFileDestination = { _, _ in
let pathComponent = "pack\(self.packID)-\(selectRow + 1).mp4"
let directoryURL: URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
let folderPath: URL = directoryURL.appendingPathComponent("Downloads", isDirectory: true)
let fileURL: URL = folderPath.appendingPathComponent(pathComponent)
return (fileURL, [.removePreviousFile, .createIntermediateDirectories])
}
Run Code Online (Sandbox Code Playgroud)
我的视频已下载并成功播放.但是有一个问题,当我在Xcode中重建应用程序并尝试播放我下载的最后一个视频时,视频没有显示,当我下载新视频时,这个保存并成功播放.
我已经看过每个视频包路径,它们是不同的.
1 - file:/// Users/myMac/Library/Developer/CoreSimulator/Devices/EAC2F4CE-EA09-46C0-B403-1CE9E24B6822/data/Containers/Data/Application/1D2C1F7B-E627-4898-91C1-D0AF8D5E0F1E/Documents/Downloads /pack7-1.mp4
2 - file:/// Users/myMac/Library/Developer/CoreSimulator/Devices/EAC2F4CE-EA09-46C0-B403-1CE9E24B6822/data/Containers/Data/Application/F950E9A5-C9F3-4B8C-BCF5-647EEC233CEE/Documents/Downloads /pack7-3.mp4
现在,我的问题是,当我们从App Store更新应用程序时,是否意味着重新安装?这条路是否改变了?
怎么能解决这个问题?
概观
我试图了解Swift的面向协议编程范例.根据Apple的WWDC 2015视频https://developer.apple.com/videos/play/wwdc2015/408/协议可以实现继承所能实现的一切,并且还解决了继承的根本问题.
虽然协议通过将每个功能(功能)捕获为协议并允许类/结构确认多个协议来解决多重继承的问题,但我认为协议永远不能替代继承,原因如下.
让我们假设我正在实施学院/学校自动化软件,并且有两个实体,工作人员和校长,我们假设他们都上课但是校长以及课程控制员工.
所以我创建了一个协议,它将模拟正在上课的常用功能.所以让我们创建一个协议.
protocol staffProtocol {
var classHour : Int { get set}
var numberOfClass : Int? { get set }
mutating func doesWork()
}
extension staffProtocol {
mutating func doesWork(){
classHour = 9
numberOfClass = 4
print("Takes calss")
}
}
Run Code Online (Sandbox Code Playgroud)
由于Take class是工作人员和校长的共同任务所以我提供了一个默认扩展,它提供了一个实现,doesWork()
并说类需要.
现在让我们编写一个Staff结构,它将向staffProtocol确认,
struct Staff : staffProtocol {
var classHour: Int = 0
var numberOfClass: Int? = 0
}
Run Code Online (Sandbox Code Playgroud)
现在,如果我创建一个staff对象
var staff = Staff()
staff.doesWork()
Run Code Online (Sandbox Code Playgroud)
一切都运行得很好,现在让我们创建一个Principal结构,它也将扩展staffProtocol,
struct Principal : staffProtocol {
var …
Run Code Online (Sandbox Code Playgroud) 我正在尝试深度复制Swift类实例.由于copy
和mutableCopy
函数仅适用于NSObject
类后代,我需要为Swift类对象实现我自己的copy函数.
这是我做的,
protocol Copying {
init(original: Self)
}
extension Copying {
func copy() -> Self {
return Self.init(original: self)
}
}
class A : Copying {
var name : String? = nil
var age : Int? = nil
var address : String? = nil
init(name : String) {
self.name = name
}
required init(original: A) {
//one way
self.name = original.name
self.age = original.age
self.address = original.address
//second way
let originalReflect = Mirror(reflecting: original) …
Run Code Online (Sandbox Code Playgroud) 我正试图每秒重新加载我的tableview.我现在重新加载tableview对象,但由于我Order
在重新加载之前清除数组,因为索引超出范围而崩溃.
这是我目前的代码
var orders = [Order]()
override func viewDidLoad() {
super.viewDidLoad()
// table stuff
tableview.dataSource = self
tableview.delegate = self
// update orders
var timer = Timer.scheduledTimer(timeInterval: 4, target: self, selector: "GetOrders", userInfo: nil, repeats: true)
GetOrders()
}
func numberOfSections(in tableView: UITableView) -> Int {
if orders.count > 0 {
self.tableview.backgroundView = nil
self.tableview.separatorStyle = .singleLine
return 1
}
let rect = CGRect(x: 0,
y: 0,
width: self.tableview.bounds.size.width,
height: self.tableview.bounds.size.height)
let noDataLabel: UILabel = UILabel(frame: rect)
noDataLabel.text = …
Run Code Online (Sandbox Code Playgroud) PS:
这不是一个自以为是的问题。在VIPER中连接各种模块是一个合理的疑问。这是一个理论问题,因此没有附加任何代码。我只需要知道在这种特定情况下如何连接View-Presenter-Router,而不会违反VIPER
我是第一次尝试与VIPER接触。这是我对VIPER的基本了解。
视图:应该显示UI控件并捕获IBActions
并调用其演示者的委托方法来处理事件
演示者:将处理所有与UI相关的数据,并准备进行渲染的数据并将其移交给View。每当需要屏幕转换时,它将调用其路由器并要求路由器执行转换
PS: Presenter中将没有任何UIComponent。因此import UIKit
,主持人中没有任何发言。
路由器:负责执行屏幕转换,通常在线框的帮助下进行(可选,但最好在应用中使用此类)
Interactor:包含所有业务逻辑。只要需要基于业务逻辑进行处理,Presenter就会调用Interactor。
实体: POJO类(简单的Swift对象或Core数据实体)。
现在出现问题:
如果我的假设是正确的,那么Presenter应该是没有UIKit
访问权限的普通Swift类。
如果为true,则假设我按了自己的按钮,ViewControllerA
并且需要ViewControllerB
在其顶部按另一个按钮,显然ViewControllerA
会与之交谈PresenterA
并告知该按钮已被轻按,现在PresenterA
应该RouterA
与之交谈并告诉其按入ViewControllerB
。
因为Router可以访问,UIKit
所以我可以ViewControllerB
使用Storyboard实例或通过xib 轻松创建一个新实例,但是为了推送该实例,我需要ViewControllerA的实例。
但是PresenterA
不能包含对函数的引用ViewControllerA
或将其作为参数传递给PresenterA
in函数,因为UIViewController
属于UIKit
和Presenters不应具有UI语句。
我可能想到的解决方案:
解决方案1:
在创建Router实例时,将相应的ViewController
实例作为其init(依赖注入阶段)的一部分传递,以这种方式,Router将始终引用其所属的ViewController
解决方案2:
让Router声明其协议并在ViewController中实现它,并且每当需要引用ViewController时,都使用Router的委托。但这与VIPER的规则矛盾,即路由器不应与View对话。
我在想什么吗 我的假设对吗?如果是,解决此问题的正确方法是什么,请提出建议
背景:
iOS14 引入了一种新的方式来注册和配置 collectionViewCell 和在CollectionView 中的列表中WWDC 视频苹果开发人员表示默认情况下会自动调整大小UICollectionViewListCell
,我们不必明确指定单元格的高度。如果我在各种配置中使用系统列表单元格,这很有效,但是当我将它与UICollectionViewListCell
我尝试了什么?
iOS 14 引入了一种配置单元格的新方法,我们不直接访问单元格组件来设置我们使用的各种 UI 属性评估器content configuration
以及background configuration
更新/配置单元格。当我们使用自定义单元格时,这变得有点棘手。
CustomSkillListCollectionViewCell
class CustomSkillListCollectionViewCell: UICollectionViewListCell {
var skillLavel: String? {
didSet {
setNeedsUpdateConfiguration()
}
}
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func updateConfiguration(using state: UICellConfigurationState) {
backgroundConfiguration = SkillListViewBackgroundConfiguration.getBackgroundConfiguration(for: state)
var content = SkillListViewContentConfiguration().updated(for: state)
content.label = skillLavel
contentConfiguration = content
}
}
Run Code Online (Sandbox Code Playgroud)
技能列表视图背景配置
struct SkillListViewBackgroundConfiguration {
@available(iOS 14.0, *)
static func getBackgroundConfiguration(for …
Run Code Online (Sandbox Code Playgroud) 我有近4年的Objective C经验和快速新手.我试图从Objective C的角度理解swift的概念.所以,如果我错了,请指导我:)
在目标c中,我们有块(可以在以后异步执行的代码块),这绝对是完美的意义.但是现在我们可以将一个函数作为参数传递给另一个函数,这个函数可以在以后执行,然后我们也可以关闭它.
根据Apple "功能是特殊情况的条款."
根据O'Reilly的 说法,"当函数作为值传递时,它会携带对外部变量的内部引用.这就是使函数成为闭包的原因."
所以我试了一下就明白了:)
这是我的关闭
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a ni
let tempNumber : Int = 5
let numbers = [1,2,3,4,5]
print (numbers.map({ $0 - tempNumber}))
}
Run Code Online (Sandbox Code Playgroud)
变量tempNumber甚至在声明闭包之前就被声明,但是闭包可以访问变量.现在而不是地图,我尝试使用自定义类传递闭包作为参数并尝试执行相同的代码:)虽然现在关闭在不同的范围内执行,但它仍然可以访问tempNumber.
我得出结论:闭包可以访问变量和方法,这些变量和方法在与自己封闭相同的范围内声明,尽管它在不同的范围内被执行.
现在而不是将关闭作为参数传递,尝试将函数作为参数传递,
class test {
func testFunctionAsParameter(testMethod : (Int) -> Int){
let seconds = 4.0
let delay = seconds * Double(NSEC_PER_SEC) // nanoseconds per seconds
let dispatchTime = dispatch_time(DISPATCH_TIME_NOW, Int64(delay))
dispatch_after(dispatchTime, dispatch_get_main_queue(), { …
Run Code Online (Sandbox Code Playgroud) 我正在尝试放置一个循环进度条,最初以不确定模式启动它,一旦下载开始并且进度可用,就将其转换为确定模式并设置其进度.使用样式progressBarStyleHorizontal时,代码工作正常,一旦我将其更改为progressBarStyleInverse设置,进度无效.进度条开始不确定并持续不变.
让我感到惊讶的是设置android:xml中的indeterminate = false也没有效果.
这是xml中进度条的声明
<ProgressBar
style="?android:attr/progressBarStyleHorizontal"
android:indeterminate="false"
android:layout_gravity = "center"
android:layout_height="wrap_content"
android:layout_width="wrap_content"/>
Run Code Online (Sandbox Code Playgroud)
这是我更新进度条进度的方法.显然我有一个id我已经在xml粘贴中删除了它.我有使用findViewById的进度条的参考.(如果您认为这是问题,参考进度条不是问题)
holder.progressbar.setIndeterminate(false);
holder.progressbar.invalidate();
holder.progressbar.setProgress(/*value */);
Run Code Online (Sandbox Code Playgroud)
我犯了什么错误?请帮忙.我在这个问题上浪费了近5个小时.请帮忙.
提前致谢.
我正在尝试折叠/合并属于我应用程序中同一事件的多个通知。iOS 10在有效负载中引入了键名apns-collapse-id。文档说具有相同的多个远程通知apns-collapse-id
将合并并显示为单个通知。
因此,我们的通知有效负载中包含apns-collapse-id
和thread-id
。不幸的是,由于在线上没有太多内容解释这些键的实际工作方式,因此为了安全起见,我们为apns-collapse-id
和使用了相同的唯一值thread-id
。
我们期望与之apns-collapse-id
合并的多个远程通知。这没有发生。
很少有人认为APNS崩溃不是免费的,我必须UNNotificationContentExtension
手动实施和处理通知。我知道我可以添加和删除已经发布的本地通知,但是不确定如何更新已经发布的远程通知。
这是我们的有效载荷的样子
payload {
"aps": {
"alert": {
"title": "Some title : ",
"body": "Some body text"
},
"sound": "default",
"payload": {
"target": {
"some key" : "Some value"
},
"thread_id": "Some_string_155863",
},
"apns-collapse-id": "Some_string_155863",
"mutable-content": 1,
"thread-id": "Some_string_155863",
"badge": 33
},
"thread-id": "Some_string_155863",
"apns-collapse-id": "Some_string_155863",
"mutable-content": 1
}
Run Code Online (Sandbox Code Playgroud)
如您所见,apns-collapse-id和thread-id在JSON中重复了多次,因为我们不确定在哪里准确放置它们
我们尚未使用HTTPS / 2,但我相信iOS 10通知仍支持旧版HTTPS。我不是一个真正的网络人,所以我不太了解这些东西。忽略我对Https和Http2的傲慢态度
是否有人设法使apns-collapse-id起作用?请帮忙。