├── .gitignore
├── .swiftpm
└── xcode
│ └── package.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ └── IDEWorkspaceChecks.plist
├── CombineStorable.podspec
├── CombineStorable.xcodeproj
├── CombineStorableTests_Info.plist
├── CombineStorable_Info.plist
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcshareddata
│ │ ├── IDEWorkspaceChecks.plist
│ │ └── WorkspaceSettings.xcsettings
└── xcshareddata
│ └── xcschemes
│ └── CombineStorable-Package.xcscheme
├── LICENSE
├── Package.swift
├── README.md
├── Sources
└── CombineStorable
│ ├── NSObject+Storable.swift
│ ├── Publisher+Storable.swift
│ └── Storable.swift
└── Tests
├── CombineStorableTests
├── StorableTests.swift
└── XCTestManifests.swift
└── LinuxMain.swift
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## User settings
6 | xcuserdata/
7 |
8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9)
9 | *.xcscmblueprint
10 | *.xccheckout
11 |
12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4)
13 | build/
14 | DerivedData/
15 | *.moved-aside
16 | *.pbxuser
17 | !default.pbxuser
18 | *.mode1v3
19 | !default.mode1v3
20 | *.mode2v3
21 | !default.mode2v3
22 | *.perspectivev3
23 | !default.perspectivev3
24 |
25 | ## Obj-C/Swift specific
26 | *.hmap
27 |
28 | ## App packaging
29 | *.ipa
30 | *.dSYM.zip
31 | *.dSYM
32 |
33 | ## Playgrounds
34 | timeline.xctimeline
35 | playground.xcworkspace
36 |
37 | # Swift Package Manager
38 | .build/
39 |
40 | # CocoaPods
41 | # Pods/
42 | # *.xcworkspace
43 |
44 | # Carthage
45 | Carthage/Build/
46 |
47 | # Accio dependency management
48 | Dependencies/
49 | .accio/
50 |
51 | # fastlane
52 | fastlane/report.xml
53 | fastlane/Preview.html
54 | fastlane/screenshots/**/*.png
55 | fastlane/test_output
56 |
57 | # Code Injection
58 | iOSInjectionProject/
59 |
60 | # MAC
61 | .DS_Store
62 | /.build
63 | /Packages
64 | xcuserdata/
65 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.swiftpm/xcode/package.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/CombineStorable.podspec:
--------------------------------------------------------------------------------
1 | Pod::Spec.new do |spec|
2 | spec.name = "CombineStorable"
3 | spec.version = "1.0.0"
4 | spec.summary = "Handy Combine extensions on NSObject, including Set."
5 | spec.homepage = "https://github.com/crane-hiromu/CombineStorable"
6 | spec.license = { :type => 'MIT', :file => 'LICENSE' }
7 | spec.author = "h.crane"
8 | spec.platform = :ios, "13.0"
9 | spec.swift_versions = "5.0"
10 | spec.source = { :git => "https://github.com/crane-hiromu/CombineStorable.git", :tag => "#{spec.version}" }
11 | spec.source_files = "Sources/**/*.{swift}"
12 | end
--------------------------------------------------------------------------------
/CombineStorable.xcodeproj/CombineStorableTests_Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CFBundleDevelopmentRegion
5 | en
6 | CFBundleExecutable
7 | $(EXECUTABLE_NAME)
8 | CFBundleIdentifier
9 | $(PRODUCT_BUNDLE_IDENTIFIER)
10 | CFBundleInfoDictionaryVersion
11 | 6.0
12 | CFBundleName
13 | $(PRODUCT_NAME)
14 | CFBundlePackageType
15 | BNDL
16 | CFBundleShortVersionString
17 | 1.0
18 | CFBundleSignature
19 | ????
20 | CFBundleVersion
21 | $(CURRENT_PROJECT_VERSION)
22 | NSPrincipalClass
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/CombineStorable.xcodeproj/CombineStorable_Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | CFBundleDevelopmentRegion
5 | en
6 | CFBundleExecutable
7 | $(EXECUTABLE_NAME)
8 | CFBundleIdentifier
9 | $(PRODUCT_BUNDLE_IDENTIFIER)
10 | CFBundleInfoDictionaryVersion
11 | 6.0
12 | CFBundleName
13 | $(PRODUCT_NAME)
14 | CFBundlePackageType
15 | FMWK
16 | CFBundleShortVersionString
17 | 1.0
18 | CFBundleSignature
19 | ????
20 | CFBundleVersion
21 | $(CURRENT_PROJECT_VERSION)
22 | NSPrincipalClass
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/CombineStorable.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = "1";
4 | objectVersion = "46";
5 | objects = {
6 | "CombineStorable::CombineStorable" = {
7 | isa = "PBXNativeTarget";
8 | buildConfigurationList = "OBJ_23";
9 | buildPhases = (
10 | "OBJ_26",
11 | "OBJ_30"
12 | );
13 | dependencies = (
14 | );
15 | name = "CombineStorable";
16 | productName = "CombineStorable";
17 | productReference = "CombineStorable::CombineStorable::Product";
18 | productType = "com.apple.product-type.framework";
19 | };
20 | "CombineStorable::CombineStorable::Product" = {
21 | isa = "PBXFileReference";
22 | path = "CombineStorable.framework";
23 | sourceTree = "BUILT_PRODUCTS_DIR";
24 | };
25 | "CombineStorable::CombineStorablePackageTests::ProductTarget" = {
26 | isa = "PBXAggregateTarget";
27 | buildConfigurationList = "OBJ_38";
28 | buildPhases = (
29 | );
30 | dependencies = (
31 | "OBJ_41"
32 | );
33 | name = "CombineStorablePackageTests";
34 | productName = "CombineStorablePackageTests";
35 | };
36 | "CombineStorable::CombineStorableTests" = {
37 | isa = "PBXNativeTarget";
38 | buildConfigurationList = "OBJ_43";
39 | buildPhases = (
40 | "OBJ_46",
41 | "OBJ_49"
42 | );
43 | dependencies = (
44 | "OBJ_51"
45 | );
46 | name = "CombineStorableTests";
47 | productName = "CombineStorableTests";
48 | productReference = "CombineStorable::CombineStorableTests::Product";
49 | productType = "com.apple.product-type.bundle.unit-test";
50 | };
51 | "CombineStorable::CombineStorableTests::Product" = {
52 | isa = "PBXFileReference";
53 | path = "CombineStorableTests.xctest";
54 | sourceTree = "BUILT_PRODUCTS_DIR";
55 | };
56 | "CombineStorable::SwiftPMPackageDescription" = {
57 | isa = "PBXNativeTarget";
58 | buildConfigurationList = "OBJ_32";
59 | buildPhases = (
60 | "OBJ_35"
61 | );
62 | dependencies = (
63 | );
64 | name = "CombineStorablePackageDescription";
65 | productName = "CombineStorablePackageDescription";
66 | productType = "com.apple.product-type.framework";
67 | };
68 | "OBJ_1" = {
69 | isa = "PBXProject";
70 | attributes = {
71 | LastSwiftMigration = "9999";
72 | LastUpgradeCheck = "9999";
73 | };
74 | buildConfigurationList = "OBJ_2";
75 | compatibilityVersion = "Xcode 3.2";
76 | developmentRegion = "en";
77 | hasScannedForEncodings = "0";
78 | knownRegions = (
79 | "en"
80 | );
81 | mainGroup = "OBJ_5";
82 | productRefGroup = "OBJ_16";
83 | projectDirPath = ".";
84 | targets = (
85 | "CombineStorable::CombineStorable",
86 | "CombineStorable::SwiftPMPackageDescription",
87 | "CombineStorable::CombineStorablePackageTests::ProductTarget",
88 | "CombineStorable::CombineStorableTests"
89 | );
90 | };
91 | "OBJ_10" = {
92 | isa = "PBXFileReference";
93 | path = "Publisher+Storable.swift";
94 | sourceTree = "";
95 | };
96 | "OBJ_11" = {
97 | isa = "PBXFileReference";
98 | path = "Storable.swift";
99 | sourceTree = "";
100 | };
101 | "OBJ_12" = {
102 | isa = "PBXGroup";
103 | children = (
104 | "OBJ_13"
105 | );
106 | name = "Tests";
107 | path = "";
108 | sourceTree = "SOURCE_ROOT";
109 | };
110 | "OBJ_13" = {
111 | isa = "PBXGroup";
112 | children = (
113 | "OBJ_14",
114 | "OBJ_15"
115 | );
116 | name = "CombineStorableTests";
117 | path = "Tests/CombineStorableTests";
118 | sourceTree = "SOURCE_ROOT";
119 | };
120 | "OBJ_14" = {
121 | isa = "PBXFileReference";
122 | path = "StorableTests.swift";
123 | sourceTree = "";
124 | };
125 | "OBJ_15" = {
126 | isa = "PBXFileReference";
127 | path = "XCTestManifests.swift";
128 | sourceTree = "";
129 | };
130 | "OBJ_16" = {
131 | isa = "PBXGroup";
132 | children = (
133 | "CombineStorable::CombineStorableTests::Product",
134 | "CombineStorable::CombineStorable::Product"
135 | );
136 | name = "Products";
137 | path = "";
138 | sourceTree = "BUILT_PRODUCTS_DIR";
139 | };
140 | "OBJ_19" = {
141 | isa = "PBXFileReference";
142 | path = "Carthage";
143 | sourceTree = "SOURCE_ROOT";
144 | };
145 | "OBJ_2" = {
146 | isa = "XCConfigurationList";
147 | buildConfigurations = (
148 | "OBJ_3",
149 | "OBJ_4"
150 | );
151 | defaultConfigurationIsVisible = "0";
152 | defaultConfigurationName = "Release";
153 | };
154 | "OBJ_20" = {
155 | isa = "PBXFileReference";
156 | path = "LICENSE";
157 | sourceTree = "";
158 | };
159 | "OBJ_21" = {
160 | isa = "PBXFileReference";
161 | path = "README.md";
162 | sourceTree = "";
163 | };
164 | "OBJ_23" = {
165 | isa = "XCConfigurationList";
166 | buildConfigurations = (
167 | "OBJ_24",
168 | "OBJ_25"
169 | );
170 | defaultConfigurationIsVisible = "0";
171 | defaultConfigurationName = "Release";
172 | };
173 | "OBJ_24" = {
174 | isa = "XCBuildConfiguration";
175 | buildSettings = {
176 | ENABLE_TESTABILITY = "YES";
177 | FRAMEWORK_SEARCH_PATHS = (
178 | "$(inherited)",
179 | "$(PLATFORM_DIR)/Developer/Library/Frameworks"
180 | );
181 | HEADER_SEARCH_PATHS = (
182 | "$(inherited)"
183 | );
184 | INFOPLIST_FILE = "CombineStorable.xcodeproj/CombineStorable_Info.plist";
185 | IPHONEOS_DEPLOYMENT_TARGET = "8.0";
186 | LD_RUNPATH_SEARCH_PATHS = (
187 | "$(inherited)",
188 | "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"
189 | );
190 | MACOSX_DEPLOYMENT_TARGET = "10.10";
191 | OTHER_CFLAGS = (
192 | "$(inherited)"
193 | );
194 | OTHER_LDFLAGS = (
195 | "$(inherited)"
196 | );
197 | OTHER_SWIFT_FLAGS = (
198 | "$(inherited)"
199 | );
200 | PRODUCT_BUNDLE_IDENTIFIER = "CombineStorable";
201 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
202 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
203 | SKIP_INSTALL = "YES";
204 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = (
205 | "$(inherited)"
206 | );
207 | SWIFT_VERSION = "5.0";
208 | TARGET_NAME = "CombineStorable";
209 | TVOS_DEPLOYMENT_TARGET = "9.0";
210 | WATCHOS_DEPLOYMENT_TARGET = "2.0";
211 | };
212 | name = "Debug";
213 | };
214 | "OBJ_25" = {
215 | isa = "XCBuildConfiguration";
216 | buildSettings = {
217 | ENABLE_TESTABILITY = "YES";
218 | FRAMEWORK_SEARCH_PATHS = (
219 | "$(inherited)",
220 | "$(PLATFORM_DIR)/Developer/Library/Frameworks"
221 | );
222 | HEADER_SEARCH_PATHS = (
223 | "$(inherited)"
224 | );
225 | INFOPLIST_FILE = "CombineStorable.xcodeproj/CombineStorable_Info.plist";
226 | IPHONEOS_DEPLOYMENT_TARGET = "8.0";
227 | LD_RUNPATH_SEARCH_PATHS = (
228 | "$(inherited)",
229 | "$(TOOLCHAIN_DIR)/usr/lib/swift/macosx"
230 | );
231 | MACOSX_DEPLOYMENT_TARGET = "10.10";
232 | OTHER_CFLAGS = (
233 | "$(inherited)"
234 | );
235 | OTHER_LDFLAGS = (
236 | "$(inherited)"
237 | );
238 | OTHER_SWIFT_FLAGS = (
239 | "$(inherited)"
240 | );
241 | PRODUCT_BUNDLE_IDENTIFIER = "CombineStorable";
242 | PRODUCT_MODULE_NAME = "$(TARGET_NAME:c99extidentifier)";
243 | PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
244 | SKIP_INSTALL = "YES";
245 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = (
246 | "$(inherited)"
247 | );
248 | SWIFT_VERSION = "5.0";
249 | TARGET_NAME = "CombineStorable";
250 | TVOS_DEPLOYMENT_TARGET = "9.0";
251 | WATCHOS_DEPLOYMENT_TARGET = "2.0";
252 | };
253 | name = "Release";
254 | };
255 | "OBJ_26" = {
256 | isa = "PBXSourcesBuildPhase";
257 | files = (
258 | "OBJ_27",
259 | "OBJ_28",
260 | "OBJ_29"
261 | );
262 | };
263 | "OBJ_27" = {
264 | isa = "PBXBuildFile";
265 | fileRef = "OBJ_9";
266 | };
267 | "OBJ_28" = {
268 | isa = "PBXBuildFile";
269 | fileRef = "OBJ_10";
270 | };
271 | "OBJ_29" = {
272 | isa = "PBXBuildFile";
273 | fileRef = "OBJ_11";
274 | };
275 | "OBJ_3" = {
276 | isa = "XCBuildConfiguration";
277 | buildSettings = {
278 | CLANG_ENABLE_OBJC_ARC = "YES";
279 | COMBINE_HIDPI_IMAGES = "YES";
280 | COPY_PHASE_STRIP = "NO";
281 | DEBUG_INFORMATION_FORMAT = "dwarf";
282 | DYLIB_INSTALL_NAME_BASE = "@rpath";
283 | ENABLE_NS_ASSERTIONS = "YES";
284 | GCC_OPTIMIZATION_LEVEL = "0";
285 | GCC_PREPROCESSOR_DEFINITIONS = (
286 | "$(inherited)",
287 | "SWIFT_PACKAGE=1",
288 | "DEBUG=1"
289 | );
290 | MACOSX_DEPLOYMENT_TARGET = "10.10";
291 | ONLY_ACTIVE_ARCH = "YES";
292 | OTHER_SWIFT_FLAGS = (
293 | "$(inherited)",
294 | "-DXcode"
295 | );
296 | PRODUCT_NAME = "$(TARGET_NAME)";
297 | SDKROOT = "macosx";
298 | SUPPORTED_PLATFORMS = (
299 | "macosx",
300 | "iphoneos",
301 | "iphonesimulator",
302 | "appletvos",
303 | "appletvsimulator",
304 | "watchos",
305 | "watchsimulator"
306 | );
307 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = (
308 | "$(inherited)",
309 | "SWIFT_PACKAGE",
310 | "DEBUG"
311 | );
312 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
313 | USE_HEADERMAP = "NO";
314 | };
315 | name = "Debug";
316 | };
317 | "OBJ_30" = {
318 | isa = "PBXFrameworksBuildPhase";
319 | files = (
320 | );
321 | };
322 | "OBJ_32" = {
323 | isa = "XCConfigurationList";
324 | buildConfigurations = (
325 | "OBJ_33",
326 | "OBJ_34"
327 | );
328 | defaultConfigurationIsVisible = "0";
329 | defaultConfigurationName = "Release";
330 | };
331 | "OBJ_33" = {
332 | isa = "XCBuildConfiguration";
333 | buildSettings = {
334 | LD = "/usr/bin/true";
335 | OTHER_SWIFT_FLAGS = (
336 | "-swift-version",
337 | "5",
338 | "-I",
339 | "$(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2",
340 | "-target",
341 | "x86_64-apple-macosx10.10",
342 | "-sdk",
343 | "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk",
344 | "-package-description-version",
345 | "5.2.0"
346 | );
347 | SWIFT_VERSION = "5.0";
348 | };
349 | name = "Debug";
350 | };
351 | "OBJ_34" = {
352 | isa = "XCBuildConfiguration";
353 | buildSettings = {
354 | LD = "/usr/bin/true";
355 | OTHER_SWIFT_FLAGS = (
356 | "-swift-version",
357 | "5",
358 | "-I",
359 | "$(TOOLCHAIN_DIR)/usr/lib/swift/pm/4_2",
360 | "-target",
361 | "x86_64-apple-macosx10.10",
362 | "-sdk",
363 | "/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.15.sdk",
364 | "-package-description-version",
365 | "5.2.0"
366 | );
367 | SWIFT_VERSION = "5.0";
368 | };
369 | name = "Release";
370 | };
371 | "OBJ_35" = {
372 | isa = "PBXSourcesBuildPhase";
373 | files = (
374 | "OBJ_36"
375 | );
376 | };
377 | "OBJ_36" = {
378 | isa = "PBXBuildFile";
379 | fileRef = "OBJ_6";
380 | };
381 | "OBJ_38" = {
382 | isa = "XCConfigurationList";
383 | buildConfigurations = (
384 | "OBJ_39",
385 | "OBJ_40"
386 | );
387 | defaultConfigurationIsVisible = "0";
388 | defaultConfigurationName = "Release";
389 | };
390 | "OBJ_39" = {
391 | isa = "XCBuildConfiguration";
392 | buildSettings = {
393 | };
394 | name = "Debug";
395 | };
396 | "OBJ_4" = {
397 | isa = "XCBuildConfiguration";
398 | buildSettings = {
399 | CLANG_ENABLE_OBJC_ARC = "YES";
400 | COMBINE_HIDPI_IMAGES = "YES";
401 | COPY_PHASE_STRIP = "YES";
402 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
403 | DYLIB_INSTALL_NAME_BASE = "@rpath";
404 | GCC_OPTIMIZATION_LEVEL = "s";
405 | GCC_PREPROCESSOR_DEFINITIONS = (
406 | "$(inherited)",
407 | "SWIFT_PACKAGE=1"
408 | );
409 | MACOSX_DEPLOYMENT_TARGET = "10.10";
410 | OTHER_SWIFT_FLAGS = (
411 | "$(inherited)",
412 | "-DXcode"
413 | );
414 | PRODUCT_NAME = "$(TARGET_NAME)";
415 | SDKROOT = "macosx";
416 | SUPPORTED_PLATFORMS = (
417 | "macosx",
418 | "iphoneos",
419 | "iphonesimulator",
420 | "appletvos",
421 | "appletvsimulator",
422 | "watchos",
423 | "watchsimulator"
424 | );
425 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = (
426 | "$(inherited)",
427 | "SWIFT_PACKAGE"
428 | );
429 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
430 | USE_HEADERMAP = "NO";
431 | };
432 | name = "Release";
433 | };
434 | "OBJ_40" = {
435 | isa = "XCBuildConfiguration";
436 | buildSettings = {
437 | };
438 | name = "Release";
439 | };
440 | "OBJ_41" = {
441 | isa = "PBXTargetDependency";
442 | target = "CombineStorable::CombineStorableTests";
443 | };
444 | "OBJ_43" = {
445 | isa = "XCConfigurationList";
446 | buildConfigurations = (
447 | "OBJ_44",
448 | "OBJ_45"
449 | );
450 | defaultConfigurationIsVisible = "0";
451 | defaultConfigurationName = "Release";
452 | };
453 | "OBJ_44" = {
454 | isa = "XCBuildConfiguration";
455 | buildSettings = {
456 | CLANG_ENABLE_MODULES = "YES";
457 | EMBEDDED_CONTENT_CONTAINS_SWIFT = "YES";
458 | FRAMEWORK_SEARCH_PATHS = (
459 | "$(inherited)",
460 | "$(PLATFORM_DIR)/Developer/Library/Frameworks"
461 | );
462 | HEADER_SEARCH_PATHS = (
463 | "$(inherited)"
464 | );
465 | INFOPLIST_FILE = "CombineStorable.xcodeproj/CombineStorableTests_Info.plist";
466 | IPHONEOS_DEPLOYMENT_TARGET = "8.0";
467 | LD_RUNPATH_SEARCH_PATHS = (
468 | "$(inherited)",
469 | "@loader_path/../Frameworks",
470 | "@loader_path/Frameworks"
471 | );
472 | MACOSX_DEPLOYMENT_TARGET = "10.10";
473 | OTHER_CFLAGS = (
474 | "$(inherited)"
475 | );
476 | OTHER_LDFLAGS = (
477 | "$(inherited)"
478 | );
479 | OTHER_SWIFT_FLAGS = (
480 | "$(inherited)"
481 | );
482 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = (
483 | "$(inherited)"
484 | );
485 | SWIFT_VERSION = "5.0";
486 | TARGET_NAME = "CombineStorableTests";
487 | TVOS_DEPLOYMENT_TARGET = "9.0";
488 | WATCHOS_DEPLOYMENT_TARGET = "2.0";
489 | };
490 | name = "Debug";
491 | };
492 | "OBJ_45" = {
493 | isa = "XCBuildConfiguration";
494 | buildSettings = {
495 | CLANG_ENABLE_MODULES = "YES";
496 | EMBEDDED_CONTENT_CONTAINS_SWIFT = "YES";
497 | FRAMEWORK_SEARCH_PATHS = (
498 | "$(inherited)",
499 | "$(PLATFORM_DIR)/Developer/Library/Frameworks"
500 | );
501 | HEADER_SEARCH_PATHS = (
502 | "$(inherited)"
503 | );
504 | INFOPLIST_FILE = "CombineStorable.xcodeproj/CombineStorableTests_Info.plist";
505 | IPHONEOS_DEPLOYMENT_TARGET = "8.0";
506 | LD_RUNPATH_SEARCH_PATHS = (
507 | "$(inherited)",
508 | "@loader_path/../Frameworks",
509 | "@loader_path/Frameworks"
510 | );
511 | MACOSX_DEPLOYMENT_TARGET = "10.10";
512 | OTHER_CFLAGS = (
513 | "$(inherited)"
514 | );
515 | OTHER_LDFLAGS = (
516 | "$(inherited)"
517 | );
518 | OTHER_SWIFT_FLAGS = (
519 | "$(inherited)"
520 | );
521 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = (
522 | "$(inherited)"
523 | );
524 | SWIFT_VERSION = "5.0";
525 | TARGET_NAME = "CombineStorableTests";
526 | TVOS_DEPLOYMENT_TARGET = "9.0";
527 | WATCHOS_DEPLOYMENT_TARGET = "2.0";
528 | };
529 | name = "Release";
530 | };
531 | "OBJ_46" = {
532 | isa = "PBXSourcesBuildPhase";
533 | files = (
534 | "OBJ_47",
535 | "OBJ_48"
536 | );
537 | };
538 | "OBJ_47" = {
539 | isa = "PBXBuildFile";
540 | fileRef = "OBJ_14";
541 | };
542 | "OBJ_48" = {
543 | isa = "PBXBuildFile";
544 | fileRef = "OBJ_15";
545 | };
546 | "OBJ_49" = {
547 | isa = "PBXFrameworksBuildPhase";
548 | files = (
549 | "OBJ_50"
550 | );
551 | };
552 | "OBJ_5" = {
553 | isa = "PBXGroup";
554 | children = (
555 | "OBJ_6",
556 | "OBJ_7",
557 | "OBJ_12",
558 | "OBJ_16",
559 | "OBJ_19",
560 | "OBJ_20",
561 | "OBJ_21"
562 | );
563 | path = "";
564 | sourceTree = "";
565 | };
566 | "OBJ_50" = {
567 | isa = "PBXBuildFile";
568 | fileRef = "CombineStorable::CombineStorable::Product";
569 | };
570 | "OBJ_51" = {
571 | isa = "PBXTargetDependency";
572 | target = "CombineStorable::CombineStorable";
573 | };
574 | "OBJ_6" = {
575 | isa = "PBXFileReference";
576 | explicitFileType = "sourcecode.swift";
577 | path = "Package.swift";
578 | sourceTree = "";
579 | };
580 | "OBJ_7" = {
581 | isa = "PBXGroup";
582 | children = (
583 | "OBJ_8"
584 | );
585 | name = "Sources";
586 | path = "";
587 | sourceTree = "SOURCE_ROOT";
588 | };
589 | "OBJ_8" = {
590 | isa = "PBXGroup";
591 | children = (
592 | "OBJ_9",
593 | "OBJ_10",
594 | "OBJ_11"
595 | );
596 | name = "CombineStorable";
597 | path = "Sources/CombineStorable";
598 | sourceTree = "SOURCE_ROOT";
599 | };
600 | "OBJ_9" = {
601 | isa = "PBXFileReference";
602 | path = "NSObject+Storable.swift";
603 | sourceTree = "";
604 | };
605 | };
606 | rootObject = "OBJ_1";
607 | }
608 |
--------------------------------------------------------------------------------
/CombineStorable.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
--------------------------------------------------------------------------------
/CombineStorable.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEDidComputeMac32BitWarning
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/CombineStorable.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | IDEWorkspaceSharedSettings_AutocreateContextsIfNeeded
6 |
7 |
8 |
--------------------------------------------------------------------------------
/CombineStorable.xcodeproj/xcshareddata/xcschemes/CombineStorable-Package.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
11 |
12 |
13 |
14 |
15 |
21 |
22 |
24 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2021 hcrane
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Package.swift:
--------------------------------------------------------------------------------
1 | // swift-tools-version:5.2
2 | // The swift-tools-version declares the minimum version of Swift required to build this package.
3 |
4 | import PackageDescription
5 |
6 | let package = Package(
7 | name: "CombineStorable",
8 | products: [
9 | .library(
10 | name: "CombineStorable",
11 | targets: ["CombineStorable"]),
12 | ],
13 | dependencies: [],
14 | targets: [
15 | .target(
16 | name: "CombineStorable",
17 | dependencies: []),
18 | .testTarget(
19 | name: "CombineStorableTests",
20 | dependencies: ["CombineStorable"]),
21 | ]
22 | )
23 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Storable
2 |
3 |
4 |
5 |
6 | ## Description
7 |
8 | If you're using Combine, you've probably encountered the following code more than a few times.
9 |
10 | ```swift
11 | class Object: NSObject {
12 | var cancellables = Set()
13 |
14 | ...
15 | }
16 | ```
17 |
18 | Instead of adding a new property to every object, use this library to add it for you, to any subclass of NSObject.
19 |
20 | ### Example1
21 |
22 | ```swift
23 | final class Object: NSObject, Storable { // import Storable
24 |
25 | // You don't have to write this.
26 | // private var cancellables = Set()
27 |
28 | func exec() {
29 | Just(0)
30 | .sink(receiveCompletion: { _ in
31 | // do something
32 | }, receiveValue: { _ in
33 | // do something
34 | })
35 | .store(in: &self.cancellables) // read Set in yourself.
36 | }
37 | }
38 | ```
39 |
40 | You can read ``Set`` without member variable. It'll work just like a property: when the instance is deinit'd, the ``Set`` gets disposed. It's also a readwrite property, so you can use your own, too.
41 |
42 |
43 |
44 | Furthermore, ``.store(in: &self.cancellables)`` can be omitted.
45 |
46 | ### Example2
47 |
48 |
49 | ```swift
50 | final class Object: NSObject, Storable {
51 |
52 | func exec() {
53 | Just(0)
54 | .sink(self, receiveCompletion: { _ in // input self
55 | // do something
56 | }, receiveValue: { _ in
57 | // do something
58 | })
59 | }
60 | }
61 | ```
62 |
63 | For a detailed explanation, please read [here](https://qiita.com/hcrane/items/c9ae8427a5c6d8fc08ee).
64 |
65 |
66 | ## Installing
67 |
68 | ### CocoaPods
69 |
70 | Add the following line to your Podfile:
71 |
72 | ```
73 | pod 'CombineStorable', :git => 'git@github.com:crane-hiromu/CombineStorable.git', :branch => 'main'
74 | ```
75 |
76 | ### Carthage
77 |
78 | Add the following to your Cartfile:
79 |
80 | ```
81 | github "crane-hiromu/CombineStorable"
82 | ```
83 |
84 | #### Supplement
85 |
86 | If you fail to install, reset caches. (``rm -rf ~/Library/Caches/``)
87 |
88 |
89 |
90 | ### Swift Package Manager
91 |
92 | Add the following dependency to your Package.swift file:
93 |
94 | ```
95 | .package(url: "https://github.com/crane-hiromu/CombineStorable.git", from: "1.1.0")
96 | ```
97 |
98 | ### License
99 |
100 | MIT, of course ;-) See the LICENSE file.
101 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------
/Sources/CombineStorable/NSObject+Storable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // NSObject+Storable.swift
3 | //
4 | //
5 | // Created by h.crane on 2021/04/17.
6 | //
7 |
8 | #if canImport(Combine)
9 |
10 | import Foundation
11 | import Combine
12 |
13 | // MARK: - Private Property
14 | private var cancellableContext: UInt8 = 0
15 |
16 | // MARK: - Private Wrapper Class
17 | @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
18 | private class CancellableWrapper {
19 | let cancellables: Set
20 |
21 | init(cancellables: Set) {
22 | self.cancellables = cancellables
23 | }
24 | }
25 |
26 | // MARK: - NSObject Extension
27 | @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
28 | public extension NSObject {
29 |
30 | var cancellables: Set {
31 | get {
32 | if let wrapper = objc_getAssociatedObject(self, &cancellableContext) as? CancellableWrapper {
33 | return wrapper.cancellables
34 | }
35 | let cancellables = Set()
36 | self.cancellables = cancellables
37 | return cancellables
38 | }
39 | set {
40 | let wrapper = CancellableWrapper(cancellables: newValue)
41 | objc_setAssociatedObject(self, &cancellableContext, wrapper, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
42 | }
43 | }
44 | }
45 |
46 | #endif
47 |
--------------------------------------------------------------------------------
/Sources/CombineStorable/Publisher+Storable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Publisher+Storable.swift
3 | //
4 | //
5 | // Created by h.crane on 2021/04/17.
6 | //
7 |
8 | #if canImport(Combine)
9 |
10 | import Foundation
11 | import Combine
12 |
13 | // MARK: - Publisher Extension
14 | @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
15 | public extension Publisher {
16 |
17 | func sink(
18 | _ target: T,
19 | receiveCompletion: @escaping ((Subscribers.Completion) -> Void),
20 | receiveValue: @escaping ((Self.Output) -> Void)
21 | ) {
22 | sink(receiveCompletion: receiveCompletion, receiveValue: receiveValue)
23 | .store(in: &target.cancellables)
24 | }
25 | }
26 |
27 | // MARK: - Publisher Extension (Never)
28 | @available(iOS 13.0, OSX 10.15, *)
29 | public extension Publisher where Self.Failure == Never {
30 |
31 | func sink(
32 | _ target: T,
33 | receiveValue: @escaping ((Self.Output) -> Void)
34 | ) {
35 | sink(receiveValue: receiveValue)
36 | .store(in: &target.cancellables)
37 | }
38 |
39 | func assign(
40 | to keyPath: ReferenceWritableKeyPath,
41 | on object: O
42 | ) {
43 | assign(to: keyPath, on: object)
44 | .store(in: &object.cancellables)
45 | }
46 | }
47 |
48 | #endif
49 |
--------------------------------------------------------------------------------
/Sources/CombineStorable/Storable.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Storable.swift
3 | //
4 | //
5 | // Created by h.crane on 2021/04/17.
6 | //
7 |
8 | #if canImport(Combine)
9 |
10 | import Foundation
11 | import Combine
12 |
13 | // MARK: - Protocol
14 | @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
15 | public protocol Storable: NSObject {
16 | var cancellables: Set { get set }
17 | }
18 |
19 | #endif
20 |
--------------------------------------------------------------------------------
/Tests/CombineStorableTests/StorableTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // PublisherTests.swift
3 | //
4 | //
5 | // Created by h.crane on 2021/04/17.
6 | //
7 |
8 | #if canImport(Combine)
9 |
10 | import XCTest
11 | import Combine
12 | @testable import CombineStorable
13 |
14 | // MARK: - XCTestCase
15 | @available(OSX 10.15, iOS 13.0, tvOS 13.0, watchOS 6.0, *)
16 | final class StorableTests: XCTestCase {
17 |
18 | // MARK: Class
19 |
20 | final class StubObject: NSObject, Storable {
21 |
22 | // MARK: Store Method
23 |
24 | // case1
25 | func sinkWithStore(
26 | value: String,
27 | receiveCompletion: @escaping (String) -> Void,
28 | receiveValue: @escaping (String) -> Void
29 | ) {
30 | Just(value)
31 | .sink(receiveCompletion: { result in
32 | switch result {
33 | case .finished:
34 | receiveCompletion("finished")
35 | case .failure(_):
36 | receiveCompletion("error")
37 | }
38 | }, receiveValue: { value in
39 | receiveValue(value)
40 | })
41 | .store(in: &self.cancellables)
42 | }
43 |
44 | // case2
45 | func sinkWithStore(
46 | value: String,
47 | receiveValue: @escaping (String) -> Void
48 | ) {
49 | Just(value)
50 | .sink(receiveValue: { value in
51 | receiveValue(value)
52 | })
53 | .store(in: &self.cancellables)
54 | }
55 |
56 | // case3
57 | var valueWithStore = 0
58 |
59 | func assignWithStore(value: Int) {
60 | Just(value)
61 | .assign(to: \.valueWithStore, on: self)
62 | .store(in: &self.cancellables)
63 | }
64 |
65 | // MARK: No store Method
66 |
67 | // case1
68 | func sinkWithNoStore(
69 | value: String,
70 | receiveCompletion: @escaping (String) -> Void,
71 | receiveValue: @escaping (String) -> Void
72 | ) {
73 | Just(value)
74 | .sink(self, receiveCompletion: { result in
75 | switch result {
76 | case .finished:
77 | receiveCompletion("finished")
78 | case .failure(_):
79 | receiveCompletion("error")
80 | }
81 | }, receiveValue: { value in
82 | receiveValue(value)
83 | })
84 | }
85 |
86 | // case2
87 | func sinkWithNoStore(
88 | value: String,
89 | receiveValue: @escaping (String) -> Void
90 | ) {
91 | Just(value)
92 | .sink(self, receiveValue: { value in
93 | receiveValue(value)
94 | })
95 | }
96 |
97 | // case3
98 | var valueWithNoStore = 0
99 |
100 | func assignWithNoStore(value: Int) {
101 | Just(value)
102 | .assign(to: \.valueWithNoStore, on: self)
103 | }
104 | }
105 |
106 | // MARK: Prorperty
107 |
108 | static var allTests = [
109 | ("testSinkWithCompletionAndValueWithStore", testSinkWithCompletionAndValueWithStore),
110 | ("testSinkWithValueWithStore", testSinkWithValueWithStore),
111 | ("testAssignWithStore", testAssignWithStore),
112 | ("testSinkWithCompletionAndValueWithNoStore", testSinkWithCompletionAndValueWithNoStore),
113 | ("testSinkWithValueWithNoStore", testSinkWithValueWithNoStore),
114 | ("testAssignWithNoStore", testAssignWithNoStore)
115 | ]
116 |
117 | private let stubObject = StubObject()
118 |
119 | // MARK: Test
120 |
121 | func testSinkWithCompletionAndValueWithStore() {
122 | stubObject.sinkWithStore(value: "\(#function)", receiveCompletion: { value in
123 | XCTAssertEqual(value, "finished")
124 | }, receiveValue: { value in
125 | XCTAssertEqual(value, "\(#function)")
126 |
127 | })
128 | }
129 |
130 | func testSinkWithValueWithStore() {
131 | stubObject.sinkWithStore(value: "\(#function)", receiveValue: { value in
132 | XCTAssertEqual(value, "\(#function)")
133 | })
134 | }
135 |
136 | func testAssignWithStore() {
137 | stubObject.assignWithStore(value: 999)
138 | XCTAssertEqual(stubObject.valueWithStore, 999)
139 | }
140 |
141 | func testSinkWithCompletionAndValueWithNoStore() {
142 | stubObject.sinkWithNoStore(value: "\(#function)", receiveCompletion: { value in
143 | XCTAssertEqual(value, "finished")
144 | }, receiveValue: { value in
145 | XCTAssertEqual(value, "\(#function)")
146 |
147 | })
148 | }
149 |
150 | func testSinkWithValueWithNoStore() {
151 | stubObject.sinkWithNoStore(value: "\(#function)", receiveValue: { value in
152 | XCTAssertEqual(value, "\(#function)")
153 | })
154 | }
155 |
156 | func testAssignWithNoStore() {
157 | stubObject.assignWithNoStore(value: 9999)
158 | XCTAssertEqual(stubObject.valueWithNoStore, 9999)
159 | }
160 | }
161 |
162 | #endif
163 |
--------------------------------------------------------------------------------
/Tests/CombineStorableTests/XCTestManifests.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | #if !canImport(ObjectiveC)
4 | public func allTests() -> [XCTestCaseEntry] {
5 | return [
6 | testCase(StorableTests.allTests),
7 | ]
8 | }
9 | #endif
10 |
--------------------------------------------------------------------------------
/Tests/LinuxMain.swift:
--------------------------------------------------------------------------------
1 | import XCTest
2 |
3 | import CombineStorableTests
4 |
5 | var tests = [XCTestCaseEntry]()
6 | tests += CombineStorableTests.allTests()
7 | XCTMain(tests)
8 |
--------------------------------------------------------------------------------