mirror of
https://github.com/JohnEstropia/CoreStore.git
synced 2026-11-13 12:23:32 +01:00
added demo for classic ListMonitor
This commit is contained in:
1 parent
007da014f8
commit
8d7f282743
63 files changed
+1461
-100
No files matched your search
@@ -25,7 +25,7 @@
|
||||
B5A3915324E6537F00E7E8BD /* Menu.ItemView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3915224E6537F00E7E8BD /* Menu.ItemView.swift */; };
|
||||
B5A3915924E685EC00E7E8BD /* Classic.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3915824E685EC00E7E8BD /* Classic.swift */; };
|
||||
B5A3915B24E685FE00E7E8BD /* Modern.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3915A24E685FE00E7E8BD /* Modern.swift */; };
|
||||
B5A3915E24E6922E00E7E8BD /* Modern.PlacemarksDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3915D24E6922E00E7E8BD /* Modern.PlacemarksDemo.swift */; };
|
||||
B5A3915E24E6922E00E7E8BD /* ⭐️Modern.PlacemarksDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3915D24E6922E00E7E8BD /* ⭐️Modern.PlacemarksDemo.swift */; };
|
||||
B5A3916024E6925900E7E8BD /* Modern.PlacemarksDemo.MapView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3915F24E6925900E7E8BD /* Modern.PlacemarksDemo.MapView.swift */; };
|
||||
B5A3916224E697BA00E7E8BD /* ⭐️Modern.PlacemarksDemo.MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3916124E697BA00E7E8BD /* ⭐️Modern.PlacemarksDemo.MainView.swift */; };
|
||||
B5A3916524E698C700E7E8BD /* Modern.PlacemarksDemo.Place.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A3916424E698C700E7E8BD /* Modern.PlacemarksDemo.Place.swift */; };
|
||||
@@ -66,6 +66,16 @@
|
||||
B5A391B424E96C0A00E7E8BD /* ⭐️Modern.PokedexDemo.Form.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A391B324E96C0A00E7E8BD /* ⭐️Modern.PokedexDemo.Form.swift */; };
|
||||
B5A391B924E96F8500E7E8BD /* ⭐️Modern.PokedexDemo.Species.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A391B824E96F8500E7E8BD /* ⭐️Modern.PokedexDemo.Species.swift */; };
|
||||
B5A391BB24E970A400E7E8BD /* ⭐️Modern.PokedexDemo.PokemonType.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A391BA24E970A400E7E8BD /* ⭐️Modern.PokedexDemo.PokemonType.swift */; };
|
||||
B5A543D724FB7478000DC5E3 /* Classic.ColorsDemo.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543D624FB7478000DC5E3 /* Classic.ColorsDemo.swift */; };
|
||||
B5A543DB24FB7513000DC5E3 /* Classic.ColorsDemo.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = B5A543D924FB7513000DC5E3 /* Classic.ColorsDemo.xcdatamodeld */; };
|
||||
B5A543DD24FB78F9000DC5E3 /* Classic.ColorsDemo.Palette.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543DC24FB78F9000DC5E3 /* Classic.ColorsDemo.Palette.swift */; };
|
||||
B5A543E724FB82BB000DC5E3 /* Classic.ColorsDemo.Filter.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543E624FB82BB000DC5E3 /* Classic.ColorsDemo.Filter.swift */; };
|
||||
B5A543E924FB84A1000DC5E3 /* Classic.ColorsDemo.DetailView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543E824FB84A1000DC5E3 /* Classic.ColorsDemo.DetailView.swift */; };
|
||||
B5A543EB24FB84AF000DC5E3 /* ⭐️Classic.ColorsDemo.DetailViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543EA24FB84AF000DC5E3 /* ⭐️Classic.ColorsDemo.DetailViewController.swift */; };
|
||||
B5A543ED24FB84BE000DC5E3 /* Classic.ColorsDemo.MainView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543EC24FB84BE000DC5E3 /* Classic.ColorsDemo.MainView.swift */; };
|
||||
B5A543EF24FB84D1000DC5E3 /* Classic.ColorsDemo.LIstView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543EE24FB84D1000DC5E3 /* Classic.ColorsDemo.LIstView.swift */; };
|
||||
B5A543F124FB84DD000DC5E3 /* ⭐️Classic.ColorsDemo.ListViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543F024FB84DD000DC5E3 /* ⭐️Classic.ColorsDemo.ListViewController.swift */; };
|
||||
B5A543F324FB84EC000DC5E3 /* Classic.ColorsDemo.ItemCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5A543F224FB84EC000DC5E3 /* Classic.ColorsDemo.ItemCell.swift */; };
|
||||
B5E32C9024FA41F9003F46AD /* ImageDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E32C8F24FA41F9003F46AD /* ImageDownloader.swift */; };
|
||||
/* End PBXBuildFile section */
|
||||
|
||||
@@ -108,7 +118,7 @@
|
||||
B5A3915224E6537F00E7E8BD /* Menu.ItemView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Menu.ItemView.swift; sourceTree = "<group>"; };
|
||||
B5A3915824E685EC00E7E8BD /* Classic.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.swift; sourceTree = "<group>"; };
|
||||
B5A3915A24E685FE00E7E8BD /* Modern.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.swift; sourceTree = "<group>"; };
|
||||
B5A3915D24E6922E00E7E8BD /* Modern.PlacemarksDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PlacemarksDemo.swift; sourceTree = "<group>"; };
|
||||
B5A3915D24E6922E00E7E8BD /* ⭐️Modern.PlacemarksDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.PlacemarksDemo.swift"; sourceTree = "<group>"; };
|
||||
B5A3915F24E6925900E7E8BD /* Modern.PlacemarksDemo.MapView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PlacemarksDemo.MapView.swift; sourceTree = "<group>"; };
|
||||
B5A3916124E697BA00E7E8BD /* ⭐️Modern.PlacemarksDemo.MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.PlacemarksDemo.MainView.swift"; sourceTree = "<group>"; };
|
||||
B5A3916424E698C700E7E8BD /* Modern.PlacemarksDemo.Place.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Modern.PlacemarksDemo.Place.swift; sourceTree = "<group>"; };
|
||||
@@ -145,6 +155,16 @@
|
||||
B5A391B324E96C0A00E7E8BD /* ⭐️Modern.PokedexDemo.Form.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.PokedexDemo.Form.swift"; sourceTree = "<group>"; };
|
||||
B5A391B824E96F8500E7E8BD /* ⭐️Modern.PokedexDemo.Species.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.PokedexDemo.Species.swift"; sourceTree = "<group>"; };
|
||||
B5A391BA24E970A400E7E8BD /* ⭐️Modern.PokedexDemo.PokemonType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Modern.PokedexDemo.PokemonType.swift"; sourceTree = "<group>"; };
|
||||
B5A543D624FB7478000DC5E3 /* Classic.ColorsDemo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.ColorsDemo.swift; sourceTree = "<group>"; };
|
||||
B5A543DA24FB7513000DC5E3 /* ColorsDemo.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = ColorsDemo.xcdatamodel; sourceTree = "<group>"; };
|
||||
B5A543DC24FB78F9000DC5E3 /* Classic.ColorsDemo.Palette.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.ColorsDemo.Palette.swift; sourceTree = "<group>"; };
|
||||
B5A543E624FB82BB000DC5E3 /* Classic.ColorsDemo.Filter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.ColorsDemo.Filter.swift; sourceTree = "<group>"; };
|
||||
B5A543E824FB84A1000DC5E3 /* Classic.ColorsDemo.DetailView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.ColorsDemo.DetailView.swift; sourceTree = "<group>"; };
|
||||
B5A543EA24FB84AF000DC5E3 /* ⭐️Classic.ColorsDemo.DetailViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Classic.ColorsDemo.DetailViewController.swift"; sourceTree = "<group>"; };
|
||||
B5A543EC24FB84BE000DC5E3 /* Classic.ColorsDemo.MainView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.ColorsDemo.MainView.swift; sourceTree = "<group>"; };
|
||||
B5A543EE24FB84D1000DC5E3 /* Classic.ColorsDemo.LIstView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.ColorsDemo.LIstView.swift; sourceTree = "<group>"; };
|
||||
B5A543F024FB84DD000DC5E3 /* ⭐️Classic.ColorsDemo.ListViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "⭐️Classic.ColorsDemo.ListViewController.swift"; sourceTree = "<group>"; };
|
||||
B5A543F224FB84EC000DC5E3 /* Classic.ColorsDemo.ItemCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Classic.ColorsDemo.ItemCell.swift; sourceTree = "<group>"; };
|
||||
B5E32C8F24FA41F9003F46AD /* ImageDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ImageDownloader.swift; sourceTree = "<group>"; };
|
||||
/* End PBXFileReference section */
|
||||
|
||||
@@ -170,7 +190,7 @@
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5A3913D24E62C6C00E7E8BD /* Metadata */,
|
||||
B5A3911B24E5429200E7E8BD /* Sources */,
|
||||
B5A3911B24E5429200E7E8BD /* ⭐️Sources */,
|
||||
B5A3913E24E62CB200E7E8BD /* Resources */,
|
||||
B5A3911A24E5429200E7E8BD /* Products */,
|
||||
B5A3916624E698F900E7E8BD /* Frameworks */,
|
||||
@@ -185,15 +205,15 @@
|
||||
name = Products;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A3911B24E5429200E7E8BD /* Sources */ = {
|
||||
B5A3911B24E5429200E7E8BD /* ⭐️Sources */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5A3911C24E5429200E7E8BD /* AppDelegate.swift */,
|
||||
B5A3911E24E5429200E7E8BD /* SceneDelegate.swift */,
|
||||
B5A3915524E6858A00E7E8BD /* Demos */,
|
||||
B5A3915524E6858A00E7E8BD /* ⭐️Demos */,
|
||||
B5A3917A24E6A75F00E7E8BD /* Helpers */,
|
||||
);
|
||||
path = Sources;
|
||||
path = "⭐️Sources";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A3912424E5429300E7E8BD /* Preview Content */ = {
|
||||
@@ -234,45 +254,46 @@
|
||||
path = Menu;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A3915524E6858A00E7E8BD /* Demos */ = {
|
||||
B5A3915524E6858A00E7E8BD /* ⭐️Demos */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5A3915624E685B700E7E8BD /* Modern */,
|
||||
B5A3915724E685D300E7E8BD /* Classic */,
|
||||
B5A3915624E685B700E7E8BD /* ⭐️Modern */,
|
||||
B5A3915724E685D300E7E8BD /* ⭐️Classic */,
|
||||
);
|
||||
path = Demos;
|
||||
path = "⭐️Demos";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A3915624E685B700E7E8BD /* Modern */ = {
|
||||
B5A3915624E685B700E7E8BD /* ⭐️Modern */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5A3915A24E685FE00E7E8BD /* Modern.swift */,
|
||||
B5A3915C24E6921E00E7E8BD /* PlacemarksDemo */,
|
||||
B5A3918124E7A1EF00E7E8BD /* TimeZonesDemo */,
|
||||
B5A3918D24E7DE7A00E7E8BD /* ColorsDemo */,
|
||||
B5A391AF24E96AD600E7E8BD /* PokedexDemo */,
|
||||
B5A3915C24E6921E00E7E8BD /* ⭐️PlacemarksDemo */,
|
||||
B5A3918124E7A1EF00E7E8BD /* ⭐️TimeZonesDemo */,
|
||||
B5A3918D24E7DE7A00E7E8BD /* ⭐️ColorsDemo */,
|
||||
B5A391AF24E96AD600E7E8BD /* ⭐️PokedexDemo */,
|
||||
);
|
||||
path = Modern;
|
||||
path = "⭐️Modern";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A3915724E685D300E7E8BD /* Classic */ = {
|
||||
B5A3915724E685D300E7E8BD /* ⭐️Classic */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5A3915824E685EC00E7E8BD /* Classic.swift */,
|
||||
B5A543D524FB73B2000DC5E3 /* ⭐️ColorsDemo */,
|
||||
);
|
||||
path = Classic;
|
||||
path = "⭐️Classic";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A3915C24E6921E00E7E8BD /* PlacemarksDemo */ = {
|
||||
B5A3915C24E6921E00E7E8BD /* ⭐️PlacemarksDemo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5A3915D24E6922E00E7E8BD /* Modern.PlacemarksDemo.swift */,
|
||||
B5A3915D24E6922E00E7E8BD /* ⭐️Modern.PlacemarksDemo.swift */,
|
||||
B5A3916124E697BA00E7E8BD /* ⭐️Modern.PlacemarksDemo.MainView.swift */,
|
||||
B5A3915F24E6925900E7E8BD /* Modern.PlacemarksDemo.MapView.swift */,
|
||||
B5A3917D24E7728400E7E8BD /* Modern.PlacemarksDemo.Geocoder.swift */,
|
||||
B5A3916324E698B300E7E8BD /* Models */,
|
||||
);
|
||||
path = PlacemarksDemo;
|
||||
path = "⭐️PlacemarksDemo";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A3916324E698B300E7E8BD /* Models */ = {
|
||||
@@ -308,7 +329,7 @@
|
||||
path = Helpers;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A3918124E7A1EF00E7E8BD /* TimeZonesDemo */ = {
|
||||
B5A3918124E7A1EF00E7E8BD /* ⭐️TimeZonesDemo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5A3918224E7A21800E7E8BD /* Modern.TimeZonesDemo.swift */,
|
||||
@@ -317,7 +338,7 @@
|
||||
B5A3918B24E7B44B00E7E8BD /* Modern.TimeZonesDemo.ItemView.swift */,
|
||||
B5A3918424E7A53300E7E8BD /* Models */,
|
||||
);
|
||||
path = TimeZonesDemo;
|
||||
path = "⭐️TimeZonesDemo";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A3918424E7A53300E7E8BD /* Models */ = {
|
||||
@@ -328,17 +349,17 @@
|
||||
name = Models;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A3918D24E7DE7A00E7E8BD /* ColorsDemo */ = {
|
||||
B5A3918D24E7DE7A00E7E8BD /* ⭐️ColorsDemo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5A3918E24E7E06500E7E8BD /* Modern.ColorsDemo.swift */,
|
||||
B5A3919724E7E67000E7E8BD /* Modern.ColorsDemo.Filter.swift */,
|
||||
B5A391A524E8F4EA00E7E8BD /* ⭐️Modern.ColorsDemo.MainView.swift */,
|
||||
B5A3919C24E8EE9000E7E8BD /* UIKit */,
|
||||
B5A3919B24E8EE8100E7E8BD /* SwiftUI */,
|
||||
B5A3919C24E8EE9000E7E8BD /* ⭐️UIKit */,
|
||||
B5A3919B24E8EE8100E7E8BD /* ⭐️SwiftUI */,
|
||||
B5A3919024E7E0B000E7E8BD /* Models */,
|
||||
);
|
||||
path = ColorsDemo;
|
||||
path = "⭐️ColorsDemo";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A3919024E7E0B000E7E8BD /* Models */ = {
|
||||
@@ -349,7 +370,7 @@
|
||||
name = Models;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A3919B24E8EE8100E7E8BD /* SwiftUI */ = {
|
||||
B5A3919B24E8EE8100E7E8BD /* ⭐️SwiftUI */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5A3919D24E8EEB600E7E8BD /* Modern.ColorsDemo.SwiftUI.swift */,
|
||||
@@ -357,10 +378,10 @@
|
||||
B5A3919524E7E4AC00E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.ItemView.swift */,
|
||||
B5A3919924E8207A00E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.DetailView.swift */,
|
||||
);
|
||||
name = SwiftUI;
|
||||
name = "⭐️SwiftUI";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A3919C24E8EE9000E7E8BD /* UIKit */ = {
|
||||
B5A3919C24E8EE9000E7E8BD /* ⭐️UIKit */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5A3919F24E8F00A00E7E8BD /* Modern.ColorsDemo.UIKit.swift */,
|
||||
@@ -370,10 +391,10 @@
|
||||
B5A391AB24E9143B00E7E8BD /* Modern.ColorsDemo.UIKit.DetailView.swift */,
|
||||
B5A391AD24E9150F00E7E8BD /* ⭐️Modern.ColorsDemo.UIKit.DetailViewController.swift */,
|
||||
);
|
||||
name = UIKit;
|
||||
name = "⭐️UIKit";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A391AF24E96AD600E7E8BD /* PokedexDemo */ = {
|
||||
B5A391AF24E96AD600E7E8BD /* ⭐️PokedexDemo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5A391B024E96AF600E7E8BD /* Modern.PokedexDemo.swift */,
|
||||
@@ -382,29 +403,54 @@
|
||||
B566C8E724F9D406001134A1 /* Modern.PokedexDemo.ListView.swift */,
|
||||
B566C8E924F9D412001134A1 /* Modern.PokedexDemo.ListViewController.swift */,
|
||||
B566C8EB24F9D694001134A1 /* Modern.PokedexDemo.ItemCell.swift */,
|
||||
B5A391B224E96B7400E7E8BD /* Models */,
|
||||
B5A391B224E96B7400E7E8BD /* ⭐️Models */,
|
||||
);
|
||||
path = PokedexDemo;
|
||||
path = "⭐️PokedexDemo";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A391B224E96B7400E7E8BD /* Models */ = {
|
||||
B5A391B224E96B7400E7E8BD /* ⭐️Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B531EFE824EB5A52005F247D /* ⭐️Modern.PokedexDemo.PokedexEntry.swift */,
|
||||
B566C8ED24FA1EA3001134A1 /* Modern.PokedexDemo.Details.swift */,
|
||||
B5A391B824E96F8500E7E8BD /* ⭐️Modern.PokedexDemo.Species.swift */,
|
||||
B5A391B324E96C0A00E7E8BD /* ⭐️Modern.PokedexDemo.Form.swift */,
|
||||
B5A391B724E96E8600E7E8BD /* Attributes */,
|
||||
B5A391B724E96E8600E7E8BD /* ⭐️Attributes */,
|
||||
);
|
||||
name = Models;
|
||||
name = "⭐️Models";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A391B724E96E8600E7E8BD /* Attributes */ = {
|
||||
B5A391B724E96E8600E7E8BD /* ⭐️Attributes */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5A391BA24E970A400E7E8BD /* ⭐️Modern.PokedexDemo.PokemonType.swift */,
|
||||
);
|
||||
name = Attributes;
|
||||
name = "⭐️Attributes";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A543D524FB73B2000DC5E3 /* ⭐️ColorsDemo */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5A543D624FB7478000DC5E3 /* Classic.ColorsDemo.swift */,
|
||||
B5A543E624FB82BB000DC5E3 /* Classic.ColorsDemo.Filter.swift */,
|
||||
B5A543EC24FB84BE000DC5E3 /* Classic.ColorsDemo.MainView.swift */,
|
||||
B5A543EE24FB84D1000DC5E3 /* Classic.ColorsDemo.LIstView.swift */,
|
||||
B5A543F024FB84DD000DC5E3 /* ⭐️Classic.ColorsDemo.ListViewController.swift */,
|
||||
B5A543F224FB84EC000DC5E3 /* Classic.ColorsDemo.ItemCell.swift */,
|
||||
B5A543E824FB84A1000DC5E3 /* Classic.ColorsDemo.DetailView.swift */,
|
||||
B5A543EA24FB84AF000DC5E3 /* ⭐️Classic.ColorsDemo.DetailViewController.swift */,
|
||||
B5A543D824FB7483000DC5E3 /* Models */,
|
||||
);
|
||||
path = "⭐️ColorsDemo";
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
B5A543D824FB7483000DC5E3 /* Models */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
B5A543D924FB7513000DC5E3 /* Classic.ColorsDemo.xcdatamodeld */,
|
||||
B5A543DC24FB78F9000DC5E3 /* Classic.ColorsDemo.Palette.swift */,
|
||||
);
|
||||
name = Models;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
/* End PBXGroup section */
|
||||
@@ -484,19 +530,25 @@
|
||||
B5A3918024E787D900E7E8BD /* InstructionsView.swift in Sources */,
|
||||
B5A3917C24E6A76C00E7E8BD /* LazyView.swift in Sources */,
|
||||
B5A3913424E6170500E7E8BD /* Menu.swift in Sources */,
|
||||
B5A543DB24FB7513000DC5E3 /* Classic.ColorsDemo.xcdatamodeld in Sources */,
|
||||
B5A3915B24E685FE00E7E8BD /* Modern.swift in Sources */,
|
||||
B5A543D724FB7478000DC5E3 /* Classic.ColorsDemo.swift in Sources */,
|
||||
B5A3911F24E5429200E7E8BD /* SceneDelegate.swift in Sources */,
|
||||
B5A3915324E6537F00E7E8BD /* Menu.ItemView.swift in Sources */,
|
||||
B5A3912124E5429200E7E8BD /* Menu.MainView.swift in Sources */,
|
||||
B531EFE724EA762D005F247D /* Menu.PlaceholderView.swift in Sources */,
|
||||
B5A3918F24E7E06500E7E8BD /* Modern.ColorsDemo.swift in Sources */,
|
||||
B5A3915E24E6922E00E7E8BD /* Modern.PlacemarksDemo.swift in Sources */,
|
||||
B5A543EF24FB84D1000DC5E3 /* Classic.ColorsDemo.LIstView.swift in Sources */,
|
||||
B5A3915E24E6922E00E7E8BD /* ⭐️Modern.PlacemarksDemo.swift in Sources */,
|
||||
B5A543F324FB84EC000DC5E3 /* Classic.ColorsDemo.ItemCell.swift in Sources */,
|
||||
B5A391B124E96AF600E7E8BD /* Modern.PokedexDemo.swift in Sources */,
|
||||
B5A3918324E7A21800E7E8BD /* Modern.TimeZonesDemo.swift in Sources */,
|
||||
B5A3919824E7E67000E7E8BD /* Modern.ColorsDemo.Filter.swift in Sources */,
|
||||
B5A3919224E7E0C600E7E8BD /* Modern.ColorsDemo.Palette.swift in Sources */,
|
||||
B5A3919E24E8EEB600E7E8BD /* Modern.ColorsDemo.SwiftUI.swift in Sources */,
|
||||
B5A391A024E8F00A00E7E8BD /* Modern.ColorsDemo.UIKit.swift in Sources */,
|
||||
B5A543E724FB82BB000DC5E3 /* Classic.ColorsDemo.Filter.swift in Sources */,
|
||||
B5A543ED24FB84BE000DC5E3 /* Classic.ColorsDemo.MainView.swift in Sources */,
|
||||
B5A3917E24E7728400E7E8BD /* Modern.PlacemarksDemo.Geocoder.swift in Sources */,
|
||||
B5A3916024E6925900E7E8BD /* Modern.PlacemarksDemo.MapView.swift in Sources */,
|
||||
B5A3916524E698C700E7E8BD /* Modern.PlacemarksDemo.Place.swift in Sources */,
|
||||
@@ -510,6 +562,7 @@
|
||||
B5A3918624E7A54A00E7E8BD /* Modern.TimeZonesDemo.TimeZone.swift in Sources */,
|
||||
B5A391A624E8F4EA00E7E8BD /* ⭐️Modern.ColorsDemo.MainView.swift in Sources */,
|
||||
B5A3916224E697BA00E7E8BD /* ⭐️Modern.PlacemarksDemo.MainView.swift in Sources */,
|
||||
B5A543EB24FB84AF000DC5E3 /* ⭐️Classic.ColorsDemo.DetailViewController.swift in Sources */,
|
||||
B5A391B424E96C0A00E7E8BD /* ⭐️Modern.PokedexDemo.Form.swift in Sources */,
|
||||
B531EFE924EB5A53005F247D /* ⭐️Modern.PokedexDemo.PokedexEntry.swift in Sources */,
|
||||
B5A391BB24E970A400E7E8BD /* ⭐️Modern.PokedexDemo.PokemonType.swift in Sources */,
|
||||
@@ -519,11 +572,14 @@
|
||||
B5A391AC24E9143B00E7E8BD /* Modern.ColorsDemo.UIKit.DetailView.swift in Sources */,
|
||||
B5A391AA24E9104300E7E8BD /* Modern.ColorsDemo.UIKit.ItemCell.swift in Sources */,
|
||||
B5A391A424E8F04300E7E8BD /* Modern.ColorsDemo.UIKit.ListView.swift in Sources */,
|
||||
B5A543E924FB84A1000DC5E3 /* Classic.ColorsDemo.DetailView.swift in Sources */,
|
||||
B5A3919A24E8207A00E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.DetailView.swift in Sources */,
|
||||
B5A543F124FB84DD000DC5E3 /* ⭐️Classic.ColorsDemo.ListViewController.swift in Sources */,
|
||||
B5A3919624E7E4AC00E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.ItemView.swift in Sources */,
|
||||
B5A3919424E7E36700E7E8BD /* ⭐️Modern.ColorsDemo.SwiftUI.ListView.swift in Sources */,
|
||||
B5A391AE24E9150F00E7E8BD /* ⭐️Modern.ColorsDemo.UIKit.DetailViewController.swift in Sources */,
|
||||
B5A391A224E8F01F00E7E8BD /* ⭐️Modern.ColorsDemo.UIKit.ListViewController.swift in Sources */,
|
||||
B5A543DD24FB78F9000DC5E3 /* Classic.ColorsDemo.Palette.swift in Sources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
};
|
||||
@@ -717,6 +773,19 @@
|
||||
defaultConfigurationName = Release;
|
||||
};
|
||||
/* End XCConfigurationList section */
|
||||
|
||||
/* Begin XCVersionGroup section */
|
||||
B5A543D924FB7513000DC5E3 /* Classic.ColorsDemo.xcdatamodeld */ = {
|
||||
isa = XCVersionGroup;
|
||||
children = (
|
||||
B5A543DA24FB7513000DC5E3 /* ColorsDemo.xcdatamodel */,
|
||||
);
|
||||
currentVersion = B5A543DA24FB7513000DC5E3 /* ColorsDemo.xcdatamodel */;
|
||||
path = Classic.ColorsDemo.xcdatamodeld;
|
||||
sourceTree = "<group>";
|
||||
versionGroupType = wrapper.xcdatamodel;
|
||||
};
|
||||
/* End XCVersionGroup section */
|
||||
};
|
||||
rootObject = B5A3910F24E5424E00E7E8BD /* Project object */;
|
||||
}
|
||||
File renamed without changes.
+2
-5
@@ -1,9 +1,6 @@
|
||||
//
|
||||
// ImageDownloader.swift
|
||||
// Demo
|
||||
//
|
||||
// Created by John Rommel Estropia on 2020/08/29.
|
||||
//
|
||||
// Demo
|
||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
||||
|
||||
import Foundation
|
||||
import UIKit
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
+8
-19
@@ -79,34 +79,23 @@ extension Menu {
|
||||
}
|
||||
Section(header: Text("Classic (NSManagedObject subclasses)")) {
|
||||
Menu.ItemView(
|
||||
title: "Placemarks (Swift)",
|
||||
title: "Placemarks",
|
||||
subtitle: "Making changes using transactions in Swift",
|
||||
destination: { EmptyView() }
|
||||
)
|
||||
Menu.ItemView(
|
||||
title: "Placemarks (Objective-C)",
|
||||
subtitle: "Making changes using transactions in Objective-C",
|
||||
destination: { EmptyView() }
|
||||
)
|
||||
.disabled(true)
|
||||
Menu.ItemView(
|
||||
title: "Time Zones",
|
||||
subtitle: "Fetching objects and Querying raw values",
|
||||
destination: { EmptyView() }
|
||||
)
|
||||
.disabled(true)
|
||||
Menu.ItemView(
|
||||
title: "Colors (Swift)",
|
||||
subtitle: "Observing list changes and single-object changes in Swift",
|
||||
destination: { EmptyView() }
|
||||
)
|
||||
Menu.ItemView(
|
||||
title: "Colors (Objective-C)",
|
||||
subtitle: "Observing list changes and single-object changes in Objective-C",
|
||||
destination: { EmptyView() }
|
||||
)
|
||||
Menu.ItemView(
|
||||
title: "Pokedex API",
|
||||
subtitle: "Importing JSON data from external source",
|
||||
destination: { EmptyView() }
|
||||
title: "Colors",
|
||||
subtitle: "Observing list changes and single-object changes using ListMonitor",
|
||||
destination: {
|
||||
Classic.ColorsDemo.MainView()
|
||||
}
|
||||
)
|
||||
}
|
||||
Section(header: Text("Advanced")) {
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -0,0 +1,79 @@
|
||||
//
|
||||
// Demo
|
||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
||||
|
||||
import Combine
|
||||
import CoreStore
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - Classic.ColorsDemo
|
||||
|
||||
extension Classic.ColorsDemo {
|
||||
|
||||
// MARK: - Classic.ColorsDemo.DetailView
|
||||
|
||||
struct DetailView: UIViewControllerRepresentable {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
init(_ palette: ObjectMonitor<Classic.ColorsDemo.Palette>) {
|
||||
|
||||
self.palette = palette
|
||||
}
|
||||
|
||||
// MARK: UIViewControllerRepresentable
|
||||
|
||||
typealias UIViewControllerType = Classic.ColorsDemo.DetailViewController
|
||||
|
||||
func makeUIViewController(context: Self.Context) -> UIViewControllerType {
|
||||
|
||||
return UIViewControllerType(self.palette)
|
||||
}
|
||||
|
||||
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Self.Context) {
|
||||
|
||||
uiViewController.palette = self.palette
|
||||
}
|
||||
|
||||
static func dismantleUIViewController(_ uiViewController: UIViewControllerType, coordinator: Void) {}
|
||||
|
||||
func makeCoordinator() -> ObjectMonitor<Classic.ColorsDemo.Palette> {
|
||||
|
||||
return self.palette
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let palette: ObjectMonitor<Classic.ColorsDemo.Palette>
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
struct _Demo_Classic_ColorsDemo_DetailView_Preview: PreviewProvider {
|
||||
|
||||
// MARK: PreviewProvider
|
||||
|
||||
static var previews: some View {
|
||||
|
||||
try! Classic.ColorsDemo.dataStack.perform(
|
||||
synchronous: { transaction in
|
||||
|
||||
guard (try transaction.fetchCount(From<Modern.ColorsDemo.Palette>())) <= 0 else {
|
||||
return
|
||||
}
|
||||
let palette = transaction.create(Into<Modern.ColorsDemo.Palette>())
|
||||
palette.setRandomHue()
|
||||
}
|
||||
)
|
||||
|
||||
return Classic.ColorsDemo.DetailView(
|
||||
Classic.ColorsDemo.dataStack.monitorObject(
|
||||
Classic.ColorsDemo.palettesMonitor[0, 0]
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,36 @@
|
||||
//
|
||||
// Demo
|
||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
||||
|
||||
import CoreStore
|
||||
|
||||
|
||||
// MARK: - Classic.ColorsDemo
|
||||
|
||||
extension Classic.ColorsDemo {
|
||||
|
||||
// MARK: - Classic.ColorsDemo.Filter
|
||||
|
||||
enum Filter: String, CaseIterable {
|
||||
|
||||
case all = "All Colors"
|
||||
case light = "Light Colors"
|
||||
case dark = "Dark Colors"
|
||||
|
||||
func next() -> Filter {
|
||||
|
||||
let allCases = Self.allCases
|
||||
return allCases[(allCases.firstIndex(of: self)! + 1) % allCases.count]
|
||||
}
|
||||
|
||||
func whereClause() -> Where<Classic.ColorsDemo.Palette> {
|
||||
|
||||
switch self {
|
||||
|
||||
case .all: return .init()
|
||||
case .light: return (\.brightness >= 0.9)
|
||||
case .dark: return (\.brightness <= 0.4)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// Demo
|
||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
||||
|
||||
import CoreStore
|
||||
import UIKit
|
||||
|
||||
|
||||
// MARK: - Classic.ColorsDemo
|
||||
|
||||
extension Classic.ColorsDemo {
|
||||
|
||||
// MARK: - Classic.ColorsDemo.ItemCell
|
||||
|
||||
final class ItemCell: UITableViewCell {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
static let reuseIdentifier: String = NSStringFromClass(Classic.ColorsDemo.ItemCell.self)
|
||||
|
||||
func setPalette(_ palette: Classic.ColorsDemo.Palette) {
|
||||
|
||||
self.contentView.backgroundColor = palette.color
|
||||
self.textLabel?.text = palette.colorText
|
||||
self.textLabel?.textColor = palette.brightness > 0.6 ? .black : .white
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,89 @@
|
||||
//
|
||||
// Demo
|
||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
||||
|
||||
import CoreStore
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - Classic.ColorsDemo
|
||||
|
||||
extension Classic.ColorsDemo {
|
||||
|
||||
// MARK: - Classic.ColorsDemo.ListView
|
||||
|
||||
struct ListView: UIViewControllerRepresentable {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
init(
|
||||
listMonitor: ListMonitor<Classic.ColorsDemo.Palette>,
|
||||
onPaletteTapped: @escaping (Classic.ColorsDemo.Palette) -> Void
|
||||
) {
|
||||
|
||||
self.listMonitor = listMonitor
|
||||
self.onPaletteTapped = onPaletteTapped
|
||||
}
|
||||
|
||||
|
||||
// MARK: UIViewControllerRepresentable
|
||||
|
||||
typealias UIViewControllerType = Classic.ColorsDemo.ListViewController
|
||||
|
||||
func makeUIViewController(context: Self.Context) -> UIViewControllerType {
|
||||
|
||||
return UIViewControllerType(
|
||||
listMonitor: self.listMonitor,
|
||||
onPaletteTapped: self.onPaletteTapped
|
||||
)
|
||||
}
|
||||
|
||||
func updateUIViewController(_ uiViewController: UIViewControllerType, context: Self.Context) {
|
||||
|
||||
uiViewController.setEditing(
|
||||
context.environment.editMode?.wrappedValue.isEditing == true,
|
||||
animated: true
|
||||
)
|
||||
}
|
||||
|
||||
static func dismantleUIViewController(_ uiViewController: UIViewControllerType, coordinator: Void) {}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let listMonitor: ListMonitor<Classic.ColorsDemo.Palette>
|
||||
private let onPaletteTapped: (Classic.ColorsDemo.Palette) -> Void
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
struct _Demo_Classic_ColorsDemo_ListView_Preview: PreviewProvider {
|
||||
|
||||
// MARK: PreviewProvider
|
||||
|
||||
static var previews: some View {
|
||||
|
||||
let minimumSamples = 10
|
||||
try! Classic.ColorsDemo.dataStack.perform(
|
||||
synchronous: { transaction in
|
||||
|
||||
let missing = minimumSamples
|
||||
- (try transaction.fetchCount(From<Classic.ColorsDemo.Palette>()))
|
||||
guard missing > 0 else {
|
||||
return
|
||||
}
|
||||
for _ in 0..<missing {
|
||||
|
||||
let palette = transaction.create(Into<Classic.ColorsDemo.Palette>())
|
||||
palette.setRandomHue()
|
||||
}
|
||||
}
|
||||
)
|
||||
return Classic.ColorsDemo.ListView(
|
||||
listMonitor: Classic.ColorsDemo.palettesMonitor,
|
||||
onPaletteTapped: { _ in }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,247 @@
|
||||
//
|
||||
// Demo
|
||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
||||
|
||||
import CoreStore
|
||||
import SwiftUI
|
||||
|
||||
// MARK: - Classic.ColorsDemo
|
||||
|
||||
extension Classic.ColorsDemo {
|
||||
|
||||
// MARK: - Classic.ColorsDemo.MainView
|
||||
|
||||
struct MainView: View {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
init() {
|
||||
|
||||
let listMonitor = Classic.ColorsDemo.palettesMonitor
|
||||
self.listMonitor = listMonitor
|
||||
self.listHelper = .init(listMonitor: listMonitor)
|
||||
self._filter = Binding(
|
||||
get: { Classic.ColorsDemo.filter },
|
||||
set: { Classic.ColorsDemo.filter = $0 }
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// MARK: View
|
||||
|
||||
var body: some View {
|
||||
let detailView: AnyView
|
||||
if let selectedObject = self.listHelper.selectedObject() {
|
||||
|
||||
detailView = AnyView(
|
||||
Classic.ColorsDemo.DetailView(selectedObject)
|
||||
)
|
||||
}
|
||||
else {
|
||||
|
||||
detailView = AnyView(EmptyView())
|
||||
}
|
||||
let listMonitor = self.listMonitor
|
||||
return VStack(spacing: 0) {
|
||||
Classic.ColorsDemo.ListView
|
||||
.init(
|
||||
listMonitor: listMonitor,
|
||||
onPaletteTapped: {
|
||||
|
||||
self.listHelper.setSelectedPalette($0)
|
||||
}
|
||||
)
|
||||
.navigationBarTitle(
|
||||
Text("Colors (\(self.listHelper.count) objects)")
|
||||
)
|
||||
.frame(minHeight: 0, maxHeight: .infinity)
|
||||
.edgesIgnoringSafeArea(.vertical)
|
||||
detailView
|
||||
.edgesIgnoringSafeArea(.all)
|
||||
.frame(minHeight: 0, maxHeight: .infinity)
|
||||
}
|
||||
.navigationBarItems(
|
||||
leading: HStack {
|
||||
EditButton()
|
||||
Button(
|
||||
action: { self.clearColors() },
|
||||
label: { Text("Clear") }
|
||||
)
|
||||
},
|
||||
trailing: HStack {
|
||||
Button(
|
||||
action: { self.changeFilter() },
|
||||
label: { Text(self.filter.rawValue) }
|
||||
)
|
||||
Button(
|
||||
action: { self.shuffleColors() },
|
||||
label: { Text("Shuffle") }
|
||||
)
|
||||
Button(
|
||||
action: { self.addColor() },
|
||||
label: { Text("Add") }
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let listMonitor: ListMonitor<Classic.ColorsDemo.Palette>
|
||||
|
||||
@ObservedObject
|
||||
private var listHelper: ListHelper
|
||||
|
||||
@Binding
|
||||
private var filter: Classic.ColorsDemo.Filter
|
||||
|
||||
private func changeFilter() {
|
||||
|
||||
Classic.ColorsDemo.filter = Classic.ColorsDemo.filter.next()
|
||||
}
|
||||
|
||||
private func clearColors() {
|
||||
|
||||
Classic.ColorsDemo.dataStack.perform(
|
||||
asynchronous: { transaction in
|
||||
|
||||
try transaction.deleteAll(From<Classic.ColorsDemo.Palette>())
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
|
||||
private func addColor() {
|
||||
|
||||
Classic.ColorsDemo.dataStack.perform(
|
||||
asynchronous: { transaction in
|
||||
|
||||
_ = transaction.create(Into<Classic.ColorsDemo.Palette>())
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
|
||||
private func shuffleColors() {
|
||||
|
||||
Classic.ColorsDemo.dataStack.perform(
|
||||
asynchronous: { transaction in
|
||||
|
||||
for palette in try transaction.fetchAll(From<Classic.ColorsDemo.Palette>()) {
|
||||
|
||||
palette.setRandomHue()
|
||||
}
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// MARK: - Classic.ColorsDemo.MainView.ListHelper
|
||||
|
||||
fileprivate final class ListHelper: ObservableObject, ListObjectObserver {
|
||||
|
||||
// MARK: FilePrivate
|
||||
|
||||
fileprivate private(set) var count: Int = 0
|
||||
|
||||
fileprivate init(listMonitor: ListMonitor<Classic.ColorsDemo.Palette>) {
|
||||
|
||||
listMonitor.addObserver(self)
|
||||
self.count = listMonitor.numberOfObjects()
|
||||
}
|
||||
|
||||
fileprivate func selectedObject() -> ObjectMonitor<Classic.ColorsDemo.Palette>? {
|
||||
|
||||
return self.selectedPalette.flatMap {
|
||||
|
||||
guard !$0.isDeleted else {
|
||||
|
||||
return nil
|
||||
}
|
||||
return Classic.ColorsDemo.dataStack.monitorObject($0)
|
||||
}
|
||||
}
|
||||
|
||||
fileprivate func setSelectedPalette(_ palette: Classic.ColorsDemo.Palette?) {
|
||||
|
||||
guard self.selectedPalette != palette else {
|
||||
|
||||
return
|
||||
}
|
||||
self.objectWillChange.send()
|
||||
if let palette = palette, !palette.isDeleted {
|
||||
|
||||
self.selectedPalette = palette
|
||||
}
|
||||
else {
|
||||
|
||||
self.selectedPalette = nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: ListObserver
|
||||
|
||||
typealias ListEntityType = Classic.ColorsDemo.Palette
|
||||
|
||||
func listMonitorDidChange(_ monitor: ListMonitor<Classic.ColorsDemo.Palette>) {
|
||||
|
||||
self.objectWillChange.send()
|
||||
self.count = monitor.numberOfObjects()
|
||||
}
|
||||
|
||||
func listMonitorDidRefetch(_ monitor: ListMonitor<ListEntityType>) {
|
||||
|
||||
self.objectWillChange.send()
|
||||
self.count = monitor.numberOfObjects()
|
||||
}
|
||||
|
||||
// MARK: ListObjectObserver
|
||||
|
||||
func listMonitor(_ monitor: ListMonitor<Classic.ColorsDemo.Palette>, didDeleteObject object: Classic.ColorsDemo.Palette, fromIndexPath indexPath: IndexPath) {
|
||||
|
||||
if self.selectedPalette == object {
|
||||
|
||||
self.setSelectedPalette(nil)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private var selectedPalette: Classic.ColorsDemo.Palette?
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
|
||||
struct _Demo_Classic_ColorsDemo_MainView_Preview: PreviewProvider {
|
||||
|
||||
// MARK: PreviewProvider
|
||||
|
||||
static var previews: some View {
|
||||
|
||||
let minimumSamples = 10
|
||||
try! Classic.ColorsDemo.dataStack.perform(
|
||||
synchronous: { transaction in
|
||||
|
||||
let missing = minimumSamples
|
||||
- (try transaction.fetchCount(From<Classic.ColorsDemo.Palette>()))
|
||||
guard missing > 0 else {
|
||||
return
|
||||
}
|
||||
for _ in 0..<missing {
|
||||
|
||||
let palette = transaction.create(Into<Classic.ColorsDemo.Palette>())
|
||||
palette.setRandomHue()
|
||||
}
|
||||
}
|
||||
)
|
||||
return Classic.ColorsDemo.MainView()
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,101 @@
|
||||
//
|
||||
// Demo
|
||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
||||
|
||||
import CoreData
|
||||
import UIKit
|
||||
|
||||
|
||||
// MARK: - Classic.ColorsDemo.Palette
|
||||
|
||||
@objc(Classic_ColorsDemo_Palette)
|
||||
final class Classic_ColorsDemo_Palette: NSManagedObject {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
@NSManaged
|
||||
dynamic var hue: Float
|
||||
|
||||
@NSManaged
|
||||
dynamic var saturation: Float
|
||||
|
||||
@NSManaged
|
||||
dynamic var brightness: Float
|
||||
|
||||
@objc
|
||||
dynamic var colorGroup: String! {
|
||||
|
||||
let key = #keyPath(colorGroup)
|
||||
if case let value as String = self.getValue(forKvcKey: key) {
|
||||
|
||||
return value
|
||||
}
|
||||
let newValue: String
|
||||
switch self.hue * 359 {
|
||||
|
||||
case 0 ..< 20: newValue = "Lower Reds"
|
||||
case 20 ..< 57: newValue = "Oranges and Browns"
|
||||
case 57 ..< 90: newValue = "Yellow-Greens"
|
||||
case 90 ..< 159: newValue = "Greens"
|
||||
case 159 ..< 197: newValue = "Blue-Greens"
|
||||
case 197 ..< 241: newValue = "Blues"
|
||||
case 241 ..< 297: newValue = "Violets"
|
||||
case 297 ..< 331: newValue = "Magentas"
|
||||
default: newValue = "Upper Reds"
|
||||
}
|
||||
self.setPrimitiveValue(newValue, forKey: key)
|
||||
return newValue
|
||||
}
|
||||
|
||||
var color: UIColor {
|
||||
|
||||
let newValue = UIColor(
|
||||
hue: CGFloat(self.hue),
|
||||
saturation: CGFloat(self.saturation),
|
||||
brightness: CGFloat(self.brightness),
|
||||
alpha: 1.0
|
||||
)
|
||||
return newValue
|
||||
}
|
||||
|
||||
var colorText: String {
|
||||
|
||||
let newValue: String = "H: \(self.hue * 359)˚, S: \(round(self.saturation * 100.0))%, B: \(round(self.brightness * 100.0))%"
|
||||
return newValue
|
||||
}
|
||||
|
||||
func setRandomHue() {
|
||||
|
||||
self.hue = Self.randomHue()
|
||||
}
|
||||
|
||||
|
||||
// MARK: NSManagedObject
|
||||
|
||||
public override func awakeFromInsert() {
|
||||
|
||||
super.awakeFromInsert()
|
||||
|
||||
self.hue = Self.randomHue()
|
||||
self.saturation = Self.randomSaturation()
|
||||
self.brightness = Self.randomBrightness()
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private static func randomHue() -> Float {
|
||||
|
||||
return Float.random(in: 0.0 ... 1.0)
|
||||
}
|
||||
|
||||
private static func randomSaturation() -> Float {
|
||||
|
||||
return Float.random(in: 0.4 ... 1.0)
|
||||
}
|
||||
|
||||
private static func randomBrightness() -> Float {
|
||||
|
||||
return Float.random(in: 0.0 ... 1.0)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
//
|
||||
// Demo
|
||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
||||
|
||||
import CoreStore
|
||||
|
||||
// MARK: - Classic
|
||||
|
||||
extension Classic {
|
||||
|
||||
// MARK: - Classic.ColorsDemo
|
||||
|
||||
/**
|
||||
Sample usages for observing lists or single instances of `NSManagedObject`s
|
||||
*/
|
||||
enum ColorsDemo {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
typealias Palette = Classic_ColorsDemo_Palette
|
||||
|
||||
static let dataStack: DataStack = {
|
||||
|
||||
let dataStack = DataStack(
|
||||
xcodeModelName: "Classic.ColorsDemo",
|
||||
bundle: Bundle(for: Palette.self)
|
||||
)
|
||||
|
||||
/**
|
||||
- Important: `addStorageAndWait(_:)` was used here to simplify initializing the demo, but in practice the asynchronous function variants are recommended.
|
||||
*/
|
||||
try! dataStack.addStorageAndWait(
|
||||
SQLiteStore(
|
||||
fileName: "Classic.ColorsDemo.sqlite",
|
||||
localStorageOptions: .recreateStoreOnModelMismatch
|
||||
)
|
||||
)
|
||||
return dataStack
|
||||
}()
|
||||
|
||||
static let palettesMonitor: ListMonitor<Classic.ColorsDemo.Palette> = Classic.ColorsDemo.dataStack.monitorSectionedList(
|
||||
From<Classic.ColorsDemo.Palette>()
|
||||
.sectionBy(\.colorGroup)
|
||||
.where(Classic.ColorsDemo.filter.whereClause())
|
||||
.orderBy(.ascending(\.hue))
|
||||
)
|
||||
|
||||
static var filter: Classic.ColorsDemo.Filter = .all {
|
||||
|
||||
didSet {
|
||||
|
||||
Classic.ColorsDemo.palettesMonitor.refetch(
|
||||
self.filter.whereClause(),
|
||||
OrderBy<Classic.ColorsDemo.Palette>(.ascending(\.hue))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="16119" systemVersion="19F101" minimumToolsVersion="Automatic" sourceLanguage="Swift" userDefinedModelVersionIdentifier="">
|
||||
<entity name="Palette" representedClassName="Classic_ColorsDemo_Palette" syncable="YES">
|
||||
<attribute name="brightness" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="colorGroup" optional="YES" transient="YES" attributeType="String"/>
|
||||
<attribute name="hue" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
<attribute name="saturation" attributeType="Float" defaultValueString="0.0" usesScalarValueType="YES"/>
|
||||
</entity>
|
||||
<elements>
|
||||
<element name="Palette" positionX="-63" positionY="-18" width="128" height="103"/>
|
||||
</elements>
|
||||
</model>
|
||||
+291
@@ -0,0 +1,291 @@
|
||||
//
|
||||
// Demo
|
||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
||||
|
||||
import CoreStore
|
||||
import UIKit
|
||||
|
||||
|
||||
// MARK: - Classic.ColorsDemo
|
||||
|
||||
extension Classic.ColorsDemo {
|
||||
|
||||
// MARK: - Classic.ColorsDemo.DetailViewController
|
||||
|
||||
final class DetailViewController: UIViewController, ObjectObserver {
|
||||
|
||||
/**
|
||||
⭐️ Sample 1: We can normally use `ObjectPublisher` directly, which is simpler. But for this demo, we will be using `ObjectMonitor` instead because we need to keep track of which properties change to prevent our `UISlider` from stuttering. Refer to the `objectMonitor(_:didUpdateObject:changedPersistentKeys:)` implementation below.
|
||||
*/
|
||||
var palette: ObjectMonitor<Classic.ColorsDemo.Palette> {
|
||||
|
||||
didSet {
|
||||
|
||||
oldValue.removeObserver(self)
|
||||
|
||||
self.startMonitoringObject()
|
||||
}
|
||||
}
|
||||
|
||||
init(_ palette: ObjectMonitor<Classic.ColorsDemo.Palette>) {
|
||||
|
||||
self.palette = palette
|
||||
super.init(nibName: nil, bundle: nil)
|
||||
}
|
||||
|
||||
/**
|
||||
⭐️ Sample 2: Once the views are created, we can start receiving `ObjectMonitor` updates in our `ObjectObserver` conformance methods. We typically call this at the end of `viewDidLoad`. Note that after the `addObserver` call, only succeeding updates will trigger our `ObjectObserver` methods, so to immediately display the current values, we need to initialize our views once (in this case, using `reloadPaletteInfo(_:changedKeys:)`.
|
||||
*/
|
||||
private func startMonitoringObject() {
|
||||
|
||||
self.palette.addObserver(self)
|
||||
if let palette = self.palette.object {
|
||||
|
||||
self.reloadPaletteInfo(palette, changedKeys: nil)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
⭐️ Sample 3: We can end monitoring updates anytime. `removeObserver()` was called here for illustration purposes only. `ObjectMonitor`s safely remove deallocated observers automatically.
|
||||
*/
|
||||
deinit {
|
||||
|
||||
self.palette.removeObserver(self)
|
||||
}
|
||||
|
||||
/**
|
||||
⭐️ Sample 4: Our `objectMonitor(_:didUpdateObject:changedPersistentKeys:)` implementation passes a `Set<KeyPathString>` to our reload method. We can then inspect which values were triggered by each `UISlider`, so we can avoid double-updates that can lag the `UISlider` dragging.
|
||||
*/
|
||||
func reloadPaletteInfo(
|
||||
_ palette: Classic.ColorsDemo.Palette,
|
||||
changedKeys: Set<KeyPathString>?
|
||||
) {
|
||||
|
||||
self.view.backgroundColor = palette.color
|
||||
|
||||
self.hueLabel.text = "H: \(Int(palette.hue * 359))°"
|
||||
self.saturationLabel.text = "S: \(Int(palette.saturation * 100))%"
|
||||
self.brightnessLabel.text = "B: \(Int(palette.brightness * 100))%"
|
||||
|
||||
if changedKeys == nil
|
||||
|| changedKeys?.contains(String(keyPath: \Classic.ColorsDemo.Palette.hue)) == true {
|
||||
|
||||
self.hueSlider.value = Float(palette.hue)
|
||||
}
|
||||
if changedKeys == nil
|
||||
|| changedKeys?.contains(String(keyPath: \Classic.ColorsDemo.Palette.saturation)) == true {
|
||||
|
||||
self.saturationSlider.value = palette.saturation
|
||||
}
|
||||
if changedKeys == nil
|
||||
|| changedKeys?.contains(String(keyPath: \Classic.ColorsDemo.Palette.brightness)) == true {
|
||||
|
||||
self.brightnessSlider.value = palette.brightness
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: ObjectObserver
|
||||
|
||||
func objectMonitor(
|
||||
_ monitor: ObjectMonitor<Classic.ColorsDemo.Palette>,
|
||||
didUpdateObject object: Classic.ColorsDemo.Palette,
|
||||
changedPersistentKeys: Set<KeyPathString>
|
||||
) {
|
||||
|
||||
self.reloadPaletteInfo(object, changedKeys: changedPersistentKeys)
|
||||
}
|
||||
|
||||
|
||||
// MARK: UIViewController
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
||||
super.viewDidLoad()
|
||||
|
||||
let view = self.view!
|
||||
let containerView = UIView()
|
||||
do {
|
||||
containerView.translatesAutoresizingMaskIntoConstraints = false
|
||||
containerView.backgroundColor = UIColor.white
|
||||
containerView.layer.cornerRadius = 10
|
||||
containerView.layer.masksToBounds = true
|
||||
containerView.layer.shadowColor = UIColor(white: 0.5, alpha: 0.3).cgColor
|
||||
containerView.layer.shadowOffset = .init(width: 1, height: 1)
|
||||
containerView.layer.shadowRadius = 2
|
||||
|
||||
view.addSubview(containerView)
|
||||
}
|
||||
|
||||
let vStackView = UIStackView()
|
||||
do {
|
||||
vStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
vStackView.axis = .vertical
|
||||
vStackView.spacing = 10
|
||||
vStackView.distribution = .fill
|
||||
vStackView.alignment = .fill
|
||||
|
||||
containerView.addSubview(vStackView)
|
||||
}
|
||||
|
||||
let palette = self.palette.object
|
||||
let rows: [(label: UILabel, slider: UISlider, initialValue: Float, sliderValueChangedSelector: Selector)] = [
|
||||
(
|
||||
self.hueLabel,
|
||||
self.hueSlider,
|
||||
palette?.hue ?? 0,
|
||||
#selector(self.hueSliderValueDidChange(_:))
|
||||
),
|
||||
(
|
||||
self.saturationLabel,
|
||||
self.saturationSlider,
|
||||
palette?.saturation ?? 0,
|
||||
#selector(self.saturationSliderValueDidChange(_:))
|
||||
),
|
||||
(
|
||||
self.brightnessLabel,
|
||||
self.brightnessSlider,
|
||||
palette?.brightness ?? 0,
|
||||
#selector(self.brightnessSliderValueDidChange(_:))
|
||||
)
|
||||
]
|
||||
for (label, slider, initialValue, sliderValueChangedSelector) in rows {
|
||||
|
||||
let hStackView = UIStackView()
|
||||
do {
|
||||
hStackView.translatesAutoresizingMaskIntoConstraints = false
|
||||
hStackView.axis = .horizontal
|
||||
hStackView.spacing = 5
|
||||
hStackView.distribution = .fill
|
||||
hStackView.alignment = .center
|
||||
|
||||
vStackView.addArrangedSubview(hStackView)
|
||||
}
|
||||
do {
|
||||
label.translatesAutoresizingMaskIntoConstraints = false
|
||||
label.textColor = UIColor(white: 0, alpha: 0.8)
|
||||
label.textAlignment = .center
|
||||
|
||||
hStackView.addArrangedSubview(label)
|
||||
}
|
||||
do {
|
||||
slider.translatesAutoresizingMaskIntoConstraints = false
|
||||
slider.minimumValue = 0
|
||||
slider.maximumValue = 1
|
||||
slider.value = initialValue
|
||||
slider.addTarget(
|
||||
self,
|
||||
action: sliderValueChangedSelector,
|
||||
for: .valueChanged
|
||||
)
|
||||
|
||||
hStackView.addArrangedSubview(slider)
|
||||
}
|
||||
}
|
||||
|
||||
layout: do {
|
||||
|
||||
NSLayoutConstraint.activate(
|
||||
[
|
||||
containerView.leadingAnchor.constraint(
|
||||
equalTo: view.safeAreaLayoutGuide.leadingAnchor,
|
||||
constant: 10
|
||||
),
|
||||
containerView.bottomAnchor.constraint(
|
||||
equalTo: view.safeAreaLayoutGuide.bottomAnchor,
|
||||
constant: -10
|
||||
),
|
||||
containerView.trailingAnchor.constraint(
|
||||
equalTo: view.safeAreaLayoutGuide.trailingAnchor,
|
||||
constant: -10
|
||||
),
|
||||
|
||||
vStackView.topAnchor.constraint(
|
||||
equalTo: containerView.topAnchor,
|
||||
constant: 15
|
||||
),
|
||||
vStackView.leadingAnchor.constraint(
|
||||
equalTo: containerView.leadingAnchor,
|
||||
constant: 15
|
||||
),
|
||||
vStackView.bottomAnchor.constraint(
|
||||
equalTo: containerView.bottomAnchor,
|
||||
constant: -15
|
||||
),
|
||||
vStackView.trailingAnchor.constraint(
|
||||
equalTo: containerView.trailingAnchor,
|
||||
constant: -15
|
||||
)
|
||||
]
|
||||
)
|
||||
NSLayoutConstraint.activate(
|
||||
rows.map { label, _, _, _ in
|
||||
label.widthAnchor.constraint(equalToConstant: 80)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
self.startMonitoringObject()
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
|
||||
fatalError()
|
||||
}
|
||||
|
||||
private let hueLabel: UILabel = .init()
|
||||
private let saturationLabel: UILabel = .init()
|
||||
private let brightnessLabel: UILabel = .init()
|
||||
private let hueSlider: UISlider = .init()
|
||||
private let saturationSlider: UISlider = .init()
|
||||
private let brightnessSlider: UISlider = .init()
|
||||
|
||||
@objc
|
||||
private dynamic func hueSliderValueDidChange(_ sender: UISlider) {
|
||||
|
||||
let value = sender.value
|
||||
Classic.ColorsDemo.dataStack.perform(
|
||||
asynchronous: { [weak self] (transaction) in
|
||||
|
||||
let palette = transaction.edit(self?.palette.object)
|
||||
palette?.hue = value
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
|
||||
@objc
|
||||
private dynamic func saturationSliderValueDidChange(_ sender: UISlider) {
|
||||
|
||||
let value = sender.value
|
||||
Classic.ColorsDemo.dataStack.perform(
|
||||
asynchronous: { [weak self] (transaction) in
|
||||
|
||||
let palette = transaction.edit(self?.palette.object)
|
||||
palette?.saturation = value
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
|
||||
@objc
|
||||
private dynamic func brightnessSliderValueDidChange(_ sender: UISlider) {
|
||||
|
||||
let value = sender.value
|
||||
Classic.ColorsDemo.dataStack.perform(
|
||||
asynchronous: { [weak self] (transaction) in
|
||||
|
||||
let palette = transaction.edit(self?.palette.object)
|
||||
palette?.brightness = value
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
//
|
||||
// Demo
|
||||
// Copyright © 2020 John Rommel Estropia, Inc. All rights reserved.
|
||||
|
||||
import CoreStore
|
||||
import UIKit
|
||||
|
||||
|
||||
// MARK: - Classic.ColorsDemo
|
||||
|
||||
extension Classic.ColorsDemo {
|
||||
|
||||
// MARK: - Classic.ColorsDemo.ListViewController
|
||||
|
||||
final class ListViewController: UITableViewController, ListSectionObserver {
|
||||
|
||||
/**
|
||||
⭐️ Sample 1: Once the views are created, we can start observing `ListMonitor` updates. We typically call this at the end of `viewDidLoad`. Note that the `addObserver`'s closure argument will only be called on the succeeding updates, so to immediately display the current values, we need to call `tableView.reloadData()` once.
|
||||
*/
|
||||
private func startObservingList() {
|
||||
|
||||
self.listMonitor.addObserver(self)
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
|
||||
/**
|
||||
⭐️ Sample 2: We can end monitoring updates anytime. `removeObserver()` was called here for illustration purposes only. `ListMonitor`s safely remove deallocated observers automatically.
|
||||
*/
|
||||
deinit {
|
||||
|
||||
self.listMonitor.removeObserver(self)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
⭐️ Sample 3: `ListSectionObserver` (and inherently, `ListObjectObserver` and `ListObserver`) conformance
|
||||
*/
|
||||
|
||||
// MARK: ListObserver
|
||||
|
||||
typealias ListEntityType = Classic.ColorsDemo.Palette
|
||||
|
||||
func listMonitorWillChange(_ monitor: ListMonitor<Classic.ColorsDemo.Palette>) {
|
||||
|
||||
self.tableView.beginUpdates()
|
||||
}
|
||||
|
||||
func listMonitorDidChange(_ monitor: ListMonitor<Classic.ColorsDemo.Palette>) {
|
||||
|
||||
self.tableView.endUpdates()
|
||||
}
|
||||
|
||||
func listMonitorDidRefetch(_ monitor: ListMonitor<Classic.ColorsDemo.Palette>) {
|
||||
|
||||
self.tableView.reloadData()
|
||||
}
|
||||
|
||||
|
||||
// MARK: ListObjectObserver
|
||||
|
||||
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didInsertObject object: ListEntityType, toIndexPath indexPath: IndexPath) {
|
||||
|
||||
self.tableView.insertRows(at: [indexPath], with: .automatic)
|
||||
}
|
||||
|
||||
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didDeleteObject object: ListEntityType, fromIndexPath indexPath: IndexPath) {
|
||||
|
||||
self.tableView.deleteRows(at: [indexPath], with: .automatic)
|
||||
}
|
||||
|
||||
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didUpdateObject object: ListEntityType, atIndexPath indexPath: IndexPath) {
|
||||
|
||||
if case let cell as Classic.ColorsDemo.ItemCell = self.tableView.cellForRow(at: indexPath) {
|
||||
|
||||
cell.setPalette(object)
|
||||
}
|
||||
}
|
||||
|
||||
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didMoveObject object: ListEntityType, fromIndexPath: IndexPath, toIndexPath: IndexPath) {
|
||||
|
||||
self.tableView.deleteRows(at: [fromIndexPath], with: .automatic)
|
||||
self.tableView.insertRows(at: [toIndexPath], with: .automatic)
|
||||
}
|
||||
|
||||
|
||||
// MARK: ListSectionObserver
|
||||
|
||||
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didInsertSection sectionInfo: NSFetchedResultsSectionInfo, toSectionIndex sectionIndex: Int) {
|
||||
|
||||
self.tableView.insertSections(IndexSet(integer: sectionIndex), with: .automatic)
|
||||
}
|
||||
|
||||
func listMonitor(_ monitor: ListMonitor<ListEntityType>, didDeleteSection sectionInfo: NSFetchedResultsSectionInfo, fromSectionIndex sectionIndex: Int) {
|
||||
|
||||
self.tableView.deleteSections(IndexSet(integer: sectionIndex), with: .automatic)
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDataSource
|
||||
|
||||
override func numberOfSections(in tableView: UITableView) -> Int {
|
||||
|
||||
return self.listMonitor.numberOfSections()
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
|
||||
|
||||
return self.listMonitor.numberOfObjects(in: section)
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
|
||||
|
||||
let cell = tableView.dequeueReusableCell(
|
||||
withIdentifier: Classic.ColorsDemo.ItemCell.reuseIdentifier,
|
||||
for: indexPath
|
||||
) as! Classic.ColorsDemo.ItemCell
|
||||
cell.setPalette(self.listMonitor[indexPath])
|
||||
return cell
|
||||
}
|
||||
|
||||
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
|
||||
|
||||
return self.listMonitor.sectionInfo(at: section).name
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDelegate
|
||||
|
||||
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
|
||||
|
||||
switch editingStyle {
|
||||
|
||||
case .delete:
|
||||
let object = self.listMonitor[indexPath]
|
||||
Classic.ColorsDemo.dataStack.perform(
|
||||
asynchronous: { (transaction) in
|
||||
|
||||
transaction.delete(object)
|
||||
},
|
||||
completion: { _ in }
|
||||
)
|
||||
|
||||
default:
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
init(
|
||||
listMonitor: ListMonitor<Classic.ColorsDemo.Palette>,
|
||||
onPaletteTapped: @escaping (Classic.ColorsDemo.Palette) -> Void
|
||||
) {
|
||||
|
||||
self.listMonitor = listMonitor
|
||||
self.onPaletteTapped = onPaletteTapped
|
||||
|
||||
super.init(style: .plain)
|
||||
}
|
||||
|
||||
|
||||
// MARK: UIViewController
|
||||
|
||||
override func viewDidLoad() {
|
||||
|
||||
super.viewDidLoad()
|
||||
|
||||
self.tableView.register(
|
||||
Classic.ColorsDemo.ItemCell.self,
|
||||
forCellReuseIdentifier: Classic.ColorsDemo.ItemCell.reuseIdentifier
|
||||
)
|
||||
|
||||
self.startObservingList()
|
||||
}
|
||||
|
||||
|
||||
// MARK: UITableViewDelegate
|
||||
|
||||
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
|
||||
|
||||
self.onPaletteTapped(
|
||||
self.listMonitor[indexPath]
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private let listMonitor: ListMonitor<Classic.ColorsDemo.Palette>
|
||||
private let onPaletteTapped: (Classic.ColorsDemo.Palette) -> Void
|
||||
|
||||
@available(*, unavailable)
|
||||
required init?(coder: NSCoder) {
|
||||
|
||||
fatalError()
|
||||
}
|
||||
}
|
||||
}
|
||||
File renamed without changes.
+2
-2
@@ -28,8 +28,8 @@ extension Modern.ColorsDemo {
|
||||
switch self {
|
||||
|
||||
case .all: return .init()
|
||||
case .light: return (\Modern.ColorsDemo.Palette.$brightness >= 0.9)
|
||||
case .dark: return (\Modern.ColorsDemo.Palette.$brightness <= 0.4)
|
||||
case .light: return (\.$brightness >= 0.9)
|
||||
case .dark: return (\.$brightness <= 0.4)
|
||||
}
|
||||
}
|
||||
}
|
||||
+17
-17
@@ -49,31 +49,31 @@ extension Modern.ColorsDemo {
|
||||
var brightness: Float
|
||||
|
||||
@Field.Virtual(
|
||||
"colorName",
|
||||
"colorGroup",
|
||||
customGetter: { object, field in
|
||||
|
||||
if let colorName = field.primitiveValue {
|
||||
if let colorGroup = field.primitiveValue {
|
||||
|
||||
return colorName
|
||||
return colorGroup
|
||||
}
|
||||
let colorName: String
|
||||
let colorGroup: String
|
||||
switch object.$hue.value * 359 {
|
||||
|
||||
case 0 ..< 20: colorName = "Lower Reds"
|
||||
case 20 ..< 57: colorName = "Oranges and Browns"
|
||||
case 57 ..< 90: colorName = "Yellow-Greens"
|
||||
case 90 ..< 159: colorName = "Greens"
|
||||
case 159 ..< 197: colorName = "Blue-Greens"
|
||||
case 197 ..< 241: colorName = "Blues"
|
||||
case 241 ..< 297: colorName = "Violets"
|
||||
case 297 ..< 331: colorName = "Magentas"
|
||||
default: colorName = "Upper Reds"
|
||||
case 0 ..< 20: colorGroup = "Lower Reds"
|
||||
case 20 ..< 57: colorGroup = "Oranges and Browns"
|
||||
case 57 ..< 90: colorGroup = "Yellow-Greens"
|
||||
case 90 ..< 159: colorGroup = "Greens"
|
||||
case 159 ..< 197: colorGroup = "Blue-Greens"
|
||||
case 197 ..< 241: colorGroup = "Blues"
|
||||
case 241 ..< 297: colorGroup = "Violets"
|
||||
case 297 ..< 331: colorGroup = "Magentas"
|
||||
default: colorGroup = "Upper Reds"
|
||||
}
|
||||
field.primitiveValue = colorName
|
||||
return colorName
|
||||
field.primitiveValue = colorGroup
|
||||
return colorGroup
|
||||
}
|
||||
)
|
||||
var colorName: String
|
||||
var colorGroup: String
|
||||
|
||||
@Field.Virtual(
|
||||
"color",
|
||||
@@ -120,7 +120,7 @@ extension Modern.ColorsDemo {
|
||||
|
||||
private static func resetVirtualProperties(_ object: ObjectProxy<Modern.ColorsDemo.Palette>) {
|
||||
|
||||
object.$colorName.primitiveValue = nil
|
||||
object.$colorGroup.primitiveValue = nil
|
||||
object.$color.primitiveValue = nil
|
||||
object.$colorText.primitiveValue = nil
|
||||
}
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+2
-2
@@ -45,7 +45,7 @@ extension Modern {
|
||||
|
||||
static let palettesPublisher: ListPublisher<Modern.ColorsDemo.Palette> = Modern.ColorsDemo.dataStack.publishList(
|
||||
From<Modern.ColorsDemo.Palette>()
|
||||
.sectionBy(\.$colorName)
|
||||
.sectionBy(\.$colorGroup)
|
||||
.where(Modern.ColorsDemo.filter.whereClause())
|
||||
.orderBy(.ascending(\.$hue))
|
||||
)
|
||||
@@ -56,7 +56,7 @@ extension Modern {
|
||||
|
||||
try! Modern.ColorsDemo.palettesPublisher.refetch(
|
||||
From<Modern.ColorsDemo.Palette>()
|
||||
.sectionBy(\.$colorName)
|
||||
.sectionBy(\.$colorGroup)
|
||||
.where(self.filter.whereClause())
|
||||
.orderBy(.ascending(\.$hue))
|
||||
)
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+3
@@ -17,6 +17,9 @@ extension Modern {
|
||||
|
||||
// MARK: Internal
|
||||
|
||||
/**
|
||||
⭐️ Sample 1: Setting up the `DataStack` and storage
|
||||
*/
|
||||
static let dataStack: DataStack = {
|
||||
|
||||
let dataStack = DataStack(
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
+1
-1
@@ -9,7 +9,7 @@ import UIKit
|
||||
|
||||
extension Modern.PokedexDemo {
|
||||
|
||||
// MARK: - Modern.PokedexDemo.Move
|
||||
// MARK: - Modern.PokedexDemo.PokemonType
|
||||
|
||||
/**
|
||||
⭐️ Sample 1: Types that will be used with `@Field.Stored` need to implement both `ImportableAttributeType` and `FieldStorableType`. In this case, `RawRepresentable` types with primitive `RawValue`s have built-in implementations so we only have to declare conformance to `ImportableAttributeType` and `FieldStorableType`.
|
||||
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -1914,14 +1914,14 @@ class Vehicle: CoreStoreObject {
|
||||
Built-in encoders such as `FieldCoders.NSCoding`, `FieldCoders.Json`, and `FieldCoders.Plist` are available, and custom encoding/decoding is also supported:
|
||||
```swift
|
||||
class Person: CoreStoreObject {
|
||||
<br />
|
||||
|
||||
struct CustomInfo: Codable {
|
||||
// ...
|
||||
}
|
||||
<br />
|
||||
|
||||
@Field.Coded("otherInfo", coder: FieldCoders.Json.self)
|
||||
var otherInfo: CustomInfo?
|
||||
<br />
|
||||
|
||||
@Field.Coded(
|
||||
"photo",
|
||||
coder: {
|
||||
|
||||
+134
-6
@@ -65,7 +65,8 @@ extension FieldContainer {
|
||||
var eyeColor: UIColor = .black
|
||||
}
|
||||
```
|
||||
- parameter initial: the initial value for the property when the object is first created.
|
||||
- Important: Any changes in the `coder` are not reflected in the VersionLock, so make sure that the encoder and decoder logic is compatible for all versions of your persistent store.
|
||||
- parameter initial: the initial value for the property that is shared for all instances of this object. Note that this is evaluated during `DataStack` setup, not during object creation. To assign a value during object creation, use the `dynamicInitialValue` argument instead.
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
@@ -99,6 +100,25 @@ extension FieldContainer {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes the metadata for the property.
|
||||
```
|
||||
class Person: CoreStoreObject {
|
||||
|
||||
@Field.Coded("eyeColor", coder: FieldCoders.NSCoding.self, dynamicInitialValue: { UIColor.random() })
|
||||
var eyeColor: UIColor
|
||||
}
|
||||
```
|
||||
- Important: Any changes in the `coder` are not reflected in the VersionLock, so make sure that the encoder and decoder logic is compatible for all versions of your persistent store.
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
- parameter coder: The `FieldCoderType` to be used for encoding and decoding the value
|
||||
- parameter customGetter: use this closure as an "override" for the default property getter. The closure receives a `ObjectProxy<O>`, which acts as a type-safe proxy for the receiver. When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively. Do not make assumptions on the thread/queue that the closure is executed on; accessors may be called from `NSError` logs for example.
|
||||
- parameter customSetter: use this closure as an "override" for the default property setter. The closure receives a `ObjectProxy<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively.
|
||||
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
|
||||
- parameter dynamicInitialValue: the initial value for the property when the object is first created.
|
||||
*/
|
||||
public init<Coder: FieldCoderType>(
|
||||
_ keyPath: KeyPathString,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
@@ -139,7 +159,8 @@ extension FieldContainer {
|
||||
var bloodType: BloodType = .unknown
|
||||
}
|
||||
```
|
||||
- parameter initial: the initial value for the property when the object is first created.
|
||||
- Important: Any changes in the encoder/decoder are not reflected in the VersionLock, so make sure that the encoder and decoder logic is compatible for all versions of your persistent store.
|
||||
- parameter initial: the initial value for the property that is shared for all instances of this object. Note that this is evaluated during `DataStack` setup, not during object creation. To assign a value during object creation, use the `dynamicInitialValue` argument instead.
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
@@ -173,6 +194,32 @@ extension FieldContainer {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes the metadata for the property.
|
||||
```
|
||||
class Person: CoreStoreObject {
|
||||
|
||||
@Field.Coded(
|
||||
"bloodType",
|
||||
coder: {
|
||||
encode: { $0.toData() },
|
||||
decode: { BloodType(fromData: $0) }
|
||||
},
|
||||
dynamicInitialValue: { BloodType.random() }
|
||||
)
|
||||
var bloodType: BloodType
|
||||
}
|
||||
```
|
||||
- Important: Any changes in the encoder/decoder are not reflected in the VersionLock, so make sure that the encoder and decoder logic is compatible for all versions of your persistent store.
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
- parameter coder: The closures to be used for encoding and decoding the value
|
||||
- parameter customGetter: use this closure as an "override" for the default property getter. The closure receives a `ObjectProxy<O>`, which acts as a type-safe proxy for the receiver. When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively. Do not make assumptions on the thread/queue that the closure is executed on; accessors may be called from `NSError` logs for example.
|
||||
- parameter customSetter: use this closure as an "override" for the default property setter. The closure receives a `ObjectProxy<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively.
|
||||
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
|
||||
- parameter dynamicInitialValue: the initial value for the property when the object is first created.
|
||||
*/
|
||||
public init(
|
||||
_ keyPath: KeyPathString,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
@@ -467,7 +514,8 @@ extension FieldContainer.Coded where V: FieldOptionalType {
|
||||
var eyeColor: UIColor? = nil
|
||||
}
|
||||
```
|
||||
- parameter initial: the initial value for the property when the object is first created.
|
||||
- Important: Any changes in the `coder` are not reflected in the VersionLock, so make sure that the encoder and decoder logic is compatible for all versions of your persistent store.
|
||||
- parameter initial: the initial value for the property that is shared for all instances of this object. Note that this is evaluated during `DataStack` setup, not during object creation. To assign a value during object creation, use the `dynamicInitialValue` argument instead.
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
@@ -501,6 +549,25 @@ extension FieldContainer.Coded where V: FieldOptionalType {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes the metadata for the property.
|
||||
```
|
||||
class Person: CoreStoreObject {
|
||||
|
||||
@Field.Coded("eyeColor", coder: FieldCoders.NSCoding.self, dynamicInitialValue: { UIColor.random() })
|
||||
var eyeColor: UIColor?
|
||||
}
|
||||
```
|
||||
- Important: Any changes in the `coder` are not reflected in the VersionLock, so make sure that the encoder and decoder logic is compatible for all versions of your persistent store.
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
- parameter coder: The `FieldCoderType` to be used for encoding and decoding the value
|
||||
- parameter customGetter: use this closure as an "override" for the default property getter. The closure receives a `ObjectProxy<O>`, which acts as a type-safe proxy for the receiver. When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively. Do not make assumptions on the thread/queue that the closure is executed on; accessors may be called from `NSError` logs for example.
|
||||
- parameter customSetter: use this closure as an "override" for the default property setter. The closure receives a `ObjectProxy<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively.
|
||||
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
|
||||
- parameter dynamicInitialValue: the initial value for the property when the object is first created.
|
||||
*/
|
||||
public init<Coder: FieldCoderType>(
|
||||
_ keyPath: KeyPathString,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
@@ -541,7 +608,8 @@ extension FieldContainer.Coded where V: FieldOptionalType {
|
||||
var bloodType: BloodType?
|
||||
}
|
||||
```
|
||||
- parameter initial: the initial value for the property when the object is first created.
|
||||
- Important: Any changes in the encoder/decoder are not reflected in the VersionLock, so make sure that the encoder and decoder logic is compatible for all versions of your persistent store.
|
||||
- parameter initial: the initial value for the property that is shared for all instances of this object. Note that this is evaluated during `DataStack` setup, not during object creation. To assign a value during object creation, use the `dynamicInitialValue` argument instead.
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
@@ -575,6 +643,32 @@ extension FieldContainer.Coded where V: FieldOptionalType {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes the metadata for the property.
|
||||
```
|
||||
class Person: CoreStoreObject {
|
||||
|
||||
@Field.Coded(
|
||||
"bloodType",
|
||||
coder: {
|
||||
encode: { $0.toData() },
|
||||
decode: { BloodType(fromData: $0) }
|
||||
},
|
||||
dynamicInitialValue: { BloodType.random() }
|
||||
)
|
||||
var bloodType: BloodType?
|
||||
}
|
||||
```
|
||||
- Important: Any changes in the encoder/decoder are not reflected in the VersionLock, so make sure that the encoder and decoder logic is compatible for all versions of your persistent store.
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
- parameter coder: The closures to be used for encoding and decoding the value
|
||||
- parameter customGetter: use this closure as an "override" for the default property getter. The closure receives a `ObjectProxy<O>`, which acts as a type-safe proxy for the receiver. When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively. Do not make assumptions on the thread/queue that the closure is executed on; accessors may be called from `NSError` logs for example.
|
||||
- parameter customSetter: use this closure as an "override" for the default property setter. The closure receives a `ObjectProxy<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively.
|
||||
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
|
||||
- parameter dynamicInitialValue: the initial value for the property when the object is first created.
|
||||
*/
|
||||
public init(
|
||||
_ keyPath: KeyPathString,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
@@ -615,7 +709,7 @@ extension FieldContainer.Coded where V: DefaultNSSecureCodable {
|
||||
var customInfo: NSDictionary = [:]
|
||||
}
|
||||
```
|
||||
- parameter initial: the initial value for the property when the object is first created.
|
||||
- parameter initial: the initial value for the property that is shared for all instances of this object. Note that this is evaluated during `DataStack` setup, not during object creation. To assign a value during object creation, use the `dynamicInitialValue` argument instead.
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
@@ -647,6 +741,23 @@ extension FieldContainer.Coded where V: DefaultNSSecureCodable {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes the metadata for the property. This overload is for types supported by Core Data's default NSSecureCodable implementation: `NSArray`, `NSDictionary`, `NSSet`, `NSString`, `NSNumber`, `NSDate`, `NSData`, `NSURL`, `NSUUID`, and `NSNull`.
|
||||
```
|
||||
class Person: CoreStoreObject {
|
||||
|
||||
@Field.Coded("customInfo", dynamicInitialValue: { ["id": UUID()] })
|
||||
var customInfo: NSDictionary
|
||||
}
|
||||
```
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
- parameter customGetter: use this closure as an "override" for the default property getter. The closure receives a `ObjectProxy<O>`, which acts as a type-safe proxy for the receiver. When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively. Do not make assumptions on the thread/queue that the closure is executed on; accessors may be called from `NSError` logs for example.
|
||||
- parameter customSetter: use this closure as an "override" for the default property setter. The closure receives a `ObjectProxy<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively.
|
||||
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
|
||||
- parameter dynamicInitialValue: the initial value for the property when the object is first created.
|
||||
*/
|
||||
public init(
|
||||
_ keyPath: KeyPathString,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
@@ -686,7 +797,7 @@ extension FieldContainer.Coded where V: FieldOptionalType, V.Wrapped: DefaultNSS
|
||||
var customInfo: NSDictionary? = nil
|
||||
}
|
||||
```
|
||||
- parameter initial: the initial value for the property when the object is first created.
|
||||
- parameter initial: the initial value for the property that is shared for all instances of this object. Note that this is evaluated during `DataStack` setup, not during object creation. To assign a value during object creation, use the `dynamicInitialValue` argument instead.
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
@@ -718,6 +829,23 @@ extension FieldContainer.Coded where V: FieldOptionalType, V.Wrapped: DefaultNSS
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes the metadata for the property. This overload is for types supported by Core Data's default NSSecureCodable implementation: `NSArray`, `NSDictionary`, `NSSet`, `NSString`, `NSNumber`, `NSDate`, `NSData`, `NSURL`, `NSUUID`, and `NSNull`.
|
||||
```
|
||||
class Person: CoreStoreObject {
|
||||
|
||||
@Field.Coded("customInfo", dynamicInitialValue: { ["id": UUID()] })
|
||||
var customInfo: NSDictionary?
|
||||
}
|
||||
```
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
- parameter customGetter: use this closure as an "override" for the default property getter. The closure receives a `ObjectProxy<O>`, which acts as a type-safe proxy for the receiver. When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively. Do not make assumptions on the thread/queue that the closure is executed on; accessors may be called from `NSError` logs for example.
|
||||
- parameter customSetter: use this closure as an "override" for the default property setter. The closure receives a `ObjectProxy<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively.
|
||||
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
|
||||
- parameter dynamicInitialValue: the initial value for the property when the object is first created.
|
||||
*/
|
||||
public init(
|
||||
_ keyPath: KeyPathString,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
|
||||
@@ -59,7 +59,7 @@ extension FieldContainer {
|
||||
var title: String = "Mr."
|
||||
}
|
||||
```
|
||||
- parameter initial: the initial value for the property when the object is first created.
|
||||
- parameter initial: the initial value for the property that is shared for all instances of this object. Note that this is evaluated during `DataStack` setup, not during object creation. To assign a value during object creation, use the `dynamicInitialValue` argument instead.
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
@@ -90,6 +90,23 @@ extension FieldContainer {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes the metadata for the property.
|
||||
```
|
||||
class Person: CoreStoreObject {
|
||||
|
||||
@Field.Stored("title", dynamicInitialValue: { Person.randomTitle() })
|
||||
var title: String
|
||||
}
|
||||
```
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
- parameter customGetter: use this closure as an "override" for the default property getter. The closure receives a `ObjectProxy<O>`, which acts as a type-safe proxy for the receiver. When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively. Do not make assumptions on the thread/queue that the closure is executed on; accessors may be called from `NSError` logs for example.
|
||||
- parameter customSetter: use this closure as an "override" for the default property setter. The closure receives a `ObjectProxy<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively.
|
||||
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
|
||||
- parameter dynamicInitialValue: the initial value for the property when the object is first created.
|
||||
*/
|
||||
public init(
|
||||
_ keyPath: KeyPathString,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
@@ -360,7 +377,7 @@ extension FieldContainer.Stored where V: FieldOptionalType {
|
||||
var nickname: String?
|
||||
}
|
||||
```
|
||||
- parameter initial: the initial value for the property when the object is first created.
|
||||
- parameter initial: the initial value for the property that is shared for all instances of this object. Note that this is evaluated during `DataStack` setup, not during object creation. To assign a value during object creation, use the `dynamicInitialValue` argument instead.
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
@@ -391,6 +408,23 @@ extension FieldContainer.Stored where V: FieldOptionalType {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
Initializes the metadata for the property.
|
||||
```
|
||||
class Person: CoreStoreObject {
|
||||
|
||||
@Field.Stored("nickname", dynamicInitialValue: { Person.randomNickname() })
|
||||
var nickname: String?
|
||||
}
|
||||
```
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter previousVersionKeyPath: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property's `keyPath` with a matching destination entity property's `previousVersionKeyPath` indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's `keyPath`.
|
||||
- parameter customGetter: use this closure as an "override" for the default property getter. The closure receives a `ObjectProxy<O>`, which acts as a type-safe proxy for the receiver. When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively. Do not make assumptions on the thread/queue that the closure is executed on; accessors may be called from `NSError` logs for example.
|
||||
- parameter customSetter: use this closure as an "override" for the default property setter. The closure receives a `ObjectProxy<O>`, which acts as a fast, type-safe KVC interface for `CoreStoreObject`. The reason a `CoreStoreObject` instance is not passed directly is because the Core Data runtime is not aware of `CoreStoreObject` properties' static typing, and so loading those info everytime KVO invokes this accessor method incurs a cumulative performance hit (especially in KVO-heavy operations such as `ListMonitor` observing.) When accessing the property value from `ObjectProxy<O>`, make sure to use `field.primitiveValue` instead of `field.value`, which would unintentionally execute the same closure again recursively.
|
||||
- parameter affectedByKeyPaths: a set of key paths for properties whose values affect the value of the receiver. This is similar to `NSManagedObject.keyPathsForValuesAffectingValue(forKey:)`.
|
||||
- parameter dynamicInitialValue: the initial value for the property when the object is first created.
|
||||
*/
|
||||
public init(
|
||||
_ keyPath: KeyPathString,
|
||||
versionHashModifier: @autoclosure @escaping () -> String? = nil,
|
||||
|
||||
@@ -74,7 +74,7 @@ extension TransformableContainer {
|
||||
}
|
||||
```
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter initial: the initial value for the property when the object is first created. Defaults to the `ImportableAttributeType`'s empty value if not specified.
|
||||
- parameter initial: the initial value for the property that is shared for all instances of this object. Note that this is evaluated during `DataStack` setup, not during object creation. Defaults to the `ImportableAttributeType`'s empty value if not specified.
|
||||
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
||||
- parameter allowsExternalBinaryDataStorage: `true` if the attribute allows external binary storage, otherwise `false`.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
|
||||
@@ -77,7 +77,7 @@ extension TransformableContainer {
|
||||
}
|
||||
```
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter initial: the initial value for the property when the object is first created. Defaults to the `ImportableAttributeType`'s empty value if not specified.
|
||||
- parameter initial: the initial value for the property that is shared for all instances of this object. Note that this is evaluated during `DataStack` setup, not during object creation. Defaults to the `ImportableAttributeType`'s empty value if not specified.
|
||||
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
||||
- parameter allowsExternalBinaryDataStorage: `true` if the attribute allows external binary storage, otherwise `false`.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
|
||||
@@ -71,7 +71,7 @@ extension ValueContainer {
|
||||
}
|
||||
```
|
||||
- parameter keyPath: the permanent attribute name for this property.
|
||||
- parameter initial: the initial value for the property when the object is first created. Defaults to `nil` if not specified.
|
||||
- parameter initial: the initial value for the property that is shared for all instances of this object. Note that this is evaluated during `DataStack` setup, not during object creation. Defaults to `nil` if not specified.
|
||||
- parameter isTransient: `true` if the property is transient, otherwise `false`. Defaults to `false` if not specified. The transient flag specifies whether or not a property's value is ignored when an object is saved to a persistent store. Transient properties are not saved to the persistent store, but are still managed for undo, redo, validation, and so on.
|
||||
- parameter versionHashModifier: used to mark or denote a property as being a different "version" than another even if all of the values which affect persistence are equal. (Such a difference is important in cases where the properties are unchanged but the format or content of its data are changed.)
|
||||
- parameter renamingIdentifier: used to resolve naming conflicts between models. When creating an entity mapping between entities in two managed object models, a source entity property and a destination entity property that share the same identifier indicate that a property mapping should be configured to migrate from the source to the destination. If unset, the identifier will be the property's name.
|
||||
|
||||
Reference in new issue
Block a user