在 Swift 中多次过滤 weak

如何解决在 Swift 中多次过滤 weak

我对 Swift 或 OOP 一无所知,但我必须构建一个基本的 BLE 扫描仪应用程序。我找到了一个例子,我阅读了它,试图从它的立场去理解和发展。

现在,我有一个这样的功能

 @objc private func startSearch() {
    bluetoothProvider.startScanning()
        .filter { [weak self] newPeripheral in
            guard let self = self else { return false }
            return !self.scannedPeripherals.contains(where: { $0.peripheral.identifier == newPeripheral.peripheral.identifier
            })
        }
    
        .subscribe(onNext: { [weak self] in self?.scannedPeripherals.append($0) })
        .disposed(by: disposeBag)
}

我真的从一周开始什么都没明白,后卫部分......但我想我明白了其他的东西。现在我想至少添加一个其他过滤器,但它看起来不像我可以在教程或示例中找到的任何其他过滤器机制。任何人都可以在这里解释格式或帮助添加另一个过滤器吗?

我试过这些

        .filter { [weak self] filteredPeripheral in
            guard let self = self else { return false }
            return !self.scannedPeripherals.contains(where: { _ in filteredPeripheral.rssi.intValue < 0
            })
                }


        .filter{ [weak self] filteredPeripheral in
            guard let self = self else { return false }
            return !self.scannedPeripherals.contains(where: { $0.peripheral.identifier.uuidString.contains("0863")
            })
                }

但看起来没有任何影响。

解决方法

您当然可以将过滤器链接在一起。根据您的评论,我认为您不需要在第二个或第三个过滤器中对 self 进行任何引用:

@objc private func startSearch()
 {
    // You don't need [weak self]
    bluetoothProvider.startScanning()
    .filter
    { newPeripheral in
        return !self.scannedPeripherals.contains {
            $0.peripheral.identifier == newPeripheral.peripheral.identifier
        }
    }.filter { $0.rssi.intValue >= 0 }
    .filter { $0.peripheral.identifier.uuidString.contains("0863") }
}

由于您不是动态组合过滤器,也没有映射到其间的不同类型,因此通过将它们压缩到一个过滤器中,您会获得稍微更好的性能。

@objc private func startSearch()
 {
    bluetoothProvider.startScanning().filter
    { newPeripheral in
        !self.scannedPeripherals.contains {
            $0.peripheral.identifier == newPeripheral.peripheral.identifier
         }
        && newPeripheral.rssi >= 0
        && peripheral.identifier.uuidString.contains("0863")
    }
}

由于您是 Swift 的新手,所以我想提出一个学习闭包的建议。首先编写一个传递给 filter 的命名函数(或其他采用闭包参数的方法)。让它工作。一旦你让命名函数工作,然后把它变成一个闭包。

您甚至可以更进一步,编写一个循环来执行您希望它执行的操作。循环的主体本质上是将进入您的闭包的内容。然后将循环体移动到一个命名函数中,这样你的循环就为每个元素调用它。当它起作用时,将循环更改为对 filter(或 mapforEach)的调用,并将您的命名函数传递给它。如果可行,请将您的函数更改为闭包。

随着时间的推移,您会对不需要中间折射的瓶盖感到满意。但一开始它很有帮助,因为它从你已经理解的东西开始,并朝着新事物努力。

以防万一你还没有接受它,我还会提到你看到 $0 的地方,这是对传递给闭包的第一个参数的引用,当闭包的定义没有赋值时给它取个名字。在第一个闭包中,忽略不必要的 [weak self],从 newPeripheral in 开始。这为该闭包的参数提供了一个名称,因此您可以通过 newPeripheral 引用它,但是当您调用 contains 时,您将传递另一个嵌套在第一个闭包中的闭包。该嵌套闭包没有命名其参数,因此它使用 $0 来引用它。对于接受多个参数的闭包,还可以有 $1$2 等...

此外,如果您熟悉 C 中“回调”函数的概念,那么这基本上就是闭包经常用于的目的,除了与 C 函数指针不同,它们不必引用命名函数,但可以动态定义,并且闭包可以从周围范围捕获变量。

