Tag:

祖传财产!

对于Objective C类的starters属性而言,它是为实例变量以及最近为类成员定义getter和setter方法的简捷方法。 它们还帮助提供数据封装。 属性可用于定义实例变量或类变量的各个方面。 这些版本方面是 1.原子性 2.内存管理语义 3.可读性和可写性 4.存取器名称 5. Swift导入语义 只是为了演示属性包含的信息量,让我们定义一个简单的信息,然后尝试描述其实际含义。 @property NSString *名称; 它是原子的,强壮的,可读写的属性,将导致getter`name`和setter setName:`的合成,然后将其作为隐式展开的可选内容导入swift! 让我们谈谈这些方面的每一个。 有组织 任何属性都可以是原子的或非原子的。 通过getter访问原子属性时,它会返回该属性的有效值。 您可能想知道,getter应该返回一个有效值,什么是无效值? 在多线程环境中,当多个线程试图同时读取/写入属性时,指定属性为原子将确保在执行setter的过程中不会返回getter。 这意味着使用getter检索的值是在另一个线程执行写操作之前或之后,这仅保证该值不是无效或未完全写入。 这与线程安全性不同。 此外,在iOS平台上使属性原子化的成本非常高,因此很少使用此功能。 该实现使用自旋锁来确保多个线程不会同时读取写入。 内存管理语义 这些属性定义属性的设置方法在内存管理方面的行为。 即,当将新值设置为属性时,对象是否会被保留或复制或仅被分配。 在我们深入探讨此问题之前,您需要了解内存管理在ARC中的工作方式,本文不对此进行介绍。 属性的最重要属性是它的内存管理方面,您可以将任何属性指定为以下任一属性 分配 弱 强大 unsafe_unreatined 复制 让我们探索这些 @属性(非原子的,分配)CGPoint中心; @属性(非原子,指定)CGFloat高度; 当setter只需要分配要设置的值时,可以使用assign。 这用于分配值类型,如上所述。 通常将值类型复制到目标变量,并且该值的生存期是该变量的范围。 对于指向在堆上为任何值类型或值类型的集合分配的内存的指针,需要调用显式的free,即需要手动管理内存。 @property(nonatomic,weak)id 委托; @property(nonatomic,weak)id 数据源; 在上面的示例中,您看到了weak的使用,weak用于指定不保留分配的对象,相反,引用仅指向该对象,直到其有效为止,因此不影响该对象的寿命。 当属性保留对其的引用时,仍可以在任何时候释放该对象,如果引用弱,则在对象被取消初始化后,引用将指向nil。 自iOS 5 SDK以来,弱引用可用,在此之前,您可以使用unsafe_unretained来指定相同的行为,但是在取消初始化对象时,无需对引用进行零位或清零。 特别提到弱引用,它们在块的情况下用于捕获“ self”的值,以使该块最终不会对其捕获的对象具有潜在的保留周期。 […]

iOS 2018系列:破解iOS采访或成为iOS专家(4)

第4章:闭包和强大的闭包参考周期 面试是一个非常热门的话题,因为它提供了从初学者到专家级别的问题,而且大多数工程师在讨论中都对它感到困惑,即使您尝试在现实生活中使用它,也可能会遇到一些情况,混淆了使用什么和不使用什么! Swift中的闭包类似于C和Objective-C中的闭包。 闭包是可以独立传递的功能块,可以在代码中传递和使用。 闭包表达式语法 逃逸关闭 当闭包作为函数的参数传递给闭包时,闭包被认为是对函数的转义 ,但是在函数返回后会被调用。 声明将闭包作为其参数之一的函数时,可以在参数的类型之前编写@escaping ,以指示允许对闭包进行转义。 reversedNames = names.sorted(by:{s1中的s1,s2> s2})// (第1行 ) reversedNames = names.sorted(by:{$ 0> $ 1})// (第2行) 这两行都在做相同的事情, 第1行称为单表达式闭包的隐式返回, 第2行称为速记参数名 ,可用于通过$0 , $1 , $2名称引用闭包的参数值。上。 封闭的强大参考周期 之所以会出现这种强引用循环,是因为闭包(如类)是引用类型 。 案例:如果您将闭包分配给类实例的属性,并且该闭包的主体捕获该实例。 说明:之所以可能发生此捕获,是因为闭包的主体访问实例的属性,例如self.someProperty ,或者因为闭包调用了实例上的方法,例如self.someMethod() 。 在任何一种情况下,这些访问都会导致闭包“捕获” self ,从而创建一个强大的参考周期。 解决方案:弱引用或无主引用,弱引用或无主引用的适当选择取决于代码不同部分之间的关​​系。 问题:无主还是弱? 您应该使用两种参考类型中的哪一种? “只要有效,在引用生命周期中的某个时候变为零就使用弱引用。 相反,当您知道引用在初始化期间被设置为永远不会为零时,请使用无主引用。” “当闭包及其捕获的实例将始终相互引用且始终在同一时间解除分配时,将闭包中的捕获定义为未拥有的引用。” 有两种可能的方案: 闭包与捕获的对象具有相同的生存期,因此闭包只有在对象可以到达之前才可以到达。 外部对象和闭包具有相同的生存期(例如,和对象及其父对象之间的简单反向引用)。 在这种情况下,您应该将引用声明为Unown 。 一个常见的例子是在许多小闭包的例子中使用的[unowned self] ,这些小闭包在其父母的上下文中做某事,并且没有被其他地方引用或传递而不会超过其父母的寿命。 […]

了解目标C的弱项和强项

积木很棒。 为了避免保持周期,您经常会看到“弱者自我” —“强者自我”舞蹈 __weak __typeof __(self)weakSelf =自我; self.block = ^ { __typeof __(self)strongSelf = weakSelf; [strongSelf doSomething]; [strongSelf doSomethingElse]; }; 复制时块是对象 块在堆栈上创建,并且在其堆栈帧返回时将消失。 在堆栈上时,块对其所访问的任何内容的存储或生存期均无影响。 如果在堆栈帧返回后需要存在块,则可以将它们复制到堆中,并且此操作是显式操作。 这样,一个块将作为可可中的所有对象获得引用计数。 复制它们时,它们会随身携带其捕获的范围,并保留它们引用的所有对象 块可以从封闭范围捕获值 除了包含可执行代码之外,块还具有从其封闭范围捕获状态的能力。 请注意,代码块会捕获变量及其修饰符(即弱限定符), =>这说明了为什么需要将self声明为 __weak 当执行块时,对于第一种方法(doSomething),weakSelf可能为非零;而对于第二种方法(doSomethingElse),不可以使weakSelf不为nil。 您可能会认为,起初,这是在块内使用self来避免保留周期警告的技巧。 不是这种情况。 在块执行时创建对self的强引用,而在块声明时评估在块中使用self,从而保留对象。 但是,为了获得最佳实践,应该使用弱对象为对象创建强引用。 这也不会创建一个保留周期,因为该块内的强指针仅在该块完成之前才存在(唯一的作用域是该块本身)。 =>这说明了为什么您需要声明另一个 __strong 自我 许多人指出,“块是在堆栈上创建的,当它们的堆栈帧返回时,它们就会消失。 在堆栈上时,块不会影响它所访问的任何内容的存储或生存期。” 即使块(在堆栈上声明)增加了对其访问的所有对象的引用计数,这也将是无用的,因为当函数返回时,该块将被丢弃 复制块时(您会看到人们通常为块声明属性(副本)),这将增加对其访问的所有对象的引用计数。 为什么? 因为块是要在以后的时间执行的,所以它需要保持对它访问的所有对象的强引用。 块可以执行很多次,所以运行后它不会释放自己。 当您取消该块时,它将被取消分配,因此将减少对其访问的所有对象的引用计数。 AFNetworking在调用该块后将其清除为零,因此您不必在块内使用weakself 因此,在某些情况下,您不必在块内使用weakself 确保没有复制该块,只需声明并运行它 确保该块在调用后为零 这是更多链接,可帮助您进一步探索 我终于想出了弱自我和强自我 使用块 […]

ARC(iOS)

Swift使用自动引用计数 (ARC)来跟踪和管理应用程序的内存使用情况。 引用计数仅适用于类的实例。 结构和枚举是值类型,而不是引用类型,并且不通过引用存储和传递。 在本教程中,我将解释: ARC如何工作以及如何简化内存管理? 什么是强引用,弱引用和无所有权? 什么是强参考周期,它如何导致内存泄漏和问题? 如何避免闭包和委托中的强刷新周期? ARC如何工作? 每当创建类的实例时,ARC都会分配内存块来存储有关该实例的信息,并且当不需要类实例时,ARC会通过从内存中删除该实例来释放内存。 现在,ARC可以跟踪/计算引用该实例的变量,常量或属性的数量。 如果count为零,则ARC从内存中删除该实例。 如果实例的引用仍然存在,ARC会将其保留在内存中。 注意:我们不必显式删除实例或担心内存管理。 ARC为我们做到了。 强参考: 默认情况下,每个引用都是强引用,直到使用显式弱引用或无所有权引用为止。 引用被称为“强引用”,因为它在该实例上保持坚挺,并且只要该强引用仍然存在,就不允许对其进行重新分配。 为了理解弱点和无主点,我们需要了解一个常见的未知问题,即强参考周期。 现在给约翰分配一个公寓,让我们说右图所示的unit4A。 约翰也是unit4A的租户。 这将创建一个强大的参考周期,即使将john和unit4A设置为nil,人实例和单元实例的参考计数也将为1,并且ARC将无法执行任何操作,并且会发生内存泄漏。 将john设置为nil并将unit4A设置为nil后,将删除var链接,但由于发生了强烈的引用循环,因此仍然不会调用deinit。 现在,我们已经清楚地了解了这个问题(如果不能再阅读2-3次,然后在Playground中尝试一下,看看是否调用了deinit),那么我们现在就可以解决它。 因此,现在是讨论弱者和无主者的好时机: 使用类类型的属性时,Swift提供了两种解决强引用周期的方法:弱引用和无主引用。 弱引用和无主引用使引用周期中的一个实例可以引用另一个实例, 而无需对其进行严格控制。 然后,这些实例可以相互引用,而无需创建强大的引用周期。 当另一个实例的生存期较短时(即,另一个实例可以首先被释放时),请使用弱引用。 在上面的“ Apartment示例中,对于公寓来说,在其生命周期的某个时候不能有任何租户是合适的,因此在这种情况下,弱引用是打破引用周期的一种适当方法。 相反,当另一个实例具有相同的生存期或更长的生存期时,请使用无主引用。 因此,在上面的示例中,可以将Apartment的租户声明为弱者,因为租户的生存期比Apartment短,即Apartment可以拥有一个租户,并且该公寓的生活可能是空的。 在使用弱解决强引用循环的同时,确定哪个实例将是短命的(这也取决于设计和要求)。 如果您仍然有疑问,请再次阅读此行: “当另一个实例具有相同的生存期或更长的生存期时,将使用一个无主引用。” 封闭的强大参考周期: 如果将闭包分配给类实例的属性,并且闭包的主体捕获该实例,则也会发生强引用循环。 由于闭包的主体访问实例的属性(例如self.someProperty ,或者闭包在实例上调用方法self.someMethod()例如self.someMethod() ,可能会发生这种捕获。 在任何一种情况下,这些访问都会导致闭包“捕获” self ,从而创建一个强大的参考周期。 之所以会发生这种强烈的引用循环,是因为像类一样,闭包是引用类型。 将闭包分配给属性时,就是在分配对该闭包的引用 。 本质上,这是与上述相同的问题-两个强引用使彼此保持生命。 但是,这次不是两个类实例,而是一个彼此保持生命的类实例和一个闭包。 HTMLElement类定义了一个名为asHTML的惰性属性。 此属性引用将name和text组合为HTML字符串片段的闭包。 asHTML属性的类型为() -> […]

功能编程:闭包参考周期和修复

Article_1链接→ 功能迅速:关于闭包的全部。 Article_2链接→ iOS中的Lazy var swift。 请阅读以上两篇文章以继续。 假设您对函数式编程和闭包有很好的了解,那么让我们开始吧。 考虑一类Human 。 它具有一个init方法,该方法接受firstName和lastName作为参数。 它还有一个名为fullName的lazy var closure ,该lazy var closure不接受任何内容并返回String 。 它是()->String类型的。 在这里,当我们调用init方法时,将创建一个新的Human对象。 我们将此对象分配给可选类型humanObj 。 在下一行中,当我们将humanObj的值设置为nil ,将deinit{}方法。 您可以看到控制台打印在deinit方法中给出的文本。 现在,尝试在创建对象之后访问fullName闭包。 然后尝试将对象设置为nil 。 var humanObj:人类? = Human(firstName:“ John”,lastName:“ Doe”) let fullName = humanObj?.fullName humanObj = nil 由于闭包强烈引用self因此不会调用deinit{}方法。 释放对象时将调用deinit方法。 解决方法 我们可以在捕获列表中使用self来使用weak引用或unowned引用来打破强引用周期。 如果您不知道什么是捕获列表,请阅读顶部提到的文章。 弱 弱引用是指不会对其引用的实例保持强大控制的引用,因此不会阻止ARC处置所引用的实例。 此行为可防止参考成为强大参考周期的一部分。 由于弱引用可能为nil ,因此捕获的变量变为可选。 因此,我们应该使用guard来安全地拆开它: 懒惰的var fullName :()->字符串= […]

使用弱和无人修复自我关闭内存泄漏

大家好,在本文中,我只想澄清一些困惑,为什么有时我们不得不在闭包块中使用[弱自我]或[未知自我] 。 通过简单的用例,我们将对此进行讨论。 让我们开始吧。 如你所知 取消初始化 当没有SecondViewController的保留周期时,将调用该函数。 因此,以上代码没有复杂性。 您是从其他使用UINavigationController的控制器来的。 当您按下后退按钮时,控制台将显示以下消息。 因为没有保留周期,也没有内存泄漏, 所以当您返回时, deinit函数将立即触发。 现在,进入一个复杂的案例。 假设SecondViewController将从应用程序的其他部分获取通知。 因此,您需要在NotificationCenter中注册。 我们可以通过两种方式实现NotificationCenter。 一种是将选择器传递给NC,另一种是Closure。 在这里,我要关闭。 在上面的代码中,我们从NotificationCenter接收到一条消息,该消息需要显示在infoLabel中。 如果运行以上代码,则控制台如下所示。 是。 它只是空的。 好。 让我做以下更改。 您只是评论了infoLabel的设置文本,并在日志中打印了新消息。 如果您现在运行代码,则deinit函数将触发,控制台将填充“ ==========我正在腾出我的空间==========” 哦! 这到底是怎么回事。 每当我们在闭包块中使用self时 ,实际上就是在创建一个保留周期。 这意味着它的secondviewconroller保留数量增加到两个。 即使您从SecondViewController返回,也只会减少一个保留计数。 因此,SecondViewController不会脱离内存。 如何解决这个问题? 在这里,我们有两个选择。 [弱自我] [无主自我] 弱者与无人者之间的基本区别 弱:弱引用使对其引用的实例保持弱引用。 这意味着ARC不考虑对实例的引用。 请记住,如果没有其他对象对该实例进行强引用,则该实例将被释放。 无主:无主引用类似于弱引用,因为它们不对所引用的实例保持强引用。 它们的作用与弱引用相同,即避免强引用循环。 总是期望无主引用具有值,而弱引用并不期望变量具有值。 您可以将nil分配给弱对象。 如果您想了解弱和无主之间的区别,请查看此链接。 要使用弱势修复此问题,代码将更改为以下代码。 我们在闭包的开头添加了[weak self] ,并为self添加了可选绑定 。 弱引用会一直存在,直到对对象的强引用出现为止。 这意味着它不会增加保留数。 […]