Skip to content

Commit 5448e5d

Browse files
committed
let's be more careful about Combine memory management
1 parent badaecb commit 5448e5d

File tree

10 files changed

+189
-19
lines changed

10 files changed

+189
-19
lines changed

bk1ch12p497notificationLeakerSolution/ch12p325NotificationLeaker/FlipsideViewController.swift

+7-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ class FlipsideViewController: UIViewController {
2323
var task = Task {
2424
let stream = NotificationCenter.default.notifications(named: .woohoo)
2525
for await _ in stream {
26-
print("the observer still exists!", self)
26+
print("Task observing!", self)
2727
}
2828
}
2929

@@ -35,7 +35,7 @@ class FlipsideViewController: UIViewController {
3535
forName: .woohoo, object:nil, queue:nil) {
3636
[unowned self] // *
3737
_ in
38-
print("The observer still exists!")
38+
print("Observer token observing!")
3939
print(self.description) // leak me, leak me
4040
}
4141
self.observers.insert(ob as! NSObject)
@@ -45,7 +45,7 @@ class FlipsideViewController: UIViewController {
4545
.sink {
4646
[unowned self] // *
4747
_ in
48-
print("The observer still exists!", self) }
48+
print("Combine pipeline observing!", self) }
4949
.store(in: &self.storage)
5050
}
5151

@@ -61,9 +61,13 @@ class FlipsideViewController: UIViewController {
6161
// if deinit is not called when you tap Done, we are leaking
6262
deinit {
6363
print("deinit")
64+
// observer token:
6465
for ob in self.observers {
6566
NotificationCenter.default.removeObserver(ob) // *
6667
}
68+
// Combine pipeline:
69+
// nothing needed!
70+
// task:
6771
self.task.cancel() // *
6872
}
6973

bk1ch13p503SwiftUIHelloWorld6/bk1ch13p503SwiftUIHelloWorld6/ContentView.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class NameSaver : ObservableObject {
1818
self.username = self.read() ?? ""
1919
self.$username
2020
.debounce(for: 0.4, scheduler: DispatchQueue.main)
21-
.sink { self.save($0) }
21+
.sink { [unowned self] in self.save($0) }
2222
.store(in: &self.storage)
2323
}
2424
func read() -> String? {

bk2ch18p714CombineAuthorization/CombineAuthorization.xcodeproj/project.pbxproj

+2
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@
290290
CURRENT_PROJECT_VERSION = 1;
291291
DEVELOPMENT_TEAM = W3LHX5RGV2;
292292
INFOPLIST_FILE = CombineAuthorization/Info.plist;
293+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
293294
LD_RUNPATH_SEARCH_PATHS = (
294295
"$(inherited)",
295296
"@executable_path/Frameworks",
@@ -311,6 +312,7 @@
311312
CURRENT_PROJECT_VERSION = 1;
312313
DEVELOPMENT_TEAM = W3LHX5RGV2;
313314
INFOPLIST_FILE = CombineAuthorization/Info.plist;
315+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
314316
LD_RUNPATH_SEARCH_PATHS = (
315317
"$(inherited)",
316318
"@executable_path/Frameworks",

bk2ch18p714CombineAuthorization/CombineAuthorization/ViewController.swift

+3-1
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,9 @@ class ViewController: UIViewController {
5959
@IBAction func giveItAGo(_ sender:Any) {
6060
self.authorizationPublisher
6161
.receive(on: DispatchQueue.global(qos: .userInitiated))
62-
.compactMap { (auth:Bool) -> Result<[CNLabeledValue<NSString>], Error>? in
62+
.compactMap {
63+
[unowned self]
64+
(auth:Bool) -> Result<[CNLabeledValue<NSString>], Error>? in
6365
if auth {
6466
return self.getMyEmailAddresses()
6567
}

bk2ch25p868mandelbrotCombine/ch38p1106mandelbrotNoThreading/MyMandelbrotView.swift

+15-9
Original file line numberDiff line numberDiff line change
@@ -42,22 +42,22 @@ class MyMandelbrotView : UIView {
4242
private func configuredPipeline() -> AnyCancellable {
4343
let pipeline = self.trigger
4444
.receive(on: DispatchQueue.main)
45-
.map { () -> (CGPoint, CGRect) in
45+
.map { [unowned self] () -> (CGPoint, CGRect) in
4646
print("start on main")
4747
let center = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
4848
let bounds = self.bounds
4949
return (center:center, bounds:bounds)
5050
}
5151
.receive(on: draw_queue)
52-
.map { (center, bounds) -> CGContext in
52+
.map { [unowned self] (center, bounds) -> CGContext in
5353
print("background start")
5454
let bitmap = self.makeBitmapContext(size: bounds.size)
5555
self.draw(center: center, bounds: bounds, zoom: 1, context: bitmap)
5656
print("background end")
5757
return bitmap
5858
}
5959
.receive(on: DispatchQueue.main)
60-
.map { (bitmap:CGContext) -> () in
60+
.map { [unowned self] (bitmap:CGContext) -> () in
6161
print("main again")
6262
self.bitmapContext = bitmap
6363
self.setNeedsDisplay()
@@ -67,20 +67,23 @@ class MyMandelbrotView : UIView {
6767
}
6868

6969
private func configuredPipeline2() -> AnyCancellable {
70-
let p1 = switchTo(upstream: self.trigger, on: DispatchQueue.main) { () -> (CGPoint, CGRect) in
70+
let p1 = switchTo(upstream: self.trigger, on: DispatchQueue.main) {
71+
[unowned self] () -> (CGPoint, CGRect) in
7172
print("start on main")
7273
let center = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
7374
let bounds = self.bounds
7475
return (center:center, bounds:bounds)
7576
}
76-
let p2 = switchTo(upstream: p1, on: draw_queue) { (center, bounds) -> CGContext in
77+
let p2 = switchTo(upstream: p1, on: draw_queue) {
78+
[unowned self] (center, bounds) -> CGContext in
7779
print("background start")
7880
let bitmap = self.makeBitmapContext(size: bounds.size)
7981
self.draw(center: center, bounds: bounds, zoom: 1, context: bitmap)
8082
print("background end")
8183
return bitmap
8284
}
83-
let p3 = switchTo(upstream: p2, on: DispatchQueue.main) { (bitmap:CGContext) -> () in
85+
let p3 = switchTo(upstream: p2, on: DispatchQueue.main) {
86+
[unowned self] (bitmap:CGContext) -> () in
8487
print("main again")
8588
self.bitmapContext = bitmap
8689
self.setNeedsDisplay()
@@ -90,20 +93,23 @@ class MyMandelbrotView : UIView {
9093

9194
private func configuredPipeline3() -> AnyCancellable {
9295
self.trigger
93-
.performOn(DispatchQueue.main) { () -> (CGPoint, CGRect) in
96+
.performOn(DispatchQueue.main) {
97+
[unowned self] () -> (CGPoint, CGRect) in
9498
print("start on main")
9599
let center = CGPoint(x: self.bounds.midX, y: self.bounds.midY)
96100
let bounds = self.bounds
97101
return (center:center, bounds:bounds)
98102
}
99-
.performOn(draw_queue) { (center, bounds) -> CGContext in
103+
.performOn(draw_queue) {
104+
[unowned self] (center, bounds) -> CGContext in
100105
print("background start")
101106
let bitmap = self.makeBitmapContext(size: bounds.size)
102107
self.draw(center: center, bounds: bounds, zoom: 1, context: bitmap)
103108
print("background end")
104109
return bitmap
105110
}
106-
.performOn(DispatchQueue.main) { (bitmap:CGContext) -> () in
111+
.performOn(DispatchQueue.main) {
112+
[unowned self] (bitmap:CGContext) -> () in
107113
print("main again")
108114
self.bitmapContext = bitmap
109115
self.setNeedsDisplay()

bk2ch25p868mandelbrotCombine/ch38p1109mandelbrotGCD.xcodeproj/project.pbxproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -270,7 +270,7 @@
270270
GCC_PRECOMPILE_PREFIX_HEADER = YES;
271271
GCC_PREFIX_HEADER = "ch38p1106mandelbrotNoThreading/ch38p1109mandelbrotGCD-Prefix.pch";
272272
INFOPLIST_FILE = "ch38p1106mandelbrotNoThreading/ch38p1109mandelbrotGCD-Info.plist";
273-
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
273+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
274274
LD_RUNPATH_SEARCH_PATHS = (
275275
"$(inherited)",
276276
"@executable_path/Frameworks",
@@ -293,7 +293,7 @@
293293
GCC_PRECOMPILE_PREFIX_HEADER = YES;
294294
GCC_PREFIX_HEADER = "ch38p1106mandelbrotNoThreading/ch38p1109mandelbrotGCD-Prefix.pch";
295295
INFOPLIST_FILE = "ch38p1106mandelbrotNoThreading/ch38p1109mandelbrotGCD-Info.plist";
296-
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
296+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
297297
LD_RUNPATH_SEARCH_PATHS = (
298298
"$(inherited)",
299299
"@executable_path/Frameworks",
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "1300"
4+
version = "1.3">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES">
8+
<BuildActionEntries>
9+
<BuildActionEntry
10+
buildForTesting = "YES"
11+
buildForRunning = "YES"
12+
buildForProfiling = "YES"
13+
buildForArchiving = "YES"
14+
buildForAnalyzing = "YES">
15+
<BuildableReference
16+
BuildableIdentifier = "primary"
17+
BlueprintIdentifier = "3247F3231837BBA300A9162F"
18+
BuildableName = "ch38p1109mandelbrotGCD.app"
19+
BlueprintName = "ch38p1109mandelbrotGCD"
20+
ReferencedContainer = "container:ch38p1109mandelbrotGCD.xcodeproj">
21+
</BuildableReference>
22+
</BuildActionEntry>
23+
</BuildActionEntries>
24+
</BuildAction>
25+
<TestAction
26+
buildConfiguration = "Debug"
27+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
shouldUseLaunchSchemeArgsEnv = "YES">
30+
<Testables>
31+
</Testables>
32+
</TestAction>
33+
<LaunchAction
34+
buildConfiguration = "Debug"
35+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
36+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
37+
launchStyle = "0"
38+
useCustomWorkingDirectory = "NO"
39+
ignoresPersistentStateOnLaunch = "NO"
40+
debugDocumentVersioning = "YES"
41+
debugServiceExtension = "internal"
42+
allowLocationSimulation = "YES">
43+
<BuildableProductRunnable
44+
runnableDebuggingMode = "0">
45+
<BuildableReference
46+
BuildableIdentifier = "primary"
47+
BlueprintIdentifier = "3247F3231837BBA300A9162F"
48+
BuildableName = "ch38p1109mandelbrotGCD.app"
49+
BlueprintName = "ch38p1109mandelbrotGCD"
50+
ReferencedContainer = "container:ch38p1109mandelbrotGCD.xcodeproj">
51+
</BuildableReference>
52+
</BuildableProductRunnable>
53+
</LaunchAction>
54+
<ProfileAction
55+
buildConfiguration = "Release"
56+
shouldUseLaunchSchemeArgsEnv = "YES"
57+
savedToolIdentifier = ""
58+
useCustomWorkingDirectory = "NO"
59+
debugDocumentVersioning = "YES">
60+
<BuildableProductRunnable
61+
runnableDebuggingMode = "0">
62+
<BuildableReference
63+
BuildableIdentifier = "primary"
64+
BlueprintIdentifier = "3247F3231837BBA300A9162F"
65+
BuildableName = "ch38p1109mandelbrotGCD.app"
66+
BlueprintName = "ch38p1109mandelbrotGCD"
67+
ReferencedContainer = "container:ch38p1109mandelbrotGCD.xcodeproj">
68+
</BuildableReference>
69+
</BuildableProductRunnable>
70+
</ProfileAction>
71+
<AnalyzeAction
72+
buildConfiguration = "Debug">
73+
</AnalyzeAction>
74+
<ArchiveAction
75+
buildConfiguration = "Release"
76+
revealArchiveInOrganizer = "YES">
77+
</ArchiveAction>
78+
</Scheme>

iOS13bookExamples/bk2ch24p834simpleHTTP2/ch37p1088simpleHTTP.xcodeproj/project.pbxproj

+2-2
Original file line numberDiff line numberDiff line change
@@ -263,7 +263,7 @@
263263
GCC_PRECOMPILE_PREFIX_HEADER = YES;
264264
GCC_PREFIX_HEADER = "ch37p1088simpleHTTP/ch37p1088simpleHTTP-Prefix.pch";
265265
INFOPLIST_FILE = "ch37p1088simpleHTTP/ch37p1088simpleHTTP-Info.plist";
266-
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
266+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
267267
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
268268
ONLY_ACTIVE_ARCH = NO;
269269
PRODUCT_BUNDLE_IDENTIFIER = "com.neuburg.matt.${PRODUCT_NAME:rfc1034identifier}";
@@ -282,7 +282,7 @@
282282
GCC_PRECOMPILE_PREFIX_HEADER = YES;
283283
GCC_PREFIX_HEADER = "ch37p1088simpleHTTP/ch37p1088simpleHTTP-Prefix.pch";
284284
INFOPLIST_FILE = "ch37p1088simpleHTTP/ch37p1088simpleHTTP-Info.plist";
285-
IPHONEOS_DEPLOYMENT_TARGET = 13.0;
285+
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
286286
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
287287
ONLY_ACTIVE_ARCH = NO;
288288
PRODUCT_BUNDLE_IDENTIFIER = "com.neuburg.matt.${PRODUCT_NAME:rfc1034identifier}";
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<Scheme
3+
LastUpgradeVersion = "1300"
4+
version = "1.3">
5+
<BuildAction
6+
parallelizeBuildables = "YES"
7+
buildImplicitDependencies = "YES">
8+
<BuildActionEntries>
9+
<BuildActionEntry
10+
buildForTesting = "YES"
11+
buildForRunning = "YES"
12+
buildForProfiling = "YES"
13+
buildForArchiving = "YES"
14+
buildForAnalyzing = "YES">
15+
<BuildableReference
16+
BuildableIdentifier = "primary"
17+
BlueprintIdentifier = "3266DC1B1834075B001A83CD"
18+
BuildableName = "ch37p1088simpleHTTP.app"
19+
BlueprintName = "ch37p1088simpleHTTP"
20+
ReferencedContainer = "container:ch37p1088simpleHTTP.xcodeproj">
21+
</BuildableReference>
22+
</BuildActionEntry>
23+
</BuildActionEntries>
24+
</BuildAction>
25+
<TestAction
26+
buildConfiguration = "Debug"
27+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
28+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
29+
shouldUseLaunchSchemeArgsEnv = "YES">
30+
<Testables>
31+
</Testables>
32+
</TestAction>
33+
<LaunchAction
34+
buildConfiguration = "Debug"
35+
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
36+
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
37+
launchStyle = "0"
38+
useCustomWorkingDirectory = "NO"
39+
ignoresPersistentStateOnLaunch = "NO"
40+
debugDocumentVersioning = "YES"
41+
debugServiceExtension = "internal"
42+
allowLocationSimulation = "YES">
43+
<BuildableProductRunnable
44+
runnableDebuggingMode = "0">
45+
<BuildableReference
46+
BuildableIdentifier = "primary"
47+
BlueprintIdentifier = "3266DC1B1834075B001A83CD"
48+
BuildableName = "ch37p1088simpleHTTP.app"
49+
BlueprintName = "ch37p1088simpleHTTP"
50+
ReferencedContainer = "container:ch37p1088simpleHTTP.xcodeproj">
51+
</BuildableReference>
52+
</BuildableProductRunnable>
53+
</LaunchAction>
54+
<ProfileAction
55+
buildConfiguration = "Release"
56+
shouldUseLaunchSchemeArgsEnv = "YES"
57+
savedToolIdentifier = ""
58+
useCustomWorkingDirectory = "NO"
59+
debugDocumentVersioning = "YES">
60+
<BuildableProductRunnable
61+
runnableDebuggingMode = "0">
62+
<BuildableReference
63+
BuildableIdentifier = "primary"
64+
BlueprintIdentifier = "3266DC1B1834075B001A83CD"
65+
BuildableName = "ch37p1088simpleHTTP.app"
66+
BlueprintName = "ch37p1088simpleHTTP"
67+
ReferencedContainer = "container:ch37p1088simpleHTTP.xcodeproj">
68+
</BuildableReference>
69+
</BuildableProductRunnable>
70+
</ProfileAction>
71+
<AnalyzeAction
72+
buildConfiguration = "Debug">
73+
</AnalyzeAction>
74+
<ArchiveAction
75+
buildConfiguration = "Release"
76+
revealArchiveInOrganizer = "YES">
77+
</ArchiveAction>
78+
</Scheme>

iOS13bookExamples/bk2ch24p834simpleHTTP2/ch37p1088simpleHTTP/ViewController.swift

+1-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ class ViewController: UIViewController {
5151
if case let .failure(err) = comp {
5252
print(err)
5353
}
54-
}) { im in
54+
}) { [unowned self] im in
5555
print("here's your image")
5656
self.iv.image = im
5757
}

0 commit comments

Comments
 (0)