weak

虽然您的问题实际上不是关于 weakguard,但您提到您不理解它们,所以我想我会简单地解释它们。

[weak self] 是“捕获语法” - 基本上它是一种告诉编译器如何将符号从周围上下文导入到您传递给 filter 的闭包中的方式。在本例中,您将 self 捕获为 weak 引用。

要了解什么是 weak 引用,了解引用是什么很有用。引用是 Swift 引用在堆中动态分配的东西的方式。这样,就像 C 中指针的主要用途。所有原始类型,加上 ArrayDictionaryStringSet 和任何 {{1} } 或 struct 您定义的都是 value 类型,因此对它们进行 enum 引用是没有意义的。事实上,对它们的唯一引用是当它们作为 weak 参数传递时。

除非您涉足 inout 类型家族,否则您可能在 Swift 中使用的唯一引用类型是某种 UnsafePointer

普通引用,通常称为引用,它增加了被引用事物的引用计数。当它超出范围时,它会减少引用计数。当引用计数变为 0 时,它所引用的事物将被取消初始化和释放。这是 Swift 内存管理的核心。

但是,在某些情况下,您可以创建强引用循环。想象一个树数据结构,其中孩子们保持对他们父母的引用。在这种情况下,如果根节点超出范围,则树(如果它不仅仅是一个根节点)将永远不会被释放,因为引用计数永远不会变为 0,因为子节点持有对父节点的强引用。

class 引用是解决该问题的方法,因为它们不会增加引用计数,因此在树数据结构中,您希望每个节点都对其子节点具有强引用,但是weak 对其父级的引用。这样,当树的根超出范围时,整个树都会被释放。同样的想法也适用于双向链表。每个节点都有一个针对其下一个节点的强引用,以及针对其前一个节点的 weak 引用(或者反过来,只要只有一个强引用)。

weak 引用使用 weak 语法,因为当您要访问它时,它们引用的对象可能不存在。

强引用循环也可能发生在称为“转义”闭包的闭包类型中。有时您会在带有闭包参数的函数声明中看到 Optional,通常用于完成处理程序。 “转义”闭包是一个存储起来以备后用的闭包。在这种情况下,闭包内对 @escaping 的任何强引用都可以防止其引用的对象被取消初始化和释放,只要闭包被保存在某处。基本上是内存泄漏。

self 不采用 filter 闭包。它不存储闭包,它在返回之前调用它,然后就完成了。所以它的声明不包含 @escaping,在这种情况下不需要捕获对 @escaping 的弱引用。

我没有提到 self 引用,但它们有点像隐式解包的 unowned 引用。

weak

guard 基本上是一个倒置的 guard 语句,增加了它的 if必须 elsereturn 或调用一个返回 throw 的函数,这是一个函数表明它永远不会返回的方式,要么是因为它终止了程序,就像 Never 那样,要么因为它出于某种原因进入了无限循环。在循环中,fatalError()guard 块也可以是 elsebreak,而在 continue 语句中,它可以是 switch 或 {{1 }}。

您在评论中提到您已经完成了嵌入式 C。C 程序通常具有“保护”if,以便在错误情况下提前退出,或者在简单的情况下将它们移出主逻辑。

break

基本上

fallthrough

相当于

int find(char x,const char* s)
{
    if (s == NULL) return -1; // This is a guard "if" in C

    for(int i = 0; s[i] != 0; ++i) {
        if (s[i] == x) return i;
    }

    return -1;
}

认为 guard condition else { return } 是说它的条件必须为真才能到达后面的主要代码,否则控制传递到 if !condition { return } 块,它必须以某种方式离开当前上下文。

通常,您可以轻松地使用其中任何一个,但如果将 guardelse 与可选绑定结合使用,则会有所不同。

guard
,

我不是 100% 肯定您在没有更多上下文的情况下尝试做的事情,但我的直觉是您正在尝试过滤掉某些与这些模式不匹配的外围设备。您的方法通常是正确的,但您正在检查已扫描的外围设备,而不是新传入的外围设备。尝试添加此过滤器:

.filter { newPeripheral in
    return (newPeripheral.rssi.intValue < 0 &&
            newPeripheral.peripheral.identifier.uuidString.contains("0863"))
}

您找到的代码中的第一个过滤器似乎只是检查重复项,这就是它查看 scannedPeripherals 的原因(也是它需要 weak self 说明符的原因)。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


依赖报错 idea导入项目后依赖报错,解决方案:https://blog.csdn.net/weixin_42420249/article/details/81191861 依赖版本报错:更换其他版本 无法下载依赖可参考:https://blog.csdn.net/weixin_42628809/a
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下 2021-12-03 13:33:33.927 ERROR 7228 [ main] o.s.b.d.LoggingFailureAnalysisReporter : *************************** APPL
错误1:gradle项目控制台输出为乱码 # 解决方案:https://blog.csdn.net/weixin_43501566/article/details/112482302 # 在gradle-wrapper.properties 添加以下内容 org.gradle.jvmargs=-Df
错误还原:在查询的过程中,传入的workType为0时,该条件不起作用 &lt;select id=&quot;xxx&quot;&gt; SELECT di.id, di.name, di.work_type, di.updated... &lt;where&gt; &lt;if test=&qu
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct redisServer’没有名为‘server_cpulist’的成员 redisSetCpuAffinity(server.server_cpulist); ^ server.c: 在函数‘hasActiveC
解决方案1 1、改项目中.idea/workspace.xml配置文件,增加dynamic.classpath参数 2、搜索PropertiesComponent,添加如下 &lt;property name=&quot;dynamic.classpath&quot; value=&quot;tru
删除根组件app.vue中的默认代码后报错:Module Error (from ./node_modules/eslint-loader/index.js): 解决方案:关闭ESlint代码检测,在项目根目录创建vue.config.js,在文件中添加 module.exports = { lin
查看spark默认的python版本 [root@master day27]# pyspark /home/software/spark-2.3.4-bin-hadoop2.7/conf/spark-env.sh: line 2: /usr/local/hadoop/bin/hadoop: No s
使用本地python环境可以成功执行 import pandas as pd import matplotlib.pyplot as plt # 设置字体 plt.rcParams[&#39;font.sans-serif&#39;] = [&#39;SimHei&#39;] # 能正确显示负号 p
错误1:Request method ‘DELETE‘ not supported 错误还原:controller层有一个接口,访问该接口时报错:Request method ‘DELETE‘ not supported 错误原因:没有接收到前端传入的参数,修改为如下 参考 错误2:cannot r
错误1:启动docker镜像时报错:Error response from daemon: driver failed programming external connectivity on endpoint quirky_allen 解决方法:重启docker -&gt; systemctl r
错误1:private field ‘xxx‘ is never assigned 按Altʾnter快捷键,选择第2项 参考:https://blog.csdn.net/shi_hong_fei_hei/article/details/88814070 错误2:启动时报错,不能找到主启动类 #
报错如下,通过源不能下载,最后警告pip需升级版本 Requirement already satisfied: pip in c:\users\ychen\appdata\local\programs\python\python310\lib\site-packages (22.0.4) Coll
错误1:maven打包报错 错误还原:使用maven打包项目时报错如下 [ERROR] Failed to execute goal org.apache.maven.plugins:maven-resources-plugin:3.2.0:resources (default-resources)
错误1:服务调用时报错 服务消费者模块assess通过openFeign调用服务提供者模块hires 如下为服务提供者模块hires的控制层接口 @RestController @RequestMapping(&quot;/hires&quot;) public class FeignControl
错误1:运行项目后报如下错误 解决方案 报错2:Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.1:compile (default-compile) on project sb 解决方案:在pom.
参考 错误原因 过滤器或拦截器在生效时,redisTemplate还没有注入 解决方案:在注入容器时就生效 @Component //项目运行时就注入Spring容器 public class RedisBean { @Resource private RedisTemplate&lt;String
使用vite构建项目报错 C:\Users\ychen\work&gt;npm init @vitejs/app @vitejs/create-app is deprecated, use npm init vite instead C:\Users\ychen\AppData\Local\npm-