├── .DS_Store ├── Алгоритмы ├── .DS_Store ├── Arcade │ ├── .DS_Store │ ├── README.md │ └── Arcade.swift ├── Структура данных │ ├── .DS_Store │ └── Hash-Table │ │ └── README.md ├── Базовые задачи и решения │ ├── .DS_Store │ └── MyPlaygroundFib.playground │ │ ├── contents.xcplayground │ │ └── Contents.swift └── Алгоритмы сортировки │ └── README.md ├── База iOS ├── .DS_Store ├── Array │ ├── .DS_Store │ ├── Array.png │ ├── Slice.png │ ├── ArrayCast.png │ ├── ContiguousArray.png │ ├── ArrayImplementation.png │ └── Functional programming (FP) │ │ └── README.md ├── Color │ ├── .DS_Store │ ├── images │ │ ├── system-colors.png │ │ ├── system-grays.png │ │ ├── dynamic-colors.png │ │ ├── dynamic-system-color-both.png │ │ ├── dynamic-stystem-background-example.png │ │ └── dynamic-system-grouped-background-example.png │ └── README.md ├── CoreGraphics │ ├── text.png │ └── images │ │ ├── circle.png │ │ ├── on-off.png │ │ ├── square.png │ │ ├── gradient.png │ │ ├── draw-lines.png │ │ ├── rotated-square.png │ │ └── square-no-border.png ├── Margins │ └── images │ │ ├── both.png │ │ ├── safe.png │ │ ├── margins.png │ │ ├── no-margins.png │ │ ├── custom-margin.png │ │ └── directional-margin.png ├── Animation │ ├── images │ │ ├── height.gif │ │ ├── old-new.gif │ │ ├── stackView.gif │ │ └── games-demo.gif │ └── README.md ├── DynamicFont │ └── images │ │ ├── demo.gif │ │ ├── demo.png │ │ ├── after.png │ │ ├── before.png │ │ ├── sizes.png │ │ └── preferred-font-sizes.png ├── ContextMenu │ └── images │ │ ├── preview.gif │ │ ├── simple.gif │ │ └── table.gif ├── FramesVsBounds │ ├── images │ │ ├── frame1.png │ │ └── frame2.png │ └── README.md ├── Networking │ └── README.md ├── hide:show Keyboard │ └── README.md ├── FactoryMethodsUIElements.md └── CoreData │ └── README.md ├── PopularApps ├── .DS_Store ├── Starbucks │ ├── .DS_Store │ ├── Starbucks │ │ ├── Assets.xcassets │ │ │ ├── Contents.json │ │ │ ├── home │ │ │ │ ├── Contents.json │ │ │ │ ├── bonus.imageset │ │ │ │ │ ├── bonus.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── meatless.imageset │ │ │ │ │ ├── meatless.png │ │ │ │ │ └── Contents.json │ │ │ │ ├── communities.imageset │ │ │ │ │ ├── communities.png │ │ │ │ │ └── Contents.json │ │ │ │ └── green-indicator.imageset │ │ │ │ │ ├── green-indicator.png │ │ │ │ │ └── Contents.json │ │ │ ├── AccentColor.colorset │ │ │ │ └── Contents.json │ │ │ └── AppIcon.appiconset │ │ │ │ └── Contents.json │ │ ├── Info.plist │ │ ├── Home │ │ │ ├── Rewards │ │ │ │ ├── RewardsTileViewController.swift │ │ │ │ ├── BalanceView.swift │ │ │ │ └── RewardsGraphView.swift │ │ │ ├── PlaceholderViewController.swift │ │ │ ├── TileViewController.swift │ │ │ ├── StarRewards │ │ │ │ ├── StarAndPoints.swift │ │ │ │ ├── StarRewardsRow.swift │ │ │ │ └── StarRewardsVIew.swift │ │ │ ├── HomeHeaderView.swift │ │ │ └── TileView.swift │ │ ├── Base.lproj │ │ │ └── LaunchScreen.storyboard │ │ ├── Factories.swift │ │ └── AppDelegate.swift │ └── Starbucks.xcodeproj │ │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ ├── xcuserdata │ │ │ └── vladimir.xcuserdatad │ │ │ │ ├── UserInterfaceState.xcuserstate │ │ │ │ └── IDEFindNavigatorScopes.plist │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ │ ├── xcuserdata │ │ └── vladimir.xcuserdatad │ │ │ ├── xcdebugger │ │ │ └── Breakpoints_v2.xcbkptlist │ │ │ └── xcschemes │ │ │ └── xcschememanagement.plist │ │ └── xcshareddata │ │ └── xcschemes │ │ └── Starbucks.xcscheme └── swift-arcade-Starbucks-assets-home │ ├── bonus.png │ ├── meatless.png │ ├── communities.png │ └── green-indicator.png ├── GenericTableVIew1 ├── .DS_Store ├── AwesonTable │ ├── Assets.xcassets │ │ ├── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── ViewController.swift │ ├── AppDelegate.swift │ ├── Base.lproj │ │ ├── Main.storyboard │ │ └── LaunchScreen.storyboard │ ├── GenericTableView.swift │ ├── Info.plist │ └── SceneDelegate.swift ├── README.md └── GenericTableView.xcodeproj │ ├── project.xcworkspace │ ├── xcuserdata │ │ └── vladimir.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ ├── hanyhabil.xcuserdatad │ └── xcschemes │ │ └── xcschememanagement.plist │ └── vladimir.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── FaceBookPage ├── FaceBookPage │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── AppDelegate.swift │ └── Base.lproj │ │ └── LaunchScreen.storyboard └── FaceBookPage.xcodeproj │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ └── vladimir.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ └── vladimir.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── Шаблоны программирования Swift ├── .DS_Store ├── Bridge │ ├── Bridge.png │ └── README.md ├── Facade │ ├── facade.png │ └── README.md ├── Observer │ ├── .DS_Store │ ├── example-observer.gif │ └── README.md ├── Adapter │ └── adapter.jpeg ├── Builder │ ├── builder.jpeg │ └── README.md ├── Decorator │ ├── .DS_Store │ ├── decorator_design.gif │ └── README.md ├── Visitor │ ├── Visitor.png │ └── README.md ├── Composite │ ├── composite.png │ └── README.md ├── Iterator │ ├── iterator.png │ └── README.md ├── Mediator │ ├── Mediator.png │ └── README.md ├── Prototype │ ├── prototype.png │ └── README.md ├── Singleton │ ├── singleton.jpeg │ └── README.md ├── Template method │ ├── template-method.png │ └── README.md ├── Strategy │ ├── strategy-design-temlate_proSwift_ru.png │ └── README.md ├── Chain of responsibility │ ├── Chain_of_responsibility_proSwift_ru.gif │ └── README.md ├── README.md ├── Factory method │ └── README.md └── Abstract Factory │ └── README.md ├── Starbucs-historyView └── HistoryVIew │ ├── HistoryVIew │ ├── Assets.xcassets │ │ ├── Contents.json │ │ ├── AccentColor.colorset │ │ │ └── Contents.json │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── AppDelegate.swift │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ └── HistoryViewController.swift │ └── HistoryVIew.xcodeproj │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ └── vladimir.xcuserdatad │ │ │ └── UserInterfaceState.xcuserstate │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist │ └── xcuserdata │ └── vladimir.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── NoStoryboards └── README.md ├── .gitignore └── BestGitIgnore └── Swift.gitignore /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/.DS_Store -------------------------------------------------------------------------------- /Алгоритмы/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Алгоритмы/.DS_Store -------------------------------------------------------------------------------- /База iOS/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/.DS_Store -------------------------------------------------------------------------------- /PopularApps/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/PopularApps/.DS_Store -------------------------------------------------------------------------------- /База iOS/Array/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Array/.DS_Store -------------------------------------------------------------------------------- /База iOS/Array/Array.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Array/Array.png -------------------------------------------------------------------------------- /База iOS/Array/Slice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Array/Slice.png -------------------------------------------------------------------------------- /База iOS/Color/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Color/.DS_Store -------------------------------------------------------------------------------- /Алгоритмы/Arcade/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Алгоритмы/Arcade/.DS_Store -------------------------------------------------------------------------------- /GenericTableVIew1/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/GenericTableVIew1/.DS_Store -------------------------------------------------------------------------------- /База iOS/Array/ArrayCast.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Array/ArrayCast.png -------------------------------------------------------------------------------- /PopularApps/Starbucks/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/PopularApps/Starbucks/.DS_Store -------------------------------------------------------------------------------- /База iOS/CoreGraphics/text.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/CoreGraphics/text.png -------------------------------------------------------------------------------- /База iOS/Array/ContiguousArray.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Array/ContiguousArray.png -------------------------------------------------------------------------------- /База iOS/Margins/images/both.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Margins/images/both.png -------------------------------------------------------------------------------- /База iOS/Margins/images/safe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Margins/images/safe.png -------------------------------------------------------------------------------- /Алгоритмы/Структура данных/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Алгоритмы/Структура данных/.DS_Store -------------------------------------------------------------------------------- /База iOS/Animation/images/height.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Animation/images/height.gif -------------------------------------------------------------------------------- /База iOS/DynamicFont/images/demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/DynamicFont/images/demo.gif -------------------------------------------------------------------------------- /База iOS/DynamicFont/images/demo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/DynamicFont/images/demo.png -------------------------------------------------------------------------------- /База iOS/Margins/images/margins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Margins/images/margins.png -------------------------------------------------------------------------------- /База iOS/Animation/images/old-new.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Animation/images/old-new.gif -------------------------------------------------------------------------------- /База iOS/Animation/images/stackView.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Animation/images/stackView.gif -------------------------------------------------------------------------------- /База iOS/Array/ArrayImplementation.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Array/ArrayImplementation.png -------------------------------------------------------------------------------- /База iOS/Color/images/system-colors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Color/images/system-colors.png -------------------------------------------------------------------------------- /База iOS/Color/images/system-grays.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Color/images/system-grays.png -------------------------------------------------------------------------------- /База iOS/ContextMenu/images/preview.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/ContextMenu/images/preview.gif -------------------------------------------------------------------------------- /База iOS/ContextMenu/images/simple.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/ContextMenu/images/simple.gif -------------------------------------------------------------------------------- /База iOS/ContextMenu/images/table.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/ContextMenu/images/table.gif -------------------------------------------------------------------------------- /База iOS/CoreGraphics/images/circle.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/CoreGraphics/images/circle.png -------------------------------------------------------------------------------- /База iOS/CoreGraphics/images/on-off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/CoreGraphics/images/on-off.png -------------------------------------------------------------------------------- /База iOS/CoreGraphics/images/square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/CoreGraphics/images/square.png -------------------------------------------------------------------------------- /База iOS/DynamicFont/images/after.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/DynamicFont/images/after.png -------------------------------------------------------------------------------- /База iOS/DynamicFont/images/before.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/DynamicFont/images/before.png -------------------------------------------------------------------------------- /База iOS/DynamicFont/images/sizes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/DynamicFont/images/sizes.png -------------------------------------------------------------------------------- /База iOS/Margins/images/no-margins.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Margins/images/no-margins.png -------------------------------------------------------------------------------- /FaceBookPage/FaceBookPage/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /GenericTableVIew1/AwesonTable/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /База iOS/Animation/images/games-demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Animation/images/games-demo.gif -------------------------------------------------------------------------------- /База iOS/Color/images/dynamic-colors.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Color/images/dynamic-colors.png -------------------------------------------------------------------------------- /База iOS/CoreGraphics/images/gradient.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/CoreGraphics/images/gradient.png -------------------------------------------------------------------------------- /База iOS/FramesVsBounds/images/frame1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/FramesVsBounds/images/frame1.png -------------------------------------------------------------------------------- /База iOS/FramesVsBounds/images/frame2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/FramesVsBounds/images/frame2.png -------------------------------------------------------------------------------- /База iOS/Margins/images/custom-margin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Margins/images/custom-margin.png -------------------------------------------------------------------------------- /Шаблоны программирования Swift/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/.DS_Store -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /Алгоритмы/Базовые задачи и решения/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Алгоритмы/Базовые задачи и решения/.DS_Store -------------------------------------------------------------------------------- /База iOS/CoreGraphics/images/draw-lines.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/CoreGraphics/images/draw-lines.png -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Assets.xcassets/home/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /База iOS/Margins/images/directional-margin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Margins/images/directional-margin.png -------------------------------------------------------------------------------- /База iOS/CoreGraphics/images/rotated-square.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/CoreGraphics/images/rotated-square.png -------------------------------------------------------------------------------- /База iOS/CoreGraphics/images/square-no-border.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/CoreGraphics/images/square-no-border.png -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Bridge/Bridge.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Bridge/Bridge.png -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Facade/facade.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Facade/facade.png -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Observer/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Observer/.DS_Store -------------------------------------------------------------------------------- /Starbucs-historyView/HistoryVIew/HistoryVIew/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "author" : "xcode", 4 | "version" : 1 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /База iOS/Color/images/dynamic-system-color-both.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Color/images/dynamic-system-color-both.png -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Adapter/adapter.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Adapter/adapter.jpeg -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Builder/builder.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Builder/builder.jpeg -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Decorator/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Decorator/.DS_Store -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Visitor/Visitor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Visitor/Visitor.png -------------------------------------------------------------------------------- /База iOS/DynamicFont/images/preferred-font-sizes.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/DynamicFont/images/preferred-font-sizes.png -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Composite/composite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Composite/composite.png -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Iterator/iterator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Iterator/iterator.png -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Mediator/Mediator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Mediator/Mediator.png -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Prototype/prototype.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Prototype/prototype.png -------------------------------------------------------------------------------- /PopularApps/swift-arcade-Starbucks-assets-home/bonus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/PopularApps/swift-arcade-Starbucks-assets-home/bonus.png -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Singleton/singleton.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Singleton/singleton.jpeg -------------------------------------------------------------------------------- /PopularApps/swift-arcade-Starbucks-assets-home/meatless.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/PopularApps/swift-arcade-Starbucks-assets-home/meatless.png -------------------------------------------------------------------------------- /База iOS/Color/images/dynamic-stystem-background-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Color/images/dynamic-stystem-background-example.png -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Decorator/decorator_design.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Decorator/decorator_design.gif -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Observer/example-observer.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Observer/example-observer.gif -------------------------------------------------------------------------------- /PopularApps/swift-arcade-Starbucks-assets-home/communities.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/PopularApps/swift-arcade-Starbucks-assets-home/communities.png -------------------------------------------------------------------------------- /PopularApps/swift-arcade-Starbucks-assets-home/green-indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/PopularApps/swift-arcade-Starbucks-assets-home/green-indicator.png -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Template method/template-method.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Template method/template-method.png -------------------------------------------------------------------------------- /База iOS/Color/images/dynamic-system-grouped-background-example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/База iOS/Color/images/dynamic-system-grouped-background-example.png -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Assets.xcassets/home/bonus.imageset/bonus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/PopularApps/Starbucks/Starbucks/Assets.xcassets/home/bonus.imageset/bonus.png -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Strategy/strategy-design-temlate_proSwift_ru.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Strategy/strategy-design-temlate_proSwift_ru.png -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Assets.xcassets/home/meatless.imageset/meatless.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/PopularApps/Starbucks/Starbucks/Assets.xcassets/home/meatless.imageset/meatless.png -------------------------------------------------------------------------------- /GenericTableVIew1/README.md: -------------------------------------------------------------------------------- 1 | # GenericTableVIew 2 | В приложения часто используют TableView, практически на каждой странице, чтобы каждый раз не дуюлировать код можно использовать GenericTableView Class который управляет созданием таблицы. -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Assets.xcassets/home/communities.imageset/communities.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/PopularApps/Starbucks/Starbucks/Assets.xcassets/home/communities.imageset/communities.png -------------------------------------------------------------------------------- /FaceBookPage/FaceBookPage.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Chain of responsibility/Chain_of_responsibility_proSwift_ru.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Шаблоны программирования Swift/Chain of responsibility/Chain_of_responsibility_proSwift_ru.gif -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /FaceBookPage/FaceBookPage/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Assets.xcassets/home/green-indicator.imageset/green-indicator.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/PopularApps/Starbucks/Starbucks/Assets.xcassets/home/green-indicator.imageset/green-indicator.png -------------------------------------------------------------------------------- /Starbucs-historyView/HistoryVIew/HistoryVIew/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /Starbucs-historyView/HistoryVIew/HistoryVIew.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks.xcodeproj/xcuserdata/vladimir.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | -------------------------------------------------------------------------------- /Starbucs-historyView/HistoryVIew/HistoryVIew/Assets.xcassets/AccentColor.colorset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "colors" : [ 3 | { 4 | "idiom" : "universal" 5 | } 6 | ], 7 | "info" : { 8 | "author" : "xcode", 9 | "version" : 1 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /FaceBookPage/FaceBookPage.xcodeproj/project.xcworkspace/xcuserdata/vladimir.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/FaceBookPage/FaceBookPage.xcodeproj/project.xcworkspace/xcuserdata/vladimir.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks.xcodeproj/project.xcworkspace/xcuserdata/vladimir.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/PopularApps/Starbucks/Starbucks.xcodeproj/project.xcworkspace/xcuserdata/vladimir.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Алгоритмы/Базовые задачи и решения/MyPlaygroundFib.playground/contents.xcplayground: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /FaceBookPage/FaceBookPage/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | UIViewControllerBasedStatusBarAppearance 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /GenericTableVIew1/GenericTableView.xcodeproj/project.xcworkspace/xcuserdata/vladimir.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/GenericTableVIew1/GenericTableView.xcodeproj/project.xcworkspace/xcuserdata/vladimir.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /GenericTableVIew1/GenericTableView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks.xcodeproj/project.xcworkspace/xcuserdata/vladimir.xcuserdatad/IDEFindNavigatorScopes.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /Starbucs-historyView/HistoryVIew/HistoryVIew.xcodeproj/project.xcworkspace/xcuserdata/vladimir.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dinozavr2005/ios-library/HEAD/Starbucs-historyView/HistoryVIew/HistoryVIew.xcodeproj/project.xcworkspace/xcuserdata/vladimir.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /Шаблоны программирования Swift/README.md: -------------------------------------------------------------------------------- 1 | # Шаблоны программирования Swift 2 | 3 | Шаблон проектирования или паттерн (англ. design pattern) в разработке программного обеспечения — повторимая архитектурная конструкция, представляющая собой решение проблемы проектирования в рамках некоторого часто возникающего контекста. 4 | 5 | 6 | -------------------------------------------------------------------------------- /FaceBookPage/FaceBookPage.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /GenericTableVIew1/GenericTableView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Starbucs-historyView/HistoryVIew/HistoryVIew.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Assets.xcassets/home/bonus.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "bonus.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Assets.xcassets/home/meatless.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "meatless.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Assets.xcassets/home/communities.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "communities.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Assets.xcassets/home/green-indicator.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "filename" : "green-indicator.png", 5 | "idiom" : "universal", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "author" : "xcode", 19 | "version" : 1 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /FaceBookPage/FaceBookPage.xcodeproj/xcuserdata/vladimir.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | FaceBookPage.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /GenericTableVIew1/GenericTableView.xcodeproj/xcuserdata/hanyhabil.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | AwesonTable.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Starbucs-historyView/HistoryVIew/HistoryVIew.xcodeproj/xcuserdata/vladimir.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | HistoryVIew.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /GenericTableVIew1/GenericTableView.xcodeproj/xcuserdata/vladimir.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | AwesonTable.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | GenericTableView.xcscheme_^#shared#^_ 13 | 14 | orderHint 15 | 0 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks.xcodeproj/xcuserdata/vladimir.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | Starbucks.xcscheme_^#shared#^_ 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | E7E7F11928280B94006E2C3C 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Алгоритмы/Arcade/README.md: -------------------------------------------------------------------------------- 1 | # Arcade 2 | https://habr.com/ru/post/701822/ 3 | ## Задачи в файле Arcade.swft 4 | 5 | примеры задач: 6 | ```swift 7 | func findMergeInsight(headA: Node?, headB: Node?) -> Int? { // O(n) 8 | let m = length(headA) // O(n) 9 | let n = length(headB) // O(n) 10 | 11 | let d = m - n 12 | var currentA = headA 13 | for _ in 1...d { // O(n) 14 | currentA = currentA?.next 15 | } 16 | 17 | var currentB = headB 18 | for _ in 0...n-1 { // O(n) 19 | let A = currentA?.data 20 | let B = currentB?.data 21 | if A == B { 22 | return A 23 | } 24 | currentA = currentA?.next 25 | currentB = currentB?.next 26 | } 27 | return nil 28 | } 29 | ``` 30 | -------------------------------------------------------------------------------- /Starbucs-historyView/HistoryVIew/HistoryVIew/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // HistoryVIew 4 | // 5 | // Created by Владимир on 31.05.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | 13 | var window: UIWindow? 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | 17 | window = UIWindow(frame: UIScreen.main.bounds) 18 | window?.makeKeyAndVisible() 19 | window?.backgroundColor = .systemBackground 20 | window?.rootViewController = HistoryViewController() 21 | 22 | 23 | return true 24 | } 25 | } 26 | 27 | -------------------------------------------------------------------------------- /GenericTableVIew1/AwesonTable/ViewController.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | import UIKit 4 | 5 | class ViewController: UIViewController { 6 | 7 | var items = [String]() 8 | var reustableTable: GenericTableView! 9 | 10 | override func viewDidLoad() { 11 | super.viewDidLoad() 12 | // Do any additional setup after loading the view. 13 | Timer.scheduledTimer(withTimeInterval: 3.0, repeats: false) { (_) in 14 | self.items = ["black", "white"] 15 | self.reustableTable.reload(data: self.items) 16 | } 17 | setupTable() 18 | } 19 | 20 | func setupTable() { 21 | reustableTable = GenericTableView(frame: view.frame, items: items, config: { (item, cell) in 22 | cell.textLabel?.text = item 23 | }, selectHandler: { (item) in 24 | print(item) 25 | }) 26 | 27 | view.addSubview(reustableTable) 28 | } 29 | 30 | } 31 | 32 | -------------------------------------------------------------------------------- /Алгоритмы/Базовые задачи и решения/MyPlaygroundFib.playground/Contents.swift: -------------------------------------------------------------------------------- 1 | import UIKit 2 | 3 | /* 4 | ___ _ ___ 5 | | __(_)_____| _ )_ _ ______ 6 | | _|| |_ /_ / _ \ || |_ /_ / 7 | |_| |_/__/__|___/\_,_/__/__| 8 | 9 | // Задача: Написать программу, которая выводит числа от 1 до 100. 10 | // Но для чисел, кратных трем, вместо числа печатать 'Fizz'. 11 | // И для чисел, кратных пяти, печатать 'Buzz'. 12 | // Для чисел, которые кратны и трем, и пяти, печатать 'FizzBuzz'. 13 | // 14 | // Пример: 15 | 1 16 | 2 17 | Fizz 18 | 4 19 | Buzz 20 | ... 21 | 14 22 | FizzBuzz 23 | */ 24 | 25 | func fizzBuzz() { 26 | for i in 1..<101 { 27 | if i % 3 == 0 && i % 5 == 0 { 28 | print("FizzBuzz") 29 | } else if i % 3 == 0 { 30 | print("Fizz") 31 | } else if i % 5 == 0 { 32 | print("Buzz") 33 | } else { 34 | print(i) 35 | } 36 | } 37 | } 38 | 39 | fizzBuzz() 40 | 41 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Home/Rewards/RewardsTileViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RewardsTileViewController.swift 3 | // Starbucks 4 | // 5 | // Created by Владимир on 13.05.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | class RewardsTileViewController: UIViewController { 11 | 12 | let rewardTileView = RewardsTileView() 13 | 14 | override func viewDidLoad() { 15 | super.viewDidLoad() 16 | 17 | rewardTileView.translatesAutoresizingMaskIntoConstraints = false 18 | 19 | view.addSubview(rewardTileView) 20 | 21 | NSLayoutConstraint.activate([ 22 | rewardTileView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), 23 | rewardTileView.leadingAnchor.constraint(equalTo: view.leadingAnchor), 24 | rewardTileView.trailingAnchor.constraint(equalTo: view.trailingAnchor), 25 | rewardTileView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor) 26 | ]) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Home/PlaceholderViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TileView.swift 3 | // Starbucks 4 | // 5 | // Created by Владимир on 11.05.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | class PlaceholderViewController: UIViewController { 11 | 12 | let label = UILabel() 13 | 14 | init(_ text: String) { 15 | super.init(nibName: nil, bundle: nil) 16 | label.text = text 17 | } 18 | 19 | required init?(coder: NSCoder) { 20 | fatalError("init(coder:) has not been implemented") 21 | } 22 | 23 | override func viewDidLoad() { 24 | super.viewDidLoad() 25 | view.backgroundColor = .systemYellow 26 | layout() 27 | } 28 | 29 | func layout() { 30 | label.translatesAutoresizingMaskIntoConstraints = false 31 | 32 | view.addSubview(label) 33 | 34 | NSLayoutConstraint.activate([ 35 | label.centerXAnchor.constraint(equalTo: view.centerXAnchor), 36 | label.centerYAnchor.constraint(equalTo: view.centerYAnchor), 37 | view.heightAnchor.constraint(equalToConstant: 300) 38 | ]) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /База iOS/FramesVsBounds/README.md: -------------------------------------------------------------------------------- 1 | # Frames vs Bounds 2 | 3 | - **frame** = местоположение и размер вида с использованием **системы координат родительского вида** (важно для размещения вида в родительском вью) 4 | 5 | 6 | - **bounds** = расположение и размер представления с использованием **собственной системы координат** (важно для размещения содержимого представления или подвидов внутри себя) 7 | 8 | Frame(Рамка) в iOS похожа на рамку картины на стене. Они относятся к super view. И они особо не меняются. 9 | 10 | Bounds is the coordinate systems within the frame itself. There is a distinction. Because while the frame rarely changes, the bounds inside the view does. This is how `UIScrollViews` work as well as animations. They change their bounds but leave their frames. 11 | 12 | Bounds(Границы) — это системы координат внутри самого кадра. Фрейм меняется редко, bounds внутри view меняются чаще - так работают `UIScrollViews`, а также анимация. Они меняют свои bounds, но оставляют свои frames. 13 | 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /FaceBookPage/FaceBookPage/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // FaceBookPage 4 | // 5 | // Created by Владимир on 07.05.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | @UIApplicationMain 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | 13 | var window: UIWindow? 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | 17 | window = UIWindow(frame: UIScreen.main.bounds) 18 | window?.makeKeyAndVisible() 19 | 20 | let feedController = FeedController(collectionViewLayout: UICollectionViewFlowLayout()) 21 | let navigatorController = UINavigationController(rootViewController: feedController) 22 | window?.rootViewController = navigatorController 23 | 24 | UINavigationBar.appearance().barTintColor = UIColor(red: 51/255, green: 90/255, blue: 149/255, alpha: 1) 25 | UINavigationBar.appearance().titleTextAttributes = [NSAttributedString.Key.foregroundColor: UIColor.white] 26 | 27 | // even after setting this the status bar is still black... 28 | application.statusBarStyle = .lightContent 29 | // fix is to add the following Info.plist entry 30 | // `View controller-based status bar` boolean value of `NO` 31 | 32 | return true 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /GenericTableVIew1/AwesonTable/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | import UIKit 4 | 5 | @UIApplicationMain 6 | class AppDelegate: UIResponder, UIApplicationDelegate { 7 | 8 | 9 | 10 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 11 | // Override point for customization after application launch. 12 | return true 13 | } 14 | 15 | // MARK: UISceneSession Lifecycle 16 | 17 | func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { 18 | // Called when a new scene session is being created. 19 | // Use this method to select a configuration to create the new scene with. 20 | return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) 21 | } 22 | 23 | func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) { 24 | // Called when the user discards a scene session. 25 | // If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions. 26 | // Use this method to release any resources that were specific to the discarded scenes, as they will not return. 27 | } 28 | 29 | 30 | } 31 | 32 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Home/TileViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TileViewController.swift 3 | // Starbucks 4 | // 5 | // Created by Владимир on 11.05.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | class TileViewController: UIViewController { 11 | 12 | let tileView = TileView() 13 | 14 | init(title: String, subtitle: String, imageName: String) { 15 | super.init(nibName: nil, bundle: nil) 16 | 17 | tileView.titleLabel.text = title 18 | tileView.subtitleLabel.text = subtitle 19 | tileView.imageView.image = UIImage(named: imageName) 20 | } 21 | 22 | required init?(coder: NSCoder) { 23 | fatalError("init(coder:) has not been implemented") 24 | } 25 | 26 | override func viewDidLoad() { 27 | super.viewDidLoad() 28 | style() 29 | layout() 30 | } 31 | 32 | func style() { 33 | tileView.translatesAutoresizingMaskIntoConstraints = false 34 | } 35 | 36 | func layout() { 37 | view.addSubview(tileView) 38 | 39 | NSLayoutConstraint.activate([ 40 | tileView.topAnchor.constraint(equalTo: view.topAnchor), 41 | tileView.leadingAnchor.constraint(equalTo: view.leadingAnchor), 42 | tileView.trailingAnchor.constraint(equalTo: view.trailingAnchor), 43 | tileView.bottomAnchor.constraint(equalTo: view.bottomAnchor), 44 | ]) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Iterator/README.md: -------------------------------------------------------------------------------- 1 | # Iterator 2 | 3 | В книге даны уж больно замудренные примеры, но это обусловленно особенностями языка Objective-C. На Swift пример занимает в разы меньше. 4 | 5 | Так что для начала пример из жизни: 6 | 7 | И как показывает практика, самый простой пример – это обычная вендинг машина. (сам пример взят из книги Pro Objective-C Design Patterns for iOS). У нас есть контейнер, который разделен на секции, каждая из которых содержит определенный вид товара, к примеру набор бутылок Coca-Cola. Когда мы заказываем товар, то нам выпадет следующий из колекции. Образно говоря, команда cocaColaCollection.next 8 | 9 | Паттерн итератор позволяет последовательно обращаться к колекции объектов, не особо вникая что же это за коллекция. 10 | 11 | Самый простой пример перебора выгляди так: 12 | ```Swift 13 | et array = ["Яблоки", "Персики", "Сливы"] 14 | 15 | for (index, item) in array.enumerate() { 16 | print("Нашли \(item) на позиции \(index)") 17 | } 18 | 19 | //console 20 | Нашли Яблоки на позиции 0 21 | Нашли Персики на позиции 1 22 | Нашли Сливы на позиции 2 23 | ``` 24 | По сути, шаблон **Итератор** используется для обеспечения стандартного интерфейса для обхода набора элементов без необходимости понять структуру этого набора. 25 | 26 | -------------------------------------------------------------------------------- /База iOS/Networking/README.md: -------------------------------------------------------------------------------- 1 | # Networking 2 | 3 | ```swift 4 | import UIKit 5 | 6 | class ViewController: UIViewController { 7 | 8 | override func viewDidLoad() { 9 | super.viewDidLoad() 10 | startLoad() 11 | } 12 | 13 | func startLoad() { 14 | let url = URL(string: "https://uwyg0quc7d.execute-api.us-west-2.amazonaws.com/prod/account")! 15 | let task = URLSession.shared.dataTask(with: url) { data, response, error in 16 | if let error = error { 17 | print("Error: \(error)") 18 | return 19 | } 20 | guard let httpResponse = response as? HTTPURLResponse, 21 | (200...299).contains(httpResponse.statusCode) else { 22 | print("Server Error") 23 | return 24 | } 25 | if let mimeType = httpResponse.mimeType, mimeType == "application/json", 26 | let data = data, 27 | let string = String(data: data, encoding: .utf8) { 28 | DispatchQueue.main.async { 29 | // update UI 30 | print(string) 31 | } 32 | } 33 | } 34 | task.resume() 35 | } 36 | } 37 | ``` 38 | 39 | 40 | ### Links that help 41 | 42 | - [Apple Networking](https://developer.apple.com/documentation/foundation/url_loading_system) 43 | - [Apple Website into Memory](https://developer.apple.com/documentation/foundation/url_loading_system/fetching_website_data_into_memory) 44 | - [Learn App Making](https://learnappmaking.com/urlsession-swift-networking-how-to/) 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /GenericTableVIew1/AwesonTable/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /GenericTableVIew1/AwesonTable/GenericTableView.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | import UIKit 4 | 5 | class GenericTableView: UITableView, UITableViewDelegate, UITableViewDataSource { 6 | 7 | var items: [Item]! 8 | var config: (Item, Cell) -> () 9 | var selectHandler: (Item) -> () 10 | 11 | init(frame: CGRect, items: [Item], config: @escaping (Item, Cell) -> (), selectHandler: @escaping (Item) -> ()) { 12 | self.items = items 13 | self.config = config 14 | self.selectHandler = selectHandler 15 | super.init(frame: frame, style: .plain) 16 | 17 | self.delegate = self 18 | self.dataSource = self 19 | self.register(Cell.self, forCellReuseIdentifier: "Cell") 20 | self.translatesAutoresizingMaskIntoConstraints = false 21 | } 22 | 23 | required init?(coder: NSCoder) { 24 | fatalError("init(coder:) has not been implemented") 25 | } 26 | 27 | func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 28 | return items.count 29 | } 30 | 31 | func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 32 | let cell = self.dequeueReusableCell(withIdentifier: "Cell", for: indexPath) as! Cell 33 | config(items[indexPath.row], cell) 34 | 35 | return cell 36 | } 37 | 38 | func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 39 | selectHandler(items[indexPath.row]) 40 | } 41 | 42 | } 43 | 44 | extension GenericTableView { 45 | func reload(data items: [Item]) { 46 | self.items = items 47 | self.reloadData() 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Home/StarRewards/StarAndPoints.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StarAndPoints.swift 3 | // Starbucks 4 | // 5 | // Created by Владимир on 18.05.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | class StarAndPoints: UIView { 11 | 12 | let pointsLabel = UILabel() 13 | let starView = makeSymbolImageView(systemName: "star.fill", scale: .small) 14 | 15 | override init(frame: CGRect) { 16 | super.init(frame: .zero) 17 | style() 18 | layout() 19 | } 20 | 21 | required init?(coder: NSCoder) { 22 | fatalError("init(coder:) has not been implemented") 23 | } 24 | 25 | func style() { 26 | pointsLabel.translatesAutoresizingMaskIntoConstraints = false 27 | pointsLabel.font = UIFont.preferredFont(forTextStyle: .callout).bold() 28 | pointsLabel.textAlignment = .right 29 | 30 | starView.translatesAutoresizingMaskIntoConstraints = false 31 | starView.tintColor = .starYellow 32 | starView.contentMode = .scaleAspectFit 33 | } 34 | 35 | func layout() { 36 | addSubview(pointsLabel) 37 | addSubview(starView) 38 | 39 | NSLayoutConstraint.activate([ 40 | pointsLabel.topAnchor.constraint(equalTo: topAnchor, constant: 2), 41 | pointsLabel.trailingAnchor.constraint(equalTo: starView.leadingAnchor, constant: -2), 42 | pointsLabel.bottomAnchor.constraint(equalTo: bottomAnchor), 43 | 44 | starView.trailingAnchor.constraint(equalTo: trailingAnchor), 45 | starView.centerYAnchor.constraint(equalTo: centerYAnchor), 46 | ]) 47 | } 48 | 49 | override var intrinsicContentSize: CGSize { 50 | return CGSize(width: 60, height: 16) 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /База iOS/hide:show Keyboard/README.md: -------------------------------------------------------------------------------- 1 | # Hide/Show Keyboard 2 | 3 | ```swift 4 | import UIKit 5 | 6 | class ViewController: UIViewController { 7 | 8 | override func viewDidLoad() { 9 | super.viewDidLoad() 10 | setupKeyBoard() 11 | } 12 | } 13 | 14 | extension ViewController { 15 | private func setupKeyBoard() { 16 | addKeyboardObserver( 17 | willShow: #selector(keyboardWillShow), 18 | willHide: #selector(keyboardWillHide) 19 | ) 20 | hideKeyboardWhenTappedAround() 21 | } 22 | // MARK: - Helpers 23 | @objc private func keyboardWillShow(notification:NSNotification){ 24 | if let userInfo = notification.userInfo { 25 | view.layoutIfNeeded() 26 | let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as! NSValue).cgRectValue 27 | UIView.animate(withDuration: 0.2, animations: { [weak self] in 28 | guard let self = self else { return } 29 | self.view.frame.origin.y = -(keyboardFrame.size.height - self.view.safeAreaBottom) 30 | self.view.layoutIfNeeded() 31 | }, completion: { finish in 32 | guard finish else { 33 | return 34 | } 35 | }) 36 | } 37 | } 38 | 39 | @objc private func keyboardWillHide(notification:NSNotification){ 40 | view.layoutIfNeeded() 41 | UIView.animate(withDuration: 0.2) { [weak self] in 42 | guard let self = self else { return } 43 | self.view.frame.origin.y = .zero 44 | self.view.layoutIfNeeded() 45 | } 46 | } 47 | } 48 | 49 | ``` 50 | 51 | 52 | 53 | -------------------------------------------------------------------------------- /FaceBookPage/FaceBookPage/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /GenericTableVIew1/AwesonTable/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Starbucs-historyView/HistoryVIew/HistoryVIew/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /Starbucs-historyView/HistoryVIew/HistoryVIew/HistoryViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HistoryViewController.swift 3 | // HistoryVIew 4 | // 5 | // Created by Владимир on 31.05.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | struct HistorySection { 11 | let title: String 12 | let transactions: [Transaction] 13 | } 14 | 15 | struct Transaction: Codable { 16 | let id: Int 17 | let type: String 18 | let amount: String 19 | let date: Date 20 | 21 | enum CodingKeys: String, CodingKey { 22 | case id 23 | case type 24 | case amount 25 | case date = "processed_at" 26 | } 27 | } 28 | 29 | class HistoryViewController: UITableViewController { 30 | 31 | let games = ["Pacman", 32 | "Space Invaders", 33 | "Galaga", 34 | "Space patrol", 35 | "Donkey kong"] 36 | 37 | let cellId = "cellId" 38 | 39 | override func viewDidLoad() { 40 | super.viewDidLoad() 41 | layout() 42 | } 43 | 44 | func layout() { 45 | navigationItem.title = "Games" 46 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellId) 47 | } 48 | } 49 | // MARK: - Data Source 50 | 51 | extension HistoryViewController { 52 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 53 | let cell = tableView.dequeueReusableCell(withIdentifier: cellId, for: indexPath) 54 | 55 | cell.textLabel?.text = games[indexPath.row] 56 | cell.accessoryType = UITableViewCell.AccessoryType.disclosureIndicator 57 | 58 | return cell 59 | } 60 | 61 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 62 | return games.count 63 | } 64 | } 65 | 66 | -------------------------------------------------------------------------------- /FaceBookPage/FaceBookPage/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /GenericTableVIew1/AwesonTable/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "20x20", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "20x20", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "29x29", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "29x29", 61 | "scale" : "2x" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "size" : "40x40", 66 | "scale" : "1x" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "size" : "40x40", 71 | "scale" : "2x" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "size" : "76x76", 76 | "scale" : "1x" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "size" : "76x76", 81 | "scale" : "2x" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "size" : "83.5x83.5", 86 | "scale" : "2x" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "size" : "1024x1024", 91 | "scale" : "1x" 92 | } 93 | ], 94 | "info" : { 95 | "version" : 1, 96 | "author" : "xcode" 97 | } 98 | } -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Starbucs-historyView/HistoryVIew/HistoryVIew/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "scale" : "2x", 6 | "size" : "20x20" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "scale" : "3x", 11 | "size" : "20x20" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "scale" : "2x", 16 | "size" : "29x29" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "scale" : "3x", 21 | "size" : "29x29" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "scale" : "2x", 26 | "size" : "40x40" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "scale" : "3x", 31 | "size" : "40x40" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "scale" : "2x", 36 | "size" : "60x60" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "scale" : "3x", 41 | "size" : "60x60" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "scale" : "1x", 46 | "size" : "20x20" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "scale" : "2x", 51 | "size" : "20x20" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "scale" : "1x", 56 | "size" : "29x29" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "scale" : "2x", 61 | "size" : "29x29" 62 | }, 63 | { 64 | "idiom" : "ipad", 65 | "scale" : "1x", 66 | "size" : "40x40" 67 | }, 68 | { 69 | "idiom" : "ipad", 70 | "scale" : "2x", 71 | "size" : "40x40" 72 | }, 73 | { 74 | "idiom" : "ipad", 75 | "scale" : "1x", 76 | "size" : "76x76" 77 | }, 78 | { 79 | "idiom" : "ipad", 80 | "scale" : "2x", 81 | "size" : "76x76" 82 | }, 83 | { 84 | "idiom" : "ipad", 85 | "scale" : "2x", 86 | "size" : "83.5x83.5" 87 | }, 88 | { 89 | "idiom" : "ios-marketing", 90 | "scale" : "1x", 91 | "size" : "1024x1024" 92 | } 93 | ], 94 | "info" : { 95 | "author" : "xcode", 96 | "version" : 1 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Decorator/README.md: -------------------------------------------------------------------------------- 1 | # Decorator 2 | 3 | 4 | Класный пример декоратора – различные чехлы для новых телефонов. Для начала у нас есть телефон. Но так как телефон дорогой, мы будем очень счастливы если он не разобьется при любом падении – потому мы покупаем чехол для него. То есть, к уже существующему предмету мы добавили функционал защиты от падения. Ну еще мы взяли стильный чехол – теперь наш телефон еще и выглядит отлично. А потом мы докупили съемный объектив, с помощью которого можно делать фотографии с эффектом “рыбьего глаза”. Декорировали наш телефон дополнительным функционалом:) 5 | 6 | Вот, приблизительно так выглядит реально описание паттерна декоратор. Теперь описание GoF: 7 | Декоратор добавляет некий функционал уже существующему объекту. 8 | 9 | Когда использовать этот паттерн: 10 | 11 | 1. Вы хотите добавить определенному объекту дополнительные возможности, при этом не задевая и не меняя других объектов 12 | 13 | 2. Дополнительные возможности класса – опциональны 14 | 15 | Радость Swift в данном случае – это использование расширений extension. Я не буду детально описывать расширения в этой статье, но в двух словах все же расскажу: Расширения – это возможность расширить любой объект дополнительным функционалом без использования механизма наследования. Давайте возьмем супер простой пример – декорирование Cocoa классов. К примеру добавим новый метод для объекта NSDate: 16 | ```Swift 17 | extension NSDate { 18 | func convertDateToString() -> String { 19 | let formatter = NSDateFormatter() 20 | formatter.dateFormat = "dd-0M-yyyy" 21 | return formatter.stringFromDate(self) 22 | } 23 | } 24 | ``` 25 | Как видим наше расширение определяет только один метод “convertDateToString”, который дату форматирует в текстовый формат 26 | 27 | Собственно, это все. 28 | ```Swift 29 | let dateNow = NSDate() 30 | print("Сейчас: \(dateNow.convertDateToString())") 31 | 32 | //console: 33 | Сейчас: 25-07-2016 34 | ``` 35 | 36 | 37 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Home/StarRewards/StarRewardsRow.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StarRewardsRow.swift 3 | // Starbucks 4 | // 5 | // Created by Владимир on 18.05.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | class StarRewardsRow: UIView { 11 | 12 | let starAndPoints = StarAndPoints() 13 | let descriptionLabel = UILabel() 14 | 15 | init(numberOfPoints: String, description: String) { 16 | starAndPoints.pointsLabel.text = numberOfPoints 17 | descriptionLabel.text = description 18 | 19 | super.init(frame: .zero) 20 | 21 | style() 22 | layout() 23 | } 24 | 25 | required init?(coder: NSCoder) { 26 | fatalError("init(coder:) has not been implemented") 27 | } 28 | } 29 | 30 | extension StarRewardsRow { 31 | func style() { 32 | starAndPoints.translatesAutoresizingMaskIntoConstraints = false 33 | 34 | descriptionLabel.translatesAutoresizingMaskIntoConstraints = false 35 | descriptionLabel.font = UIFont.preferredFont(forTextStyle: .footnote) 36 | descriptionLabel.numberOfLines = 0 37 | descriptionLabel.lineBreakMode = .byWordWrapping 38 | descriptionLabel.sizeToFit() 39 | } 40 | 41 | func layout() { 42 | addSubview(starAndPoints) 43 | addSubview(descriptionLabel) 44 | 45 | NSLayoutConstraint.activate([ 46 | starAndPoints.topAnchor.constraint(equalTo: topAnchor), 47 | starAndPoints.bottomAnchor.constraint(equalTo: bottomAnchor), 48 | starAndPoints.leadingAnchor.constraint(equalTo: leadingAnchor), 49 | 50 | descriptionLabel.topAnchor.constraint(equalTo: topAnchor), 51 | descriptionLabel.leadingAnchor.constraint(equalTo: starAndPoints.trailingAnchor, constant: 4), 52 | descriptionLabel.trailingAnchor.constraint(equalTo: trailingAnchor), 53 | descriptionLabel.bottomAnchor.constraint(equalTo: bottomAnchor), 54 | ]) 55 | 56 | starAndPoints.setContentHuggingPriority(.defaultHigh, for: .horizontal) 57 | descriptionLabel.heightAnchor.constraint(equalToConstant: descriptionLabel.frame.size.height).setActiveBreakable() 58 | } 59 | 60 | override var intrinsicContentSize: CGSize { 61 | return CGSize(width: 10, height: 16) 62 | } 63 | } 64 | -------------------------------------------------------------------------------- /NoStoryboards/README.md: -------------------------------------------------------------------------------- 1 | # Создание iOS приложения без сторибордов 2 | 1. Удаляем SceneDelegate 3 | 2. Удаляем Main.storyboard 4 | 3. Удаляем данные из info.plist, находим строчку**Application Scene Manifest** и удаляем ее 5 | 4. В настройках проекта в разделе TASRGETS переходим на вкладку "Build Settings" и в поиске пишем main, в появившемся списке удаляем **UIKit Main Storyboard File Base Name** 6 | 5. Редактируем файл **AppDelegate**, удаляем все содержимое и вставляем следующий код: 7 | ```swift 8 | import UIKit 9 | 10 | @main 11 | class AppDelegate: UIResponder, UIApplicationDelegate { 12 | 13 | var window: UIWindow? 14 | 15 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 16 | 17 | window = UIWindow(frame: UIScreen.main.bounds) 18 | window?.makeKeyAndVisible() 19 | window?.backgroundColor = .systemBackground 20 | window?.rootViewController = ViewController() 21 | 22 | return true 23 | } 24 | } 25 | ``` 26 | 6. Переходим в файл **ViewController** будаляем все содержимое и вставляем следующий код: 27 | ```swift 28 | import UIKit 29 | 30 | class ViewController: UIViewController { 31 | 32 | let stackView = UIStackView() 33 | let label = UILabel() 34 | 35 | override func viewDidLoad() { 36 | super.viewDidLoad() 37 | style() 38 | layout() 39 | } 40 | } 41 | 42 | extension ViewController { 43 | func style() { 44 | stackView.translatesAutoresizingMaskIntoConstraints = false 45 | stackView.axis = .vertical 46 | stackView.spacing = 20 47 | 48 | label.translatesAutoresizingMaskIntoConstraints = false 49 | label.text = "Welcome" 50 | label.font = UIFont.preferredFont(forTextStyle: .title1) 51 | } 52 | 53 | func layout() { 54 | stackView.addArrangedSubview(label) 55 | view.addSubview(stackView) 56 | 57 | NSLayoutConstraint.activate([ 58 | stackView.centerXAnchor.constraint(equalTo: view.centerXAnchor), 59 | stackView.centerYAnchor.constraint(equalTo: view.centerYAnchor) 60 | ]) 61 | } 62 | } 63 | ``` 64 | 65 | 7. Запускаем симулятор и на экране проявляется наш шаблон, теперь мы полностью готовы начать создавать свое приложение -------------------------------------------------------------------------------- /GenericTableVIew1/AwesonTable/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | GenericTableVIew 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | $(PRODUCT_BUNDLE_PACKAGE_TYPE) 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UIApplicationSceneManifest 26 | 27 | UIApplicationSupportsMultipleScenes 28 | 29 | UISceneConfigurations 30 | 31 | UIWindowSceneSessionRoleApplication 32 | 33 | 34 | UISceneConfigurationName 35 | Default Configuration 36 | UISceneDelegateClassName 37 | $(PRODUCT_MODULE_NAME).SceneDelegate 38 | UISceneStoryboardFile 39 | Main 40 | 41 | 42 | 43 | 44 | UILaunchStoryboardName 45 | LaunchScreen 46 | UIMainStoryboardFile 47 | Main 48 | UIRequiredDeviceCapabilities 49 | 50 | armv7 51 | 52 | UISupportedInterfaceOrientations 53 | 54 | UIInterfaceOrientationPortrait 55 | UIInterfaceOrientationLandscapeLeft 56 | UIInterfaceOrientationLandscapeRight 57 | 58 | UISupportedInterfaceOrientations~ipad 59 | 60 | UIInterfaceOrientationPortrait 61 | UIInterfaceOrientationPortraitUpsideDown 62 | UIInterfaceOrientationLandscapeLeft 63 | UIInterfaceOrientationLandscapeRight 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Home/Rewards/BalanceView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // BalanceView.swift 3 | // Starbucks 4 | // 5 | // Created by Владимир on 14.05.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | class BalanceView: UIView { 11 | 12 | let pointsLabel = UILabel() 13 | let starView = makeSymbolImageView(systemName: "star.fill") 14 | let starBalanceLabel = UILabel() 15 | 16 | override init(frame: CGRect) { 17 | super.init(frame: .zero) 18 | style() 19 | layout() 20 | } 21 | 22 | required init?(coder: NSCoder) { 23 | fatalError("init(coder:) has not been implemented") 24 | } 25 | 26 | func style() { 27 | pointsLabel.translatesAutoresizingMaskIntoConstraints = false 28 | pointsLabel.font = UIFont.preferredFont(forTextStyle: .largeTitle).bold() 29 | pointsLabel.text = "12" 30 | 31 | starView.translatesAutoresizingMaskIntoConstraints = false 32 | starView.tintColor = .starYellow 33 | starView.contentMode = .scaleAspectFit 34 | 35 | starBalanceLabel.translatesAutoresizingMaskIntoConstraints = false 36 | starBalanceLabel.font = UIFont.preferredFont(forTextStyle: .footnote) 37 | starBalanceLabel.textColor = .label 38 | starBalanceLabel.text = "Star balance" 39 | } 40 | 41 | func layout() { 42 | addSubview(pointsLabel) 43 | addSubview(starView) 44 | addSubview(starBalanceLabel) 45 | 46 | NSLayoutConstraint.activate([ 47 | pointsLabel.topAnchor.constraint(equalTo: topAnchor), 48 | pointsLabel.leadingAnchor.constraint(equalTo: leadingAnchor), 49 | 50 | starView.leadingAnchor.constraint(equalTo: pointsLabel.trailingAnchor, constant: -2), 51 | starView.centerYAnchor.constraint(equalTo: pointsLabel.centerYAnchor, constant: 4), 52 | starView.heightAnchor.constraint(equalToConstant: 15), 53 | 54 | starBalanceLabel.topAnchor.constraint(equalTo: pointsLabel.bottomAnchor,constant: 0), 55 | starBalanceLabel.leadingAnchor.constraint(equalTo: pointsLabel.leadingAnchor), 56 | starBalanceLabel.trailingAnchor.constraint(equalTo: trailingAnchor), 57 | starBalanceLabel.bottomAnchor.constraint(equalTo: bottomAnchor), 58 | ]) 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /GenericTableVIew1/AwesonTable/SceneDelegate.swift: -------------------------------------------------------------------------------- 1 | 2 | 3 | import UIKit 4 | 5 | class SceneDelegate: UIResponder, UIWindowSceneDelegate { 6 | 7 | var window: UIWindow? 8 | 9 | 10 | func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { 11 | // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`. 12 | // If using a storyboard, the `window` property will automatically be initialized and attached to the scene. 13 | // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead). 14 | guard let _ = (scene as? UIWindowScene) else { return } 15 | } 16 | 17 | func sceneDidDisconnect(_ scene: UIScene) { 18 | // Called as the scene is being released by the system. 19 | // This occurs shortly after the scene enters the background, or when its session is discarded. 20 | // Release any resources associated with this scene that can be re-created the next time the scene connects. 21 | // The scene may re-connect later, as its session was not neccessarily discarded (see `application:didDiscardSceneSessions` instead). 22 | } 23 | 24 | func sceneDidBecomeActive(_ scene: UIScene) { 25 | // Called when the scene has moved from an inactive state to an active state. 26 | // Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive. 27 | } 28 | 29 | func sceneWillResignActive(_ scene: UIScene) { 30 | // Called when the scene will move from an active state to an inactive state. 31 | // This may occur due to temporary interruptions (ex. an incoming phone call). 32 | } 33 | 34 | func sceneWillEnterForeground(_ scene: UIScene) { 35 | // Called as the scene transitions from the background to the foreground. 36 | // Use this method to undo the changes made on entering the background. 37 | } 38 | 39 | func sceneDidEnterBackground(_ scene: UIScene) { 40 | // Called as the scene transitions from the foreground to the background. 41 | // Use this method to save data, release shared resources, and store enough scene-specific state information 42 | // to restore the scene back to its current state. 43 | } 44 | 45 | 46 | } 47 | 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | .DS_Store 8 | 9 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 10 | *.xcscmblueprint 11 | *.xccheckout 12 | 13 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 14 | build/ 15 | DerivedData/ 16 | *.moved-aside 17 | *.pbxuser 18 | !default.pbxuser 19 | *.mode1v3 20 | !default.mode1v3 21 | *.mode2v3 22 | !default.mode2v3 23 | *.perspectivev3 24 | !default.perspectivev3 25 | 26 | ## Obj-C/Swift specific 27 | *.hmap 28 | 29 | ## App packaging 30 | *.ipa 31 | *.dSYM.zip 32 | *.dSYM 33 | 34 | ## Playgrounds 35 | timeline.xctimeline 36 | playground.xcworkspace 37 | 38 | # Swift Package Manager 39 | # 40 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 41 | # Packages/ 42 | # Package.pins 43 | # Package.resolved 44 | # *.xcodeproj 45 | # 46 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 47 | # hence it is not needed unless you have added a package configuration file to your project 48 | # .swiftpm 49 | 50 | .build/ 51 | 52 | # CocoaPods 53 | # 54 | # We recommend against adding the Pods directory to your .gitignore. However 55 | # you should judge for yourself, the pros and cons are mentioned at: 56 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 57 | # 58 | # Pods/ 59 | # 60 | # Add this line if you want to avoid checking in source code from the Xcode workspace 61 | # *.xcworkspace 62 | 63 | # Carthage 64 | # 65 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 66 | # Carthage/Checkouts 67 | 68 | Carthage/Build/ 69 | 70 | # Accio dependency management 71 | Dependencies/ 72 | .accio/ 73 | 74 | # fastlane 75 | # 76 | # It is recommended to not store the screenshots in the git repo. 77 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 78 | # For more information about the recommended setup visit: 79 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 80 | 81 | fastlane/report.xml 82 | fastlane/Preview.html 83 | fastlane/screenshots/**/*.png 84 | fastlane/test_output 85 | 86 | # Code Injection 87 | # 88 | # After new code Injection tools there's a generated folder /iOSInjectionProject 89 | # https://github.com/johnno1962/injectionforxcode 90 | 91 | iOSInjectionProject/ -------------------------------------------------------------------------------- /База iOS/Color/README.md: -------------------------------------------------------------------------------- 1 | # Color 2 | 3 | ## System Colors 4 | 5 | iOS имеет ряд системных цветов, которые автоматически адаптируются к яркости и изменениям в настройках специальных возможностей, таких как «Увеличить контрастность» и «Уменьшить прозрачность». Системные цвета отлично смотрятся по отдельности и в сочетании, как на светлом, так и на темном фоне, как в подобном, так и в темном режимах. 6 | 7 | 8 | drawing 9 | 10 | drawing 11 | 12 | 13 | ## Dynamic System Colors 14 | 15 | Apple также имеет семантически определенные системные цвета для использования в фоновых областях, содержимом переднего плана и собственных элементах управления, таких как метки, разделители и заливка. Они автоматически адаптируются как к темным, так и к темным режимам пользовательского интерфейса. 16 | 17 | drawing 18 | 19 | drawing 20 | 21 | drawing 22 | 23 | drawing 24 | 25 | ## Programatic Color 26 | 27 | ```swift 28 | extension UIColor { 29 | static let darkBlue = UIColor(red: 10/255, green: 132/255, blue: 255/255, alpha: 1) 30 | } 31 | ``` 32 | 33 | Но также дайте цвету имя похожее на то, что он из себя представляет 34 | 35 | ```swift 36 | public extension UIColor { 37 | static var downloadColor: UIColor { 38 | return .shawSkyBlue 39 | } 40 | 41 | static var uploadColor: UIColor { 42 | return .shawTertiaryYellow 43 | } 44 | } 45 | ``` 46 | 47 | ### Полезные ссылки 48 | 49 | - [HIG Color](https://developer.apple.com/design/human-interface-guidelines/ios/visual-design/color/) 50 | - [Apple UI Element Colors](https://developer.apple.com/documentation/uikit/uicolor/ui_element_colors) 51 | - [Apple Design Resources](https://developer.apple.com/design/resources/) 52 | - [WWDC What's new in iOS](https://developer.apple.com/videos/play/wwdc2019/808/) 53 | -------------------------------------------------------------------------------- /BestGitIgnore/Swift.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## User settings 6 | xcuserdata/ 7 | 8 | ## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) 9 | *.xcscmblueprint 10 | *.xccheckout 11 | 12 | ## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) 13 | build/ 14 | DerivedData/ 15 | *.moved-aside 16 | *.pbxuser 17 | !default.pbxuser 18 | *.mode1v3 19 | !default.mode1v3 20 | *.mode2v3 21 | !default.mode2v3 22 | *.perspectivev3 23 | !default.perspectivev3 24 | 25 | ## Obj-C/Swift specific 26 | *.hmap 27 | 28 | ## App packaging 29 | *.ipa 30 | *.dSYM.zip 31 | *.dSYM 32 | 33 | ## Playgrounds 34 | timeline.xctimeline 35 | playground.xcworkspace 36 | 37 | # Swift Package Manager 38 | # 39 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 40 | # Packages/ 41 | # Package.pins 42 | # Package.resolved 43 | # *.xcodeproj 44 | # 45 | # Xcode automatically generates this directory with a .xcworkspacedata file and xcuserdata 46 | # hence it is not needed unless you have added a package configuration file to your project 47 | # .swiftpm 48 | 49 | .build/ 50 | 51 | # CocoaPods 52 | # 53 | # We recommend against adding the Pods directory to your .gitignore. However 54 | # you should judge for yourself, the pros and cons are mentioned at: 55 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 56 | # 57 | # Pods/ 58 | # 59 | # Add this line if you want to avoid checking in source code from the Xcode workspace 60 | # *.xcworkspace 61 | 62 | # Carthage 63 | # 64 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 65 | # Carthage/Checkouts 66 | 67 | Carthage/Build/ 68 | 69 | # Accio dependency management 70 | Dependencies/ 71 | .accio/ 72 | 73 | # fastlane 74 | # 75 | # It is recommended to not store the screenshots in the git repo. 76 | # Instead, use fastlane to re-generate the screenshots whenever they are needed. 77 | # For more information about the recommended setup visit: 78 | # https://docs.fastlane.tools/best-practices/source-control/#source-control 79 | 80 | fastlane/report.xml 81 | fastlane/Preview.html 82 | fastlane/screenshots/**/*.png 83 | fastlane/test_output 84 | 85 | # Code Injection 86 | # 87 | # After new code Injection tools there's a generated folder /iOSInjectionProject 88 | # https://github.com/johnno1962/injectionforxcode 89 | 90 | iOSInjectionProject/ 91 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Home/StarRewards/StarRewardsVIew.swift: -------------------------------------------------------------------------------- 1 | // 2 | // StarRewardsVIew.swift 3 | // Starbucks 4 | // 5 | // Created by Владимир on 18.05.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | class StarRewardsView: UIView { 11 | 12 | let stackView = UIStackView() 13 | let label = UILabel() 14 | 15 | struct Reward { 16 | let numberOfPoints: String 17 | let description: String 18 | } 19 | 20 | var rewards: [Reward] = 21 | [Reward(numberOfPoints: "25", description: "Customize your drink"), 22 | Reward(numberOfPoints: "50", description: "Brewed hot coffee, bakery item or hot tea"), 23 | Reward(numberOfPoints: "150", description: "Handcrafted drink, hot breakfast or parfait"), 24 | Reward(numberOfPoints: "250", description: "Lunch sandwich or protein box"), 25 | Reward(numberOfPoints: "400", description: "Select merchandise or at-home coffee"), 26 | ] 27 | 28 | override init(frame: CGRect) { 29 | super.init(frame: .zero) 30 | style() 31 | layout() 32 | } 33 | 34 | required init?(coder: NSCoder) { 35 | fatalError("init(coder:) has not been implemented") 36 | } 37 | } 38 | 39 | extension StarRewardsView { 40 | 41 | func style() { 42 | backgroundColor = .tileBrown 43 | layer.cornerRadius = 10 44 | 45 | stackView.translatesAutoresizingMaskIntoConstraints = false 46 | stackView.axis = .vertical 47 | stackView.spacing = 26 48 | stackView.isLayoutMarginsRelativeArrangement = true 49 | stackView.directionalLayoutMargins = NSDirectionalEdgeInsets(top: 16, leading: 16, bottom: 16, trailing: -16) 50 | 51 | label.translatesAutoresizingMaskIntoConstraints = false 52 | label.font = UIFont.preferredFont(forTextStyle: .title3).bold() 53 | label.text = "Rewards you can get with Stars" 54 | } 55 | 56 | func layout() { 57 | stackView.addArrangedSubview(label) 58 | 59 | for reward in rewards { 60 | stackView.addArrangedSubview(StarRewardsRow(numberOfPoints: reward.numberOfPoints, description: reward.description)) 61 | } 62 | 63 | addSubview(stackView) 64 | 65 | NSLayoutConstraint.activate([ 66 | stackView.topAnchor.constraint(equalTo: topAnchor), 67 | stackView.leadingAnchor.constraint(equalTo: leadingAnchor), 68 | stackView.trailingAnchor.constraint(equalTo: trailingAnchor), 69 | stackView.bottomAnchor.constraint(equalTo: bottomAnchor) 70 | ]) 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Factories.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Factories.swift 3 | // Starbucks 4 | // 5 | // Created by Владимир on 08.05.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | extension UIFont { 11 | func withTraits(traits: UIFontDescriptor.SymbolicTraits) -> UIFont { 12 | let descriptor = fontDescriptor.withSymbolicTraits(traits) 13 | return UIFont(descriptor: descriptor!, size: 0) 14 | } 15 | 16 | func bold() -> UIFont { 17 | return withTraits(traits: .traitBold) 18 | } 19 | } 20 | 21 | extension UIColor { 22 | static let starYellow = UIColor(red: 204/255, green: 153/255, blue: 51/255, alpha: 1) 23 | static let tileBrown = UIColor(red: 235/255, green: 235/255, blue: 228/255, alpha: 1) 24 | static let darkGreen = UIColor(red: 0/255, green: 133/255, blue: 67/255, alpha: 1) 25 | static let lightGreen = UIColor(red: 0/255, green: 171/255, blue: 90/255, alpha: 1) 26 | static let backgroundWhite = UIColor(red: 247/255, green: 247/255, blue: 247/255, alpha: 1) 27 | } 28 | 29 | func makeGreenButton(withText text: String) -> UIButton { 30 | let button = UIButton() 31 | button.translatesAutoresizingMaskIntoConstraints = false 32 | button.setTitle(text, for: .normal) 33 | button.titleLabel?.adjustsFontSizeToFitWidth = true 34 | button.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16) 35 | button.layer.cornerRadius = 40/2 36 | button.backgroundColor = .darkGreen 37 | 38 | return button 39 | } 40 | 41 | func makeSymbolImageView(systemName: String, scale: UIImage.SymbolScale = .large) -> UIImageView { 42 | let configuration = UIImage.SymbolConfiguration(scale: scale) 43 | let image = UIImage(systemName: systemName, withConfiguration: configuration) 44 | 45 | return UIImageView(image: image) 46 | } 47 | 48 | 49 | func makeClearButton(withText text: String) -> UIButton { 50 | let button = UIButton() 51 | button.translatesAutoresizingMaskIntoConstraints = false 52 | button.setTitle(text, for: .normal) 53 | button.titleLabel?.adjustsFontSizeToFitWidth = true 54 | button.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16) 55 | button.layer.cornerRadius = 40/2 56 | button.layer.borderWidth = 0.5 57 | 58 | button.setTitleColor(.label, for: .normal) 59 | button.layer.borderColor = UIColor.label.cgColor 60 | button.backgroundColor = .systemBackground 61 | 62 | return button 63 | } 64 | 65 | public extension NSLayoutConstraint { 66 | @objc func setActiveBreakable(priority: UILayoutPriority = UILayoutPriority(900)) { 67 | self.priority = priority 68 | isActive = true 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /База iOS/FactoryMethodsUIElements.md: -------------------------------------------------------------------------------- 1 | # Factory methods of UI elements 2 | 3 | ```swift 4 | import UIKit 5 | 6 | func makeButton(withText text: String) -> UIButton { 7 | let button = UIButton() 8 | button.translatesAutoresizingMaskIntoConstraints = false 9 | button.setTitle(text, for: .normal) 10 | button.titleLabel?.adjustsFontSizeToFitWidth = true 11 | button.contentEdgeInsets = UIEdgeInsets(top: 8, left: 16, bottom: 8, right: 16) 12 | button.backgroundColor = .systemBlue 13 | button.layer.cornerRadius = 8 14 | return button 15 | } 16 | 17 | func makeLabel(withTitle title: String) -> UILabel { 18 | let label = UILabel() 19 | label.translatesAutoresizingMaskIntoConstraints = false 20 | label.text = title 21 | label.textAlignment = .center 22 | label.textColor = .black 23 | label.numberOfLines = 0 24 | label.adjustsFontSizeToFitWidth = true 25 | 26 | return label 27 | } 28 | 29 | func makeHorizontalStackView() -> UIStackView { 30 | let stack = UIStackView() 31 | stack.translatesAutoresizingMaskIntoConstraints = false 32 | stack.spacing = 8.0 33 | 34 | return stack 35 | } 36 | 37 | func makeVerticalStackView() -> UIStackView { 38 | let stack = UIStackView() 39 | stack.translatesAutoresizingMaskIntoConstraints = false 40 | stack.axis = .vertical 41 | stack.spacing = 8.0 42 | 43 | return stack 44 | } 45 | 46 | func makeSymbolButton(systemName: String, target: Any, selector: Selector) -> UIButton { 47 | let configuration = UIImage.SymbolConfiguration(scale: .large) 48 | let image = UIImage(systemName: systemName, withConfiguration: configuration) 49 | 50 | let button = UIButton() 51 | button.translatesAutoresizingMaskIntoConstraints = false 52 | button.addTarget(target, action: selector, for: .primaryActionTriggered) 53 | button.setImage(image, for: .normal) 54 | button.imageView?.contentMode = .scaleAspectFit 55 | 56 | return button 57 | } 58 | 59 | func makeBarButtonItem(text: String, selector: Selector) -> UIBarButtonItem { 60 | let button = UIButton() 61 | button.translatesAutoresizingMaskIntoConstraints = false 62 | button.addTarget(self, action: selector, for: .primaryActionTriggered) 63 | 64 | let attributes = [ 65 | NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .largeTitle).withTraits(traits: [.traitBold]), 66 | NSAttributedString.Key.foregroundColor: UIColor.label] 67 | 68 | let attributedText = NSMutableAttributedString(string: text, attributes: attributes) 69 | 70 | button.setAttributedTitle(attributedText, for: .normal) 71 | button.contentEdgeInsets = UIEdgeInsets.init(top: 0, left: 0, bottom: 0, right: 16) 72 | 73 | let barButtonItem = UIBarButtonItem(customView: button) 74 | 75 | return barButtonItem 76 | } 77 | ``` 78 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Home/HomeHeaderView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // HomeHeaderView.swift 3 | // Starbucks 4 | // 5 | // Created by Владимир on 09.05.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | class HomeHeaderView: UIView { 11 | 12 | let greeting = UILabel() 13 | let inboxButton = UIButton() 14 | 15 | override init(frame: CGRect) { 16 | super.init(frame: .zero) 17 | style() 18 | layout() 19 | } 20 | 21 | required init?(coder: NSCoder) { 22 | fatalError("init(coder:) has not been implemented") 23 | } 24 | } 25 | 26 | extension HomeHeaderView { 27 | func style() { 28 | backgroundColor = .white 29 | 30 | greeting.translatesAutoresizingMaskIntoConstraints = false 31 | greeting.font = UIFont.preferredFont(forTextStyle: .largeTitle) 32 | greeting.text = "Good afternoon, Vladimir ☀️" 33 | greeting.numberOfLines = 0 34 | greeting.lineBreakMode = .byWordWrapping 35 | 36 | makeInboxButton() 37 | } 38 | 39 | func layout() { 40 | addSubview(greeting) 41 | addSubview(inboxButton) 42 | 43 | NSLayoutConstraint.activate([ 44 | greeting.topAnchor.constraint(equalToSystemSpacingBelow: topAnchor, multiplier: 1), 45 | greeting.leadingAnchor.constraint(equalToSystemSpacingAfter: leadingAnchor, multiplier: 1), 46 | trailingAnchor.constraint(equalToSystemSpacingAfter: greeting.trailingAnchor, multiplier: 1), 47 | 48 | inboxButton.topAnchor.constraint(equalToSystemSpacingBelow: greeting.bottomAnchor, multiplier: 2), 49 | inboxButton.leadingAnchor.constraint(equalToSystemSpacingAfter: leadingAnchor, multiplier: 2), 50 | bottomAnchor.constraint(equalToSystemSpacingBelow: inboxButton.bottomAnchor, multiplier: 1), 51 | inboxButton.widthAnchor.constraint(equalTo: widthAnchor, multiplier: 0.25), 52 | ]) 53 | } 54 | } 55 | 56 | // MARK: - Factories 57 | extension HomeHeaderView { 58 | func makeInboxButton() { 59 | inboxButton.translatesAutoresizingMaskIntoConstraints = false 60 | let configuration = UIImage.SymbolConfiguration(scale: .large) 61 | let image = UIImage(systemName: "envelope", withConfiguration: configuration) 62 | 63 | inboxButton.setImage(image, for: .normal) 64 | inboxButton.imageView?.tintColor = .secondaryLabel 65 | inboxButton.imageView?.contentMode = .scaleAspectFit 66 | 67 | inboxButton.setTitle("Inbox", for: .normal) 68 | inboxButton.setTitleColor(.secondaryLabel, for: .normal) 69 | 70 | inboxButton.imageEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 16) 71 | inboxButton.contentEdgeInsets = UIEdgeInsets(top: 0, left: 0, bottom: 0, right: 0) 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Алгоритмы/Алгоритмы сортировки/README.md: -------------------------------------------------------------------------------- 1 | # Sorting Algoritmhs 2 | 3 | ## Bubble Sorting 4 | Производительность пузырьковой сортировки O(n^2) 5 | ```swift 6 | import UIKit 7 | 8 | /* 9 | ___ _ _ _ ___ _ 10 | | _ )_ _| |__| |__| |___ / __| ___ _ _| |_ 11 | | _ \ || | '_ \ '_ \ / -_) \__ \/ _ \ '_| _| 12 | |___/\_,_|_.__/_.__/_\___| |___/\___/_| \__| 13 | */ 14 | 15 | 16 | 17 | class BubbleSort { 18 | func sort(_ array: [Int]) -> [Int] { 19 | var arr = array 20 | let n = arr.count 21 | for i in 0.. arr[j+1] { 24 | // меняем местами 25 | let temp = arr[j] 26 | arr[j] = arr[j+1] 27 | arr[j+1] = temp 28 | } 29 | } 30 | } 31 | 32 | return arr 33 | } 34 | } 35 | 36 | let bubbleSort = BubbleSort() 37 | bubbleSort.sort([5, 4, 3, 2, 1]) 38 | ``` 39 | 40 | ## Merge Sort 41 | Производительность сортировки делением O(n logn) 42 | 43 | ```swift 44 | func merge(arr1: [Int], arr2: [Int]) -> [Int] { 45 | var arr1Index = 0 46 | var arr2Index = 0 47 | 48 | var sortedSublist = [Int]() 49 | 50 | while arr1Index < arr1.count && arr2Index < arr2.count { 51 | if arr1[arr1Index] < arr2[arr2Index] { 52 | sortedArray.append(arr1[arr1Index]) 53 | arr1Index += 1 54 | } else if arr1[arr1Index] > arr2[arr2Index] { 55 | sortedArray.append(arr2[arr2Index]) 56 | arr2Index += 1 57 | } else { 58 | sortedArray.append(arr1[arr1Index]) 59 | arr1Index += 1 60 | sortedArray.append(arr2[arr2Index]) 61 | arr2Index += 1 62 | 63 | } 64 | } 65 | 66 | while arr1Index < arr1.count { 67 | sortedArray.append(arr1[arr1Index]) 68 | arr1Index += 1 69 | } 70 | while arr2Index < arr2.count { 71 | sortedArray.append(arr2[arr2Index]) 72 | arr2Index += 1 73 | } 74 | 75 | return sortedArray 76 | } 77 | 78 | 79 | func mergeSort(_ array: [Int]) -> [Int] { 80 | guard array.count > 1 else { return array } 81 | 82 | let cutIndex = array.count / 2 83 | 84 | let arr1 = mergeSort(Array(array[0..(_ a: [T]) -> [T] { 97 | guard a.count > 1 else { return a } 98 | 99 | let pivot = a[a.count/2] 100 | let less = a.filter { $0 < pivot } 101 | let equal = a.filter { $0 == pivot } 102 | let greater = a.filter { $0 > pivot } 103 | 104 | return quicksort(less) + equal + quicksort(greater) 105 | } 106 | 107 | let list = [ 10, 0, 3, 9, 2, 14, 8, 27, 1, 5, 8, -1, 26 ] 108 | quicksort(list) 109 | ``` 110 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks.xcodeproj/xcshareddata/xcschemes/Starbucks.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 43 | 45 | 51 | 52 | 53 | 54 | 60 | 62 | 68 | 69 | 70 | 71 | 73 | 74 | 77 | 78 | 79 | -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Bridge/README.md: -------------------------------------------------------------------------------- 1 | # Bridge 2 | 3 | 4 | 5 | Представьте себе, что у нас есть что-то однотипное, к примеру у нас есть телефон и куча наушников. Если бы у каждого телефона был свой разъем, то мы могли бы пользоваться только одним типом наушников. Но Бог миловал! Собственно таже штука и с наушникам. Они могут выдавать различный звук, иметь различные дополнительные функции, но основная их цель – просто звучание:) И хорошо, что во многих случаях штекер у них одинаковый (я не говорю про различные студийные наушники:) ). 6 | 7 | Собственно, Мост (Bridge) позволяет разделить абстракцию от реализации, так чтобы реализация в любой момент могла быть поменяна, не меняя при этом абстракции. 8 | 9 | Когда использовать? 10 | 11 | Вам совершенно не нужна связь между абстракцией и реализацией. 12 | 13 | Собственно, как абстракцию так и имплементацию могут наследовать независимо. 14 | Вы не хотите чтобы изменения в реализации имело влияния на клиентский код. 15 | 16 | Рассмотрим пример: 17 | 18 | Создадим базовый класс для наушников со своим функционалом: 19 | ```swift 20 | class BaseHeadphones { 21 | func playSimpleSound(){ 22 | print("Пш..") 23 | } 24 | func playBassSound() { 25 | print("Пш..") 26 | } 27 | } 28 | ``` 29 | И его наследников — дорогие и дешевые наушники: 30 | ```swift 31 | class CheapHeadphones: BaseHeadphones { 32 | override func playSimpleSound() { 33 | print("Бип-бип пшшшшшшш") 34 | } 35 | 36 | override func playBassSound() { 37 | print("Бух-Бух прррр") 38 | } 39 | 40 | } 41 | 42 | 43 | 44 | class ExpensiveHeadphones: BaseHeadphones { 45 | override func playSimpleSound() { 46 | print("Бип-Бип-Бип Тарам-пам-пам") 47 | } 48 | 49 | override func playBassSound() { 50 | print("Бам-бам-бам") 51 | } 52 | 53 | } 54 | ``` 55 | Как видите, функционал у них свой, отличающийся от базовой абстракции. 56 | 57 | И собственно плеер, через который мы будем слушать музыку: 58 | 59 | ```swift 60 | class MusicPlayer { 61 | var headPhones: BaseHeadphones? 62 | 63 | func playMusic() { 64 | headPhones?.playBassSound() 65 | headPhones?.playBassSound() 66 | headPhones?.playSimpleSound() 67 | headPhones?.playSimpleSound() 68 | } 69 | } 70 | ``` 71 | Как видите, одно из свойств нашего плеера – наушники. Их можно подменять в любой момент, так как свойство того же типа, от которого наши дешевые и дорогие наушники наследуются. 72 | Теперь тест! 73 | 74 | ```swift 75 | let player = MusicPlayer() 76 | let ch = CheapHeadphones() 77 | let ex = ExpensiveHeadphones() 78 | player.headPhones = ch 79 | player.playMusic() 80 | print("- - - - - - - - - - -") 81 | player.headPhones = ex 82 | player.playMusic() 83 | 84 | //console 85 | 86 | Бух-Бух прррр 87 | Бух-Бух прррр 88 | Бип-бип пшшшшшшш 89 | Бип-бип пшшшшшшш 90 | - - - - - - - - - - - 91 | Бам-бам-бам 92 | Бам-бам-бам 93 | Бип-Бип-Бип Тарам-пам-пам 94 | Бип-Бип-Бип Тарам-пам-пам 95 | ``` 96 | 97 | Как видно, все работает нормально. Наушники меняются и меняют функционал, при этом базовая абстракция у нас неизменна. 98 | 99 | 100 | -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Singleton/README.md: -------------------------------------------------------------------------------- 1 | # Singleton 2 | 3 | 4 | 5 | Singleton — это такой объект, который существует в системе только в единственном экземпляре. Очень часто используется для хранения каких — то глобальных переменных, например настроек приложения. Написание кода для создания подобного объекта следующее: 6 | 7 | ```swift 8 | class SingletonObject { 9 | 10 | var someProperty: String = "" 11 | 12 | class var singleton: SingletonObject { 13 | struct ForStatic { 14 | static var onceToken: dispatch_once_t = 0 15 | static var singletonObject: SingletonObject? = nil 16 | } 17 | dispatch_once(&ForStatic.onceToken) { 18 | ForStatic.singletonObject = SingletonObject() 19 | } 20 | 21 | return ForStatic.singletonObject! 22 | } 23 | 24 | } 25 | ``` 26 | 27 | Собственно вот и все:) iOS сам за нас позаботится о том, чтобы создан был только один экземпляр нашего объекта. Тут стоит сделать шаг назад и описать проблему, которая является головной болью любого кто более — менее близко работал с потоками: 28 | 29 | Представьте что есть 2 потока. И тут каждый, одновременно создает singleton. Вроде бы и должен создаться только один объект, но потому что все происходит в один момент –бывают случаи когда создается два объекта. Или еще более сложная ситуация: объекта singleton не существует. Два потока хотят его создать одновременно: Поток 1 делает проверку на существование объекта. Видит что его нет, и проходит этап проверки. 2.Поток 2 делает проверку на существование объекта, и хоть и поток 1 проверку УЖЕ прошел, но объект ЕЩЕ не существует. Для решения таких проблем dispatch_once делает блокирование кода, для других потоков, пока он исполняется в каком–либо потоке. Потому, ни один поток не может зайти в этот код, пока он занят. 30 | 31 | Проверка: 32 | ```swift 33 | let oneST = SingletonObject.singleton 34 | oneST.someProperty = "First instance" 35 | 36 | let twoST = SingletonObject.singleton 37 | twoST.someProperty = "Second instance" 38 | 39 | print("First: \(oneST.someProperty) and second: \(twoST.someProperty)") 40 | 41 | //console: 42 | First: Second instance and second: Second instance 43 | ``` 44 | Думаю, понятно, что при создании второго указателя twoST, он сослался на тот же экземпляр что и oneST, и поэтому изменения свойств через один указатель повлияют и на другой. 45 | 46 | Итак, шаблон Singleton гарантирует, что только один объект определенного класса будет когда-либо создан. Все последующие ссылки на объекты этого класса указывают на тот же экзеvпляр. 47 | 48 | ```swift 49 | class DeathStarSuperlaser { 50 | static let sharedInstance = DeathStarSuperlaser() 51 | 52 | private init() { 53 | 54 | } 55 | } 56 | 57 | 58 | let laser = DeathStarSuperlaser.sharedInstance 59 | ``` 60 | Инициализатор private используется, чтобы невозможно было создать еще один объект. 61 | 62 | А теперь давайте вспомним, где Вы уже применяли это шаблон программирования. 63 | 64 | ```swift 65 | NSUserDefaults.standardUserDefaults() 66 | // только одно хранилище 67 | UIApplication.sharedApplication() 68 | // только одно приложение 69 | UIScreen.mainScreen() 70 | // только один внутренний экран у устройства 71 | NSNotificationCenter.defaultCenter() 72 | // только один центр уведомлений 73 | ``` 74 | -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Template method/README.md: -------------------------------------------------------------------------------- 1 | # Template Method 2 | 3 | Вы заметили как много в нашей жизни шаблонов? Ну к примеру – наше поведение когда мы приходим в незнакомый дом: 4 | 5 | Зайти 6 | Поздороваться с ясхозяевами 7 | Раздеться, молясь о том что у нас носки не дырявые 8 | Пройти, и охать удивляясь какая большая/уютная/забавная квартира 9 | Или же когда мы приходим в квартиру, где происходит ремонт: 10 | 11 | Зайти 12 | Поздороваться с хозяевами 13 | Не раззуваться, потому как грязно! 14 | Поохать когда хозяин квартиры поведает нам смелость его архитектурной мысли! 15 | В целом, все происходит практически одинаково, но с изюминкой в каждом различно случае:) Наверное потому то, это и называется шаблоном поведения. Шаблонный метод задает алгоритму пошаговоую инструкцию. Элементы алгоритма же, определяются в наследующих классах. 16 | 17 | Сам паттерн ну очень интуитивный, и я уверен что многие давно уже использовали его. Потому давайте попробуем сделать пример. Вернемся к старой практике, писать примеры по созданию телефонов! 18 | 19 | Итак, напишем наш шаблонный класс, при помощи которого будем создавать телефон: 20 | ```swift 21 | class AnyPhoneTemplate { 22 | 23 | func takeBox() { 24 | print("Берем коробку") 25 | } 26 | 27 | func takeCamera() { 28 | print("Берем камеру") 29 | } 30 | 31 | func takeMicrophone() { 32 | print("Берем микрофон") 33 | } 34 | 35 | 36 | func assemble() { 37 | print("Собираем все вместе") 38 | } 39 | 40 | func makePhone() { 41 | takeBox() 42 | takeCamera() 43 | takeMicrophone() 44 | assemble() 45 | } 46 | } 47 | ``` 48 | Как вы уже наверное догадались – сам шаблонный метод, это метод makePhone – который задает последовательность вызовов методов необходимых для складывания телефонов. Давайте теперь научим нашу программу создавать айфоны: 49 | ```swift 50 | class iPhoneMaker: AnyPhoneTemplate { 51 | 52 | func design() { 53 | print("Клеим яблоко, и пишем Разработано в Калифорнии") 54 | } 55 | override func takeBox() { 56 | design() 57 | super.takeBox() 58 | } 59 | } 60 | ``` 61 | У сборщика яблочных телефонов есть один дополнительный метод – design, а также перегруженный метод takeBox в котором дополнительно вызывается метод design и после этого вызывается родительский метод takeBox. 62 | 63 | На очереди сборка Android: 64 | ```swift 65 | class AndroidMaker: AnyPhoneTemplate { 66 | 67 | func addRam() { 68 | print("Суем внутрь еще 6 процессоров") 69 | } 70 | 71 | func addCPU() { 72 | print("Добавляем вечно нехватающей оперативки") 73 | } 74 | 75 | override func assemble() { 76 | addCPU() 77 | addRam() 78 | super.assemble() 79 | } 80 | } 81 | ``` 82 | У сборщика андроида аж целых два дополнительных метода, и перегружен метод assemble. 83 | 84 | Тест здесь конечно же – элементарный 85 | ```swift 86 | let android = AndroidMaker() 87 | let iPhone = iPhoneMaker() 88 | 89 | android.makePhone() 90 | print("- - - - - - ") 91 | iPhone.makePhone() 92 | 93 | //console: 94 | Берем коробку 95 | Берем камеру 96 | Берем микрофон 97 | Добавляем вечно нехватающей оперативки 98 | Суем внутрь еще 6 процессоров 99 | Собираем все вместе 100 | - - - - - - 101 | Клеим яблоко, и пишем Разработано в Калифорнии 102 | Берем коробку 103 | Берем камеру 104 | Берем микрофон 105 | Собираем все вместе 106 | ``` 107 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Home/TileView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // TileView.swift 3 | // Starbucks 4 | // 5 | // Created by Владимир on 11.05.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | class TileView: UIView { 11 | 12 | let imageView = UIImageView() 13 | let titleLabel = UILabel() 14 | let subtitleLabel = UILabel() 15 | let ctaButton = makeGreenButton(withText: "Order") 16 | 17 | override init(frame: CGRect) { 18 | super.init(frame: frame) 19 | style() 20 | layout() 21 | } 22 | 23 | required init?(coder: NSCoder) { 24 | fatalError("init(coder:) has not been implemented") 25 | } 26 | 27 | private var shadowLayer: CAShapeLayer! 28 | private var cornerRadius: CGFloat = 6 29 | private var fillColor: UIColor = .white 30 | 31 | override func layoutSubviews() { 32 | super.layoutSubviews() 33 | addShadow() 34 | } 35 | 36 | func addShadow() { 37 | shadowLayer = CAShapeLayer() 38 | 39 | shadowLayer.path = UIBezierPath(roundedRect: bounds, cornerRadius: cornerRadius).cgPath 40 | shadowLayer.fillColor = fillColor.cgColor 41 | 42 | shadowLayer.shadowColor = UIColor.black.cgColor 43 | shadowLayer.shadowPath = shadowLayer.path 44 | shadowLayer.shadowOffset = CGSize(width: 0.0, height: 1.0) 45 | shadowLayer.shadowOpacity = 0.2 46 | shadowLayer.shadowRadius = 1 47 | 48 | layer.insertSublayer(shadowLayer, at: 0) 49 | } 50 | } 51 | 52 | extension TileView { 53 | func style() { 54 | layer.cornerRadius = cornerRadius 55 | 56 | imageView.translatesAutoresizingMaskIntoConstraints = false 57 | imageView.contentMode = .scaleAspectFit 58 | imageView.clipsToBounds = true 59 | 60 | titleLabel.translatesAutoresizingMaskIntoConstraints = false 61 | titleLabel.font = UIFont.preferredFont(forTextStyle: .title3).bold() 62 | titleLabel.textColor = .label 63 | 64 | subtitleLabel.translatesAutoresizingMaskIntoConstraints = false 65 | subtitleLabel.font = UIFont.preferredFont(forTextStyle: .footnote) 66 | subtitleLabel.numberOfLines = 0 67 | subtitleLabel.lineBreakMode = .byWordWrapping 68 | 69 | ctaButton.translatesAutoresizingMaskIntoConstraints = false 70 | } 71 | 72 | func layout() { 73 | addSubview(imageView) 74 | addSubview(titleLabel) 75 | addSubview(subtitleLabel) 76 | addSubview(ctaButton) 77 | 78 | NSLayoutConstraint.activate([ 79 | imageView.topAnchor.constraint(equalTo: topAnchor), 80 | imageView.leadingAnchor.constraint(equalTo: leadingAnchor), 81 | imageView.trailingAnchor.constraint(equalTo: trailingAnchor), 82 | 83 | titleLabel.topAnchor.constraint(equalToSystemSpacingBelow: imageView.bottomAnchor, multiplier: 2), 84 | titleLabel.leadingAnchor.constraint(equalToSystemSpacingAfter: leadingAnchor, multiplier: 2), 85 | trailingAnchor.constraint(equalToSystemSpacingAfter: titleLabel.trailingAnchor, multiplier: 2), 86 | 87 | subtitleLabel.topAnchor.constraint(equalToSystemSpacingBelow: titleLabel.bottomAnchor, multiplier: 2), 88 | subtitleLabel.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor), 89 | subtitleLabel.trailingAnchor.constraint(equalTo: titleLabel.trailingAnchor), 90 | 91 | ctaButton.topAnchor.constraint(equalToSystemSpacingBelow: subtitleLabel.bottomAnchor, multiplier: 2), 92 | ctaButton.leadingAnchor.constraint(equalTo: titleLabel.leadingAnchor), 93 | bottomAnchor.constraint(equalToSystemSpacingBelow: ctaButton.bottomAnchor, multiplier: 2), 94 | ]) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Strategy/README.md: -------------------------------------------------------------------------------- 1 | # Strategy 2 | 3 | Если Ваша девушка злая, вы скорее всего будете общаться с ней осторожно. Если на вашем проетке завал, то вероятнее всего вы не будете предлагать в команде вечерком дернуть пива или поиграть в компьютерные игры. В различных ситуациях, у нас могут быть очень разные стратегии поведения. К примеру, в приложении вы можете использовать различные алгоритмы сжатия, в зависимости от того с каким форматом картинки вы работаете, или же куда вы хотите после этого картинку деть. Вот мы и добрались до паттерна Стратегия. 4 | Также отличным примером может быть MVC паттерн – в разных случаях мы можем использовать разные контроллеры для одного и того же View (к примеру авторизированный и не авторизированный пользователь). 5 | Паттерн Стратегия определяет семейство алгоритмов, которые могут взаимозаменяться. 6 | Когда использовать паттерн: 7 | 8 | Вам необходимы различные алгоритмы 9 | Вы очень не хотите использовать кучу вложенных If-ов 10 | В различных случаях ваш класс работает по разному 11 | Давайте напишем пример – RPG игра, в которой у вас есть различные стратегии нападения Вашими персонажами:) Каждый раз когда вы делаете ход, ваши персонажи делают определенное действие. Итак, для начала управление персонажами! 12 | Создадим базовую стратегию: 13 | 14 | ```swift 15 | protocol BasicStrategy { 16 | func actionPerson1() 17 | func actionPerson2() 18 | func actionPerson3() 19 | } 20 | ``` 21 | Как видно из кода стратегии – у нас есть 3 персонажа, каждый из которых может совершать одно действие! Давайте научим персонажей нападать! 22 | ```swift 23 | class AttackStrategy: BasicStrategy { 24 | 25 | func actionPerson1() { 26 | print("Герой 1 - атакуй всех врагов") 27 | } 28 | 29 | func actionPerson2() { 30 | print("Герой 2 - атакуй всех врагов") 31 | } 32 | 33 | func actionPerson3() { 34 | print("Герой 3 - атакуй всех врагов") 35 | } 36 | } 37 | ``` 38 | При использовании такой стратегии наши персонажи нападают на все что движется! Давайте научим их защищаться: 39 | ```swift 40 | class DefenceStrategy: BasicStrategy { 41 | 42 | func actionPerson1() { 43 | print("Герой 1 - атакуй всех врагов") 44 | } 45 | 46 | func actionPerson2() { 47 | print("Герой 2 - Лечи героя 1") 48 | } 49 | 50 | func actionPerson3() { 51 | print("Герой 3 - защищай героя 2") 52 | } 53 | } 54 | ``` 55 | Во время защитной стратегии, наши персонажи действуют по-другому – кто атакует, кто лечит, а некоторый даже защищают:) Ну, теперь как-то надо это все использовать. Давайте создадим нашего игрока: 56 | ```swift 57 | class Player { 58 | var strategy: BasicStrategy 59 | 60 | func makeAction() { 61 | self.strategy.actionPerson1() 62 | self.strategy.actionPerson2() 63 | self.strategy.actionPerson3() 64 | } 65 | 66 | func changeStrategy(aStrategy: BasicStrategy) { 67 | self.strategy = aStrategy 68 | } 69 | 70 | init(strategy: BasicStrategy) { 71 | self.strategy = strategy 72 | } 73 | } 74 | ``` 75 | Наш игрок может только менять стратегию и действовать в зависимости от этой стратегии. Код для тестирования: 76 | ```swift 77 | let a = AttackStrategy() 78 | let d = DefenceStrategy() 79 | 80 | let p = Player(strategy: a) 81 | p.makeAction() 82 | print("- - - - - - -") 83 | p.changeStrategy(d) 84 | p.makeAction() 85 | 86 | //console: 87 | Герой 1 - атакуй всех врагов 88 | Герой 2 - атакуй всех врагов 89 | Герой 3 - атакуй всех врагов 90 | - - - - - - - 91 | Герой 1 - атакуй всех врагов 92 | Герой 2 - Лечи героя 1 93 | Герой 3 - защищай героя 2 94 | ``` 95 | -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Mediator/README.md: -------------------------------------------------------------------------------- 1 | # Mediator 2 | 3 | Медиатор – паттерн который определяет внутри себя объект, в котором реализуется взаимодействие между некоторым количеством объектов. При этом эти объекты, могут даже не знать про существования друг друга, потому взаимодействий реализованых в медиаторе может быть огромное количество. 4 | 5 | Когда стоит использовать: 6 | 7 | Когда у вас есть некоторое количество объектов, и очень тяжело реализовать взаимодействие между ними. Яркий пример – умный дом. Онозначно есть несколько датчиков, и несколько устройств. К примеру, датчик температуры следит за тем какая на даный момент температура, а кондционер умеет охлаждать воздух. При чем кондиционер, не обязательно знает про существование датчика температуры. Есть центральный компьютер, который получает сигналы от каждого из устройств и понимает, что делать в том или ином случает. 8 | Тяжело переиспользовать объект, так как он взаимодействует и коммуницирует с огромным количеством других объектов. 9 | Логика взаимодействия должна легко настраиваться и расширяться. 10 | Собственно, пример медиатора даже писать безсмысленно, потому как это любой контроллер который мы используем во время нашей разработки. Посудите сами – на view есть очень много контролов, и все правила взаимодействия мы прописываем в контроллере. Элементарно. 11 | 12 | И все же пример не будет лишним Давайте все же создадим пример который показывает создание аля умного дома. 13 | 14 | Пускай у нас есть оборудование которое может взаимодействоать с нашим умным домом: 15 | ```swift 16 | class SmartHousePart { 17 | private weak var processor: CentralProcessor 18 | 19 | init(withCore processor: CentralProcessor) { 20 | self .processor = processor 21 | } 22 | 23 | func numberChanged() { 24 | processor.valueChanged(self) 25 | } 26 | } 27 | ``` 28 | Теперь, создадим сердце нашего умного дома: 29 | ```swift 30 | class CentralProcessor { 31 | var thermometer: Thermometer? 32 | var condSystem: ConditioningSystem? 33 | 34 | func valueChanged(aPart: SmartHousePart) { 35 | print("значение изменилось! нужно что-то сделать") 36 | 37 | // Определяем, что изменилась именно темперетура 38 | if aPart is Thermometer { 39 | print("Да - изменилась именно температура, включим кондер...") 40 | condSystem?.startCondition() 41 | } 42 | 43 | } 44 | } 45 | ``` 46 | В классе `CentrallProcessor` в методе `valueChanged` мы определяем с какой деталью и что произошло, чтобы адекватно среагировать. В нашем примере – изменение температуры приводт к тому что мы включаем кондиционер. 47 | 48 | А вот, и код термометра и кондиционера: 49 | ```swift 50 | class Thermometer: SmartHousePart { 51 | var temperature: Int? 52 | 53 | func temperatureChanged(temperature: Int) { 54 | self.temperature = temperature 55 | self.numberChanged() 56 | } 57 | } 58 | 59 | class ConditioningSystem: SmartHousePart { 60 | func startCondition() { 61 | print("Охлаждаю") 62 | } 63 | } 64 | ``` 65 | Как видим в результате у нас есть два объекта, которые друг про друга не в курсе, и все таки они взаимодействуют друг с другом посредством нашего медиатора `CentrallProcessor`. Запустим тестирование. 66 | ```swift 67 | let processor = CentralProcessor() 68 | 69 | let therm = Thermometer(withCore: processor) 70 | let cond = ConditioningSystem(withCore: processor) 71 | 72 | processor.condSystem = cond 73 | processor.thermometer = therm 74 | 75 | therm.temperatureChanged(45) 76 | 77 | //console: 78 | значение изменилось! нужно что-то сделать 79 | Да - изменилась именно температура, включим кондер... 80 | Охлаждаю 81 | ``` 82 | 83 | 84 | -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Factory method/README.md: -------------------------------------------------------------------------------- 1 | # Factory Method 2 | 3 | Еще один порождающий паттерн, довольно прост и популярен.Паттерн позволяет переложить создание специфических объектов, на наследников родительского класса, потому можно манипулировать объектами на более высоком уровне, не заморачиваясь объект какого класса будет создан. Частенько этот паттерн называют виртуальный конструктор, что по моему мнению более выражает его предназначение. 4 | 5 | Когда использовать: 6 | 7 | 1. Мы не до конца уверены объект какого типа нам необходим. 8 | 2. Мы хотим чтобы не родительский объект решал какой тип создавать, а его наследники. 9 | 10 | Почему хорошо использовать: 11 | 12 | Объекты созданные фабричным методом – схожи, потому как у них один и тот же родительский объект. Потому, если локализировать создание таких объектов, то можно добавлять новые типы, не меняя при это код который использует фабричный метод. 13 | 14 | ## Пример: 15 | 16 | Давайте представим, что мы такой неправильный магазин в котором тип товара оценивается по цене:) На данный момент товар есть 2х типов – Игрушки и Машины. 17 | 18 | В чеке мы получаем только цены, и нам надо сохранить объекты которые куплены. 19 | 20 | Для начала создадим клас Product. Его реализация нас особо не интересует, хотя он может содержать в себе общие для разных типов товаров методы (сделано для примера, мы их особо не используем) 21 | 22 | ```swift 23 | class Product { 24 | let price: Int 25 | let name: String 26 | 27 | init(price: Int, name: String) { 28 | self.price = price 29 | self.name = name 30 | } 31 | 32 | func getTotalPrice(sum: Int) -> Int { 33 | return self.price + sum 34 | } 35 | 36 | func saveObject() { 37 | print(" Saving product \(self.name) to database") 38 | } 39 | } 40 | ``` 41 | 42 | Создадим два наследника 43 | 44 | ```swift 45 | class Toy: Product { 46 | override func saveObject() { 47 | print(" Saving product \(self.name) into TOYS database") 48 | } 49 | } 50 | 51 | class Car: Product { 52 | override func saveObject() { 53 | print(" Saving product \(self.name) into CARS database") 54 | } 55 | } 56 | ``` 57 | Ну теперь мы практически в плотную подошли к нашему паттерну Factory. Собственно, теперь надо создать метод, который будет по цене определять что же за продукт у нас в чеке, и создавать объект необходимого типа. 58 | ```swift 59 | class ProductGenerator { 60 | 61 | func getProduct(price: Int) -> Product? { 62 | if price > 0 && price < 100 { 63 | let product = Toy(price: price, name: "Transformer") 64 | return product 65 | } 66 | if price > 100 { 67 | let product = Car(price: price, name: "Audi") 68 | return product 69 | } 70 | return nil 71 | } 72 | } 73 | ``` 74 | Для проверки работы будем использовать метод, который использует ProductGenerator и выведем в лог продукты, которые создала наша фабрика: 75 | ```swift 76 | func saveExpenses(aPrice: Int) { 77 | let pg = ProductGenerator() 78 | let expense = pg.getProduct(aPrice) 79 | 80 | expense?.saveObject() 81 | } 82 | 83 | 84 | saveExpenses(50) 85 | saveExpenses(80) 86 | saveExpenses(90) 87 | saveExpenses(150) 88 | saveExpenses(560) 89 | saveExpenses(5) 90 | saveExpenses(105) 91 | ``` 92 | 93 | Лог в консоле: 94 | 95 | ```swift 96 | Saving product Transformer into TOYS database 97 | Saving product Transformer into TOYS database 98 | Saving product Transformer into TOYS database 99 | Saving product Audi into CARS database 100 | Saving product Audi into CARS database 101 | Saving product Transformer into TOYS database 102 | Saving product Audi into CARS database 103 | ``` 104 | Итак, шаблон проектирования Фабрика, или Factory используется для замены конструктора класса, абстрагируя процесс генерации объекта так, чтобы тип экземпляра мог быть определен во время выполнения программы. 105 | 106 | 107 | -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Composite/README.md: -------------------------------------------------------------------------------- 1 | # Composite 2 | 3 | Вы задумывались как много в нашей жизни древовидных структур? Начиная собственно с самих деревьев и заканчивая структурами компаний. Да ладно, даже, компаний – целые страны используют древовидные структуры чтобы построить власть. 4 | 5 | Во главе компании или страны частенько стоит один человек, у него есть с 10 помошников. У них тоже есть с десяток помошников, и так далее… Если нарисовать их отношения на листе бумаги – увидим дерево! 6 | Очень часто, и мы используем такие типы даных, которые лучше всего храняться в древовидной структуре. Возьмите к примеру стандартный UI: в начале у нас есть View, в нем находяться Subview, в которых могут быть или другие View, или все такие компоненты. Та же самая структура:) 7 | 8 | Именно для хранения таких типов данных, а вернее их организации, используется паттерн – Composite или Компоновщик. 9 | 10 | ### **Когда использовать такой паттерн?** 11 | 12 | Собственно когда вы работаете с древовидными типами данных, или хотите отобразить иерархию даных таким образом. 13 | Давайте разберем более детально структуру: 14 | В начале всегда есть контейнер в котором находятся все остальные объекты. Контейнер может хранить как другие контейнеры – ветки нашего дерева, так и объекты которые контейнерами не являюстся – листья нашего дерева. Не сложно представить, что контейнеры второго уровня могут хранить как другие контейнеры, так и листья. 15 | Давайте пример! 16 | Начнем с создания протокола для наших объектов: 17 | 18 | ```swift 19 | protocol CompositeObjectProtocol { 20 | func getData() -> String 21 | func addComponent(aComponent: CompositeObjectProtocol) 22 | } 23 | 24 | class Leaf: CompositeObjectProtocol { 25 | var leafValue: String = "" 26 | 27 | func getData() -> String { 28 | return "Leaf value: \(leafValue)" 29 | } 30 | 31 | func addComponent(aComponent: CompositeObjectProtocol) { 32 | print("Это листок дерева. К нему добавить ветку не могу") 33 | } 34 | } 35 | ``` 36 | Как видим наш объект не может добавлять себе детей (ну он же не контейнер:) ), и может возвращать свое значение с помощью метода getData. 37 | 38 | Теперь нам очень необходим контейнер: 39 | ```swift 40 | class Container: CompositeObjectProtocol { 41 | var components = [CompositeObjectProtocol]() 42 | 43 | func addComponent(aComponent: CompositeObjectProtocol) { 44 | self.components.append(aComponent) 45 | } 46 | 47 | func getData() -> String { 48 | var valueToReturn = "\n\n" 49 | 50 | for obj in components { 51 | valueToReturn.appendContentsOf(obj.getData()) 52 | } 53 | 54 | valueToReturn.appendContentsOf("\n") 55 | 56 | return valueToReturn 57 | } 58 | } 59 | ``` 60 | Как видим, наш контейнер может добавлять в себя детей, которые могут быть как типа Container так и типа Leaf. Метод getData бегает по всем объектам в массиве components, и вызывает тот же самый метод в детях. Вот собственно и все. 61 | Теперь, конечно же пример: 62 | ```swift 63 | let rootContainer = Container() 64 | let leaf1 = Leaf() 65 | leaf1.leafValue = "level1 value" 66 | rootContainer.addComponent(leaf1) 67 | 68 | let firstLevelContainer1 = Container() 69 | let leaf2 = Leaf() 70 | leaf2.leafValue = "level2 value1" 71 | firstLevelContainer1.addComponent(leaf2) 72 | rootContainer.addComponent(firstLevelContainer1) 73 | 74 | let firstLevelContainer2 = Container() 75 | let leaf3 = Leaf() 76 | leaf3.leafValue = "level2 value2" 77 | firstLevelContainer2.addComponent(leaf3) 78 | rootContainer.addComponent(firstLevelContainer2) 79 | 80 | print(rootContainer.getData()) 81 | 82 | //console: 83 | 84 | Leaf value: level1 value 85 | 86 | Leaf value: level2 value1 87 | 88 | 89 | Leaf value: level2 value2 90 | 91 | 92 | ``` 93 | В корневом контейнере содержится один лист и две ветки, которые содержат по одному листу. Именно это и отражает наш лог. 94 | -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Facade/README.md: -------------------------------------------------------------------------------- 1 | # Facade 2 | 3 | Шаблон проектирования или паттерн (англ. design pattern) в разработке программного обеспечения — повторимая архитектурная конструкция, представляющая собой решение проблемы проектирования в рамках некоторого часто возникающего контекста. 4 | 5 | Многие сложные системы состоят из огромной кучи компонент. Так же и в жизни, очень часто для совершения одного основного действия, мы должны выполнить много маленьких. 6 | 7 | К примеру, чтобы пойти в кино нам надо: 8 | 9 | Посмотреть расписание фильмов, выбрать фильм, посмотреть когда есть сеансы, посмотреть когда у нас есть время. 10 | 11 | Необходимо купить билет, для этого ввести номер карточки, секретный код, дождаться снятия денег, распечатать билет. 12 | Приехать в кинотеатр, припарковать машину, купить попкорн, найти места, смотреть. 13 | 14 | И все это для того, чтобы просто посмотреть фильм, который нам, очень вероятно, не понравится. 15 | 16 | Или же возьмем пример Amazon – покупка с одного клика – как много систем задействовано в операции покупки? И проверка Вашей карточки, и проверка Вашего адреса, проверка товара на складе, проверка или возможна доставка даного товара в даную точку мира… В результате очень много действий которые происходят всего по одному клику. 17 | 18 | Для таких вот процесов был изобретен паттерн – **Фасад** ( **Facade** ) который предоставляет унифицированный интерфейса к большому количеству интерфейсов системы, в следствии чего систему стает гораздо проще в использовании. 19 | 20 | Давайте, попробуем создать систему которая нас переносит в другую точку мира с одного нажатия кнопки! Сначала нам нужна система, которая проложит путь от нашего места перебывания в место назначения: 21 | 22 | ```swift 23 | class Pathfinder { 24 | func findCurrentLocation() { 25 | print("Ищем местоположение... О! Вот ты где!") 26 | } 27 | 28 | func findLocationToTravel(location: String) { 29 | print("Итак, ты хочешь переместиться в \(location)") 30 | } 31 | func maeARoute() { 32 | print("Отлично! Для путешествия будем заглядывать на Яндекс карты...") 33 | } 34 | } 35 | ``` 36 | Так же нам необходима сама система заказа транспорта и собственно путешествия: 37 | ```swift 38 | class TravelEngene { 39 | func findTransport() { 40 | print("Для путешествия нужны ездовые собаки") 41 | } 42 | 43 | func orderTransport() { 44 | print("Дайте вот тех, которые в упряжке...") 45 | } 46 | func travel() { 47 | print("Ю-ху! В путь!") 48 | } 49 | } 50 | ``` 51 | Ну и какие же путешествия без билетика: 52 | ```swift 53 | class TicketPrintingSystem { 54 | func createTicket() { 55 | print("Ожидание ответа от базы...") 56 | } 57 | 58 | func printTicket() { 59 | print("Ответ получен! На собаках? Не забудь покормить их...") 60 | } 61 | } 62 | ``` 63 | А теперь, давайте создадим единый доступ ко всем этим системам: 64 | ```swift 65 | class TravelSystemFacade { 66 | func travelTo(aLocation: String) { 67 | 68 | let pf = Pathfinder() 69 | let te = TravelEngene() 70 | let tp = TicketPrintingSystem() 71 | 72 | pf.findCurrentLocation() 73 | pf.findLocationToTravel(aLocation) 74 | pf.maeARoute() 75 | 76 | te.findTransport() 77 | te.orderTransport() 78 | tp.createTicket() 79 | tp.printTicket() 80 | te.travel() 81 | } 82 | } 83 | ``` 84 | **Фасад** знает все про все системы, потому в одном методе он берет и транспортирует нас куда следует. Код теста элементарен: 85 | ```swift 86 | let facade = TravelSystemFacade() 87 | facade.travelTo("Лондон") 88 | 89 | //console: 90 | Ищем местоположение... О! Вот ты где! 91 | Итак, ты хочешь переместиться в Лондон 92 | Отлично! Для путешествия будем заглядывать на Яндекс карты... 93 | Для путешествия нужны ездовые собаки 94 | Дайте вот тех, которые в упряжке... 95 | Ожидание ответа от базы... 96 | Ответ получен! На собаках? Не забудь покормить их... 97 | Ю-ху! В путь! 98 | ``` 99 | 100 | 101 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // Starbucks 4 | // 5 | // Created by Владимир on 08.05.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | class StarBucksViewController: UIViewController { 11 | 12 | override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { 13 | super.init(nibName: nil, bundle: nil) 14 | commonInit() 15 | } 16 | 17 | required init?(coder: NSCoder) { 18 | fatalError("init(coder:) has not been implemented") 19 | } 20 | 21 | func commonInit() { 22 | 23 | } 24 | 25 | func setTabBarImage(imageName: String, title: String) { 26 | let configuration = UIImage.SymbolConfiguration(scale: .large) 27 | let image = UIImage(systemName: imageName, withConfiguration: configuration) 28 | tabBarItem = UITabBarItem(title: title, image: image, tag: 0) 29 | } 30 | } 31 | 32 | class ScanViewController: StarBucksViewController { 33 | override func viewDidLoad() { 34 | view.backgroundColor = .systemIndigo 35 | title = "Scan" 36 | } 37 | 38 | override func commonInit() { 39 | setTabBarImage(imageName: "qrcode", title: "Scan") 40 | } 41 | } 42 | 43 | class OrderViewController: StarBucksViewController { 44 | override func viewDidLoad() { 45 | view.backgroundColor = .systemOrange 46 | title = "Order" 47 | } 48 | 49 | override func commonInit() { 50 | setTabBarImage(imageName: "arrow.up.bin.fill", title: "Order") 51 | } 52 | } 53 | 54 | class GiftViewController: StarBucksViewController { 55 | override func viewDidLoad() { 56 | view.backgroundColor = .systemGreen 57 | title = "Gift" 58 | } 59 | 60 | override func commonInit() { 61 | setTabBarImage(imageName: "gift.fill", title: "Gift") 62 | } 63 | } 64 | 65 | class StoreViewController: StarBucksViewController { 66 | override func viewDidLoad() { 67 | view.backgroundColor = .systemIndigo 68 | title = "Stores" 69 | } 70 | 71 | override func commonInit() { 72 | setTabBarImage(imageName: "location.fill", title: "Stores") 73 | } 74 | } 75 | 76 | @main 77 | class AppDelegate: UIResponder, UIApplicationDelegate { 78 | 79 | var window: UIWindow? 80 | 81 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { 82 | 83 | window = UIWindow(frame: UIScreen.main.bounds) 84 | window?.makeKeyAndVisible() 85 | window?.backgroundColor = .systemBackground 86 | 87 | let homeVC = HomeViewController() 88 | let scanVC = ScanViewController() 89 | let orderVC = OrderViewController() 90 | let giftVC = GiftViewController() 91 | let storeVC = StoreViewController() 92 | 93 | // comment navigation controller 94 | // let homeNC = UINavigationController(rootViewController: homeVC) 95 | let scanNC = UINavigationController(rootViewController: scanVC) 96 | let orderNC = UINavigationController(rootViewController: orderVC) 97 | let giftNC = UINavigationController(rootViewController: giftVC) 98 | let storeNC = UINavigationController(rootViewController: storeVC) 99 | 100 | 101 | let tabBarController = UITabBarController() 102 | // tabBarController.viewControllers = [homeNC, scanNC, orderNC, giftNC, storeNC] 103 | tabBarController.viewControllers = [homeVC, scanNC, orderNC, giftNC, storeNC] 104 | window?.rootViewController = tabBarController 105 | 106 | tabBarController.tabBar.tintColor = .lightGreen 107 | tabBarController.tabBar.isTranslucent = false 108 | 109 | return true 110 | } 111 | // navigation controller 112 | // func makeNavigationController(rootViewController: UIViewController) -> UINavigationController { 113 | // let navigationController = UINavigationController(rootViewController: rootViewController) 114 | // navigationController.navigationBar.prefersLargeTitles = true 115 | // 116 | // let attrs = [ 117 | // NSAttributedString.Key.foregroundColor: UIColor.label, 118 | // NSAttributedString.Key.font: UIFont.preferredFont(forTextStyle: .title1).bold() 119 | // ] 120 | // 121 | // navigationController.navigationBar.largeTitleTextAttributes = attrs 122 | // 123 | // return navigationController 124 | // } 125 | } 126 | 127 | -------------------------------------------------------------------------------- /Алгоритмы/Arcade/Arcade.swift: -------------------------------------------------------------------------------- 1 | 2 | import Foundation 3 | import UIKit 4 | 5 | class Node { 6 | var data: Int 7 | var next: Node? 8 | 9 | init(_ data: Int, _ next: Node? = nil) { 10 | self.data = data 11 | self.next = next 12 | } 13 | } 14 | func length(_ head: Node?) -> Int { 15 | if head == nil { 16 | return 0 17 | } 18 | 19 | var len = 0 20 | var current = head 21 | while current != nil { 22 | len += 1 23 | current = current?.next 24 | } 25 | return len 26 | } 27 | func printLinkedList(_ head: Node?) { 28 | if head == nil { return } 29 | 30 | var result = [Int]() 31 | var node = head 32 | result.append(node!.data) 33 | 34 | while node?.next != nil { 35 | result.append(node!.next!.data) 36 | node = node?.next 37 | } 38 | 39 | print(result) 40 | } 41 | // Пройти по всем элементам A проверяя элементы B 42 | func findMergeBrute(headA: Node?, headB: Node?) -> Int? { // O(m*n) 43 | let m = length(headA) // O(m) 44 | let n = length(headB) // O(n) 45 | 46 | var currentA = headA 47 | // Один луп вложен в другой! 48 | for _ in 0...m-1 { // O(m) 49 | var currentB = headB 50 | for _ in 0...n-1 { // O(n) 51 | let A = currentA?.data 52 | let B = currentB?.data 53 | print("A: \(A ?? 0) B: \(B ?? 0)") 54 | if A == B { 55 | return currentA?.data 56 | } 57 | currentB = currentB?.next 58 | } 59 | currentA = currentA?.next 60 | } 61 | return nil 62 | } 63 | // Меняем время на память 64 | func findMergeSpaceTime(headA: Node?, headB: Node?) -> Int? { // O(2m + 2n) 65 | 66 | let m = length(headA) // O(m) 67 | let n = length(headB) // O(n) 68 | var dict = [Int?: Bool]() 69 | var currentB = headB 70 | for _ in 0...n-1 { // O(n) 71 | let B = currentB?.data 72 | dict[B] = true 73 | currentB = currentB?.next 74 | } 75 | 76 | var currentA = headA 77 | for _ in 0...m-1 { // O(m) 78 | let A = currentA?.data 79 | if dict[A] == true { 80 | return A 81 | } 82 | currentA = currentA?.next 83 | } 84 | return nil 85 | } 86 | // Инсайт: Если мы сможем выстроить массивы в ряд, мы сможем пройтись по ним один раз 87 | func findMergeInsight(headA: Node?, headB: Node?) -> Int? { // O(n + m) 88 | // Найти какой длинее 89 | // Поменять местами если надо 90 | 91 | // Посчитать d 92 | let m = length(headA) // O(m) 93 | let n = length(headB) // O(n) 94 | var currentA = headA 95 | var currentB = headB 96 | 97 | if n > m { 98 | let temp = currentA 99 | currentA = currentB 100 | currentB = temp 101 | } 102 | 103 | let d = abs(m - n) 104 | for _ in 1...d { // O(n) 105 | currentA = currentA?.next 106 | } 107 | 108 | for _ in 0...n-1 { // O(n) 109 | print(4) 110 | let A = currentA?.data 111 | let B = currentB?.data 112 | if A == B { 113 | return A 114 | } 115 | currentA = currentA?.next 116 | currentB = currentB?.next 117 | } 118 | return nil 119 | } 120 | // 1 2 3 4 5 6 121 | let node6 = Node(6) 122 | let node5 = Node(5, node6) 123 | let node4 = Node(4, node5) 124 | let node3 = Node(3, node4) 125 | let node2 = Node(2, node3) 126 | let node1 = Node(1, node2) 127 | // 10 11 12 13 4 5 6 128 | let node11 = Node(11, node4) 129 | let node10 = Node(10, node11) 130 | printLinkedList(node1) 131 | printLinkedList(node10) 132 | //findMergeBrute(headA: node1, headB: node10) 133 | //findMergeSpaceTime(headA: node1, headB: node10) 134 | findMergeInsight(headA: node1, headB: node10) 135 | 136 | // Инсайт: Простой 137 | func findMergeInsight(headA: Node?, headB: Node?) -> Int? { // O(n) 138 | // Посчитать какой длинее 139 | // поменять если надо местами 140 | // Посчитать d 141 | 142 | let m = length(headA) // O(n) 143 | let n = length(headB) // O(n) 144 | let d = m - n 145 | var currentA = headA 146 | for _ in 1...d { // O(n) 147 | currentA = currentA?.next 148 | } 149 | 150 | var currentB = headB 151 | for _ in 0...n-1 { // O(n) 152 | let A = currentA?.data 153 | let B = currentB?.data 154 | if A == B { 155 | return A 156 | } 157 | currentA = currentA?.next 158 | currentB = currentB?.next 159 | } 160 | return nil 161 | } 162 | -------------------------------------------------------------------------------- /База iOS/CoreData/README.md: -------------------------------------------------------------------------------- 1 | # CoreData 2 | 3 | ## Example 4 | 5 | ```swift 6 | 7 | import CoreData 8 | 9 | struct CoreDataManager { 10 | 11 | static let shared = CoreDataManager() 12 | 13 | let persistentContainer: NSPersistentContainer = { 14 | 15 | let container = NSPersistentContainer(name: "MyData") 16 | container.loadPersistentStores { (storeDescription, error) in 17 | if let error = error { 18 | fatalError("Loading of store failed \(error)") 19 | } 20 | } 21 | 22 | return container 23 | }() 24 | 25 | func createEmployee(name: String) -> Employee? { 26 | let context = persistentContainer.viewContext 27 | let employee = NSEntityDescription.insertNewObject(forEntityName: "Employee", into: context) as! Employee 28 | 29 | employee.name = name 30 | 31 | do { 32 | try context.save() 33 | return employee 34 | } catch let createError { 35 | print("Failed to create: \(createError)") 36 | } 37 | 38 | return nil 39 | } 40 | 41 | func fetchEmployees() -> [Employee]? { 42 | let context = persistentContainer.viewContext 43 | 44 | let fetchRequest = NSFetchRequest(entityName: "Employee") 45 | 46 | do { 47 | let employees = try context.fetch(fetchRequest) 48 | return employees 49 | } catch let fetchError { 50 | print("Failed to fetch companies: \(fetchError)") 51 | } 52 | 53 | return nil 54 | } 55 | 56 | func fetchEmployee(withName name: String) -> Employee? { 57 | let context = persistentContainer.viewContext 58 | 59 | let fetchRequest = NSFetchRequest(entityName: "Employee") 60 | fetchRequest.fetchLimit = 1 61 | fetchRequest.predicate = NSPredicate(format: "name == %@", name) 62 | 63 | do { 64 | let employees = try context.fetch(fetchRequest) 65 | return employees.first 66 | } catch let fetchError { 67 | print("Failed to fetch: \(fetchError)") 68 | } 69 | 70 | return nil 71 | } 72 | 73 | func updateEmployee(employee: Employee) { 74 | let context = persistentContainer.viewContext 75 | 76 | employee.name = "Peter" 77 | 78 | do { 79 | try context.save() 80 | } catch let createError { 81 | print("Failed to update: \(createError)") 82 | } 83 | } 84 | 85 | func deleteEmployee(employee: Employee) { 86 | let context = persistentContainer.viewContext 87 | context.delete(employee) 88 | 89 | do { 90 | try context.save() 91 | } catch let saveError { 92 | print("Failed to delete: \(saveError)") 93 | } 94 | } 95 | 96 | } 97 | ``` 98 | 99 | ```swift 100 | import UIKit 101 | 102 | class ViewController: UIViewController { 103 | 104 | override func viewDidLoad() { 105 | super.viewDidLoad() 106 | 107 | RunCoreData() 108 | } 109 | 110 | func RunCoreData() { 111 | // Create 112 | guard let newEmployee = CoreDataManager.shared.createEmployee(name: "Jon") else { return } 113 | 114 | // Read 115 | guard let employee = CoreDataManager.shared.fetchEmployee(withName: "Jon") else { return } 116 | guard let employees = CoreDataManager.shared.fetchEmployees() else { return } 117 | 118 | // Update 119 | CoreDataManager.shared.updateEmployee(employee: employee) 120 | guard let updatedEmployee = CoreDataManager.shared.fetchEmployee(withName: "Jon") else { return } 121 | 122 | // Delete 123 | CoreDataManager.shared.deleteEmployee(employee: updatedEmployee) 124 | } 125 | } 126 | ``` 127 | 128 | ### Как добавить CoreData в проект 129 | 130 | - Go new DataModel > MyData.xcdatamodeld 131 | - Click Add Entity (Employee) 132 | - Give it a name 133 | - Add your attributes 134 | - Make non-optional (RHS - but not Swift Optional) 135 | - Build / Clean / Restart Xcode 136 | - You can now access (Employee) entity in your viewController. 137 | 138 | Note 139 | - All attributes in CoreData are Optional 140 | 141 | 142 | ### Checklist 143 | 144 | - Relationship directions 145 | - Cascading deletes (top down but not bottom up) 146 | 147 | ### Links that help 148 | 149 | - [CoreData Attributes](https://developer.apple.com/documentation/coredata/modeling_data/configuring_attributes?language=objc) 150 | - [Live Cycle Managed Object](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/LifeofaManagedObject.html) 151 | - [Parsing JSON background thread](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/CoreData/Concurrency.html#//apple_ref/doc/uid/TP40001075-CH24-SW1) 152 | -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Chain of responsibility/README.md: -------------------------------------------------------------------------------- 1 | # Chain of responsibility 2 | 3 | 4 | Представьте себе очередь людей которые пришли за посылками. Выдающий посылки человек, дает первую посылку первому в очереди человеку, он смотрит на имя-фамилию на корбке, видит что посылка не для него, и передает посылку дальше. Второй человек делает собственно тоже самое, и так пока не найдется получатель. 5 | 6 | Цепочка ответственности (chain of responsibility) – позволяет вам передавать объект по цепочке объектов-обработчиков, пока не будет найден необходимый объект обработчик. 7 | 8 | Когда использовать этот паттерн: 9 | 10 | У вас более чем один объект — обработчик. 11 | У вас есть несколько объектов обработчика, при этом вы не хотите специфицировать который объект должен обрабатывать в даный момент времени. 12 | Как всегда – пример: 13 | 14 | Представим что у нас есть конвеер, который обрабатывает различные предметы которые на нем: игрушки, электронику и другие. 15 | Для начала создадим классы объектов которые могут быть обработаны нашими обработчиками: 16 | 17 | ```swift 18 | class BasicItem { 19 | } 20 | 21 | class Toy: BasicItem { 22 | } 23 | 24 | class Electronics :BasicItem { 25 | } 26 | 27 | class Trash: BasicItem { 28 | } 29 | ``` 30 | Теперь создадим обработчики: 31 | 32 | ```swift 33 | protocol BasicHandler { 34 | var nextHandler: BasicHandler? {get set} 35 | func handleItem(item: BasicItem) 36 | } 37 | ``` 38 | Наш базовый обработчик умеет обрабатывать объекты типа BasicItem. И самое важное – он может иметь ссылку на следующий обработчик (как люди в нашей очереди, которые передают посылку). 39 | 40 | Давайте создадим код обработчика игрушки: 41 | ```swift 42 | class ToysHandler: BasicHandler { 43 | 44 | var nextHandler: BasicHandler? 45 | 46 | required init(aHandler: BasicHandler) { 47 | self.nextHandler = aHandler 48 | } 49 | 50 | func handleItem(item: BasicItem) { 51 | if item is Toy { 52 | print("Нашли игрушку. Обрабатываем") 53 | } else { 54 | print("Это не игрушка, передаем на обработку следующему") 55 | 56 | self.nextHandler!.handleItem(item) 57 | } 58 | } 59 | } 60 | ``` 61 | Если обработчик получает объект класса Toy – то он его обрабатывает, если нет – то обработчик передает объект следующему обработчику. По аналогии создадим два следующих обработчика: для электроники, и мусора: 62 | ```swift 63 | class ElectronicHandler: BasicHandler { 64 | 65 | var nextHandler: BasicHandler? 66 | 67 | required init(aHandler: BasicHandler) { 68 | self.nextHandler = aHandler 69 | } 70 | 71 | func handleItem(item: BasicItem) { 72 | if item is Electronics { 73 | print("Нашли электонику. Обрабатываем") 74 | } else { 75 | print("Это не электроника, передаем на обработку следующему") 76 | self.nextHandler!.handleItem(item) 77 | } 78 | } 79 | } 80 | 81 | class OtherItemsHandler: BasicHandler { 82 | 83 | var nextHandler: BasicHandler? 84 | 85 | func handleItem(item: BasicItem) { 86 | print("Нашли неопознанный объект. Уничтожаем его") 87 | } 88 | } 89 | ``` 90 | Как видим OtherItemsHandler в случае, когда до него дошло дело – объект уничтожает, и не пробует дергать следующий обработчик (последний человек в очереди не проверяет получателя — его функция просто выбросить посылку, если она попала ему в руки). 91 | Давайте тестировать: 92 | ```swift 93 | let otherItemsHandler = OtherItemsHandler() 94 | let electronicItemsHandler = ElectronicHandler(aHandler: otherItemsHandler) 95 | let toysItemsHandler = ToysHandler(aHandler: electronicItemsHandler) 96 | 97 | let toy = Toy() 98 | let el = Electronics() 99 | let trash = Trash() 100 | 101 | toysItemsHandler.handleItem(toy) 102 | print("- - - - -") 103 | toysItemsHandler.handleItem(el) 104 | print("- - - - -") 105 | toysItemsHandler.handleItem(trash) 106 | 107 | //console: 108 | Нашли игрушку. Обрабатываем 109 | - - - - - 110 | Это не игрушка, передаем на обработку следующему 111 | Нашли электонику. Обрабатываем 112 | - - - - - 113 | Это не игрушка, передаем на обработку следующему 114 | Это не электроника, передаем на обработку следующему 115 | Нашли неопознанный объект. Уничтожаем его 116 | ``` 117 | Мы в начале создаем обработчик мусора, т.к. все предыдущие обработчики инициализируются с ссылкой на предыдущий обработчик. Таким образом все три обработчика скреплены в цепь и ссылаются один на другой, кроме последнего. Его свойство nexhtHandler = nil. Далее создаем объекты и пытаемся обработать эти различные созданные элементы 118 | -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Prototype/README.md: -------------------------------------------------------------------------------- 1 | # Prototype 2 | 3 | Прототип – один из самых простых паттернов, который позволяет нам получить точную копию необходимого объекта. Тоесть использовать как прототип для нового объекта. 4 | 5 | 6 | 7 | Когда использовать: 8 | 1. У нас есть семейство схожих объектов, разница между которыми только в состоянии их полей. 9 | 2. Чтобы создать объект вам надо пройти через огонь, воду и медные трубы. Особенно если этот объект состоит из еще одной кучи объектов, многие из которых для заполнения требуют подгрузку даных из базы, веб сервисов и тому подобных источников. Часто, легче скопировать объект и поменять несколько полей 10 | 3. Нам не важно как создается объект. 11 | 4. Нам страшно лень писать иерархию фабрик (читай дальше), которые будут инкапсулировать всю противную работу создания объекта 12 | 13 | Иными словами если для создания объекта нужно затратить много ресурсов или выполнить кучу условий и требований, а объектов нам требуется много, то проще создать один прототип, затем копировать его и заменять значения свойств на необходимые. 14 | 15 | И вот тут нужно разобрать понятия «поверхностное копирование» и «глубокое копирование». В переменной, которая содержит экземпляр класса на самом деле содержится указатель на блок памяти в куче, где расположен этот экземпляр. Поверхностное копирование – это просто создание нового указателя на те же самые байты в куче. То есть, в результате мы можем получить два объекта, которые указывают на одно и тоже значение. 16 | 17 | ## Пример кода: 18 | 19 | ```swift 20 | import Foundation 21 | 22 | class Person: NSObject { 23 | var name = "" 24 | var surname = "" 25 | } 26 | ``` 27 | 28 | А теперь создадим два объекта нашего класса, поменяем значения свойств, выведем лог и посмотрим что же получится: 29 | 30 | ```swift 31 | let firstPerson = Person() 32 | firstPerson.name = "Pavel" 33 | firstPerson.surname = "Davidoff" 34 | let secondPerson = firstPerson 35 | 36 | print("First person name: \(firstPerson.name) and surname: \(firstPerson.surname)") 37 | 38 | secondPerson.name = "Alex" 39 | secondPerson.surname = "Black" 40 | 41 | print("Second person name: \(secondPerson.name) and surname: \(secondPerson.surname)") 42 | print("First person name: \(firstPerson.name) and surname: \(firstPerson.surname)") 43 | ``` 44 | 45 | Вывод лога в консоль: 46 | 47 | ```swift 48 | First person name: Pavel and surname: Davidoff 49 | Second person name: Alex and surname: Black 50 | First person name: Alex and surname: Black 51 | ``` 52 | 53 | Думаю, понятно, что при создании второго указателя secondPerson, он сослался на тот же экземпляр что и firstPerson, и поэтому изменения свойств через один указатель повлияют и на другой. 54 | 55 | Именно для создания копии объектов в памяти следует использовать глубокое копирование, которое в Swift реализовано протоколом NSCopying, и методом этого протокола 56 | 57 | ```swift 58 | public func copyWithZone(zone: NSZone) -> AnyObject 59 | ``` 60 | 61 | Изменим реализация нашего класса, чтобы он соответствовал протоколу, и добавим инициализатор от объекта собственно типа. 62 | 63 | ```swift 64 | import Foundation 65 | 66 | class Person: NSObject, NSCopying { 67 | var name = "" 68 | var surname = "" 69 | 70 | // это чтобы реализовать NSCopyng на Swift 71 | required override init() { 72 | } 73 | 74 | required init(_ person: Person) { 75 | self.name = person.name 76 | self.surname = person.surname 77 | } 78 | 79 | func copyWithZone(zone: NSZone) -> AnyObject { 80 | return self.dynamicType.init(self) 81 | } 82 | } 83 | ``` 84 | 85 | Создаем третий и четвертый объекты, только для создания четвертого используем написанный ранее инициализатор. 86 | 87 | ```swift 88 | let thirdPerson = Person() 89 | thirdPerson.name = "Pavel" 90 | thirdPerson.surname = "Davidoff" 91 | 92 | print("Third person name: \(thirdPerson.name) and surname: \(thirdPerson.surname)") 93 | 94 | let fourthPerson = Person(thirdPerson) 95 | fourthPerson.name = "Alex" 96 | fourthPerson.surname = "Black" 97 | 98 | print("Fourth person name: \(fourthPerson.name) and surname: \(fourthPerson.surname)") 99 | print("Third person name: \(thirdPerson.name) and surname: \(thirdPerson.surname)") 100 | ``` 101 | Вполне ожидаемый лог в консоле: 102 | ```swift 103 | Third person name: Pavel and surname: Davidoff 104 | Fourth person name: Alex and surname: Black 105 | Third person name: Pavel and surname: Davidoff 106 | ``` 107 | 108 | И последнее, что нужно сказать про NSCopyng. Ведь мы нигде не использовали метод этого протокола. Это потому, что NSZone больше не используется в Swift да и в Objective-C в течение длительного времени. И передающийся в этот метод аргумент игнорируется. Этот метод существует по историческим причинам. 109 | -------------------------------------------------------------------------------- /База iOS/Animation/README.md: -------------------------------------------------------------------------------- 1 | # Анимация 2 | 3 | ## Property Animations 4 | 5 | ![](images/old-new.gif) 6 | 7 | _UIView.animate_ еще работает, но Свифт советует новый метод - Property animators. 8 | 9 | **Старый вид** 10 | 11 | ```swift 12 | UIView.animate(withDuration: 0.75) { [unowned self] in 13 | self.heightConstraint?.constant = 270 14 | self.layoutIfNeeded() 15 | } 16 | 17 | UIView.animate(withDuration: 0.25, delay: 0.5, options: [], animations: { 18 | self.starRewardsView.isHidden = false 19 | self.starRewardsView.alpha = 1 20 | }) { (finished) in 21 | 22 | } 23 | ``` 24 | 25 | **Новый** 26 | 27 | ```swift 28 | let animator1 = UIViewPropertyAnimator(duration: 0.75, curve: .easeInOut) { 29 | self.heightConstraint?.constant = 270 30 | self.layoutIfNeeded() 31 | } 32 | animator1.startAnimation() 33 | 34 | let animator2 = UIViewPropertyAnimator(duration: 0.25, curve: .easeInOut) { 35 | self.starRewardsView.isHidden = false 36 | self.starRewardsView.alpha = 1 37 | } 38 | animator2.startAnimation(afterDelay: 0.5) 39 | ``` 40 | 41 | ## Анимация высоты 42 | 43 | Чтобы анимировать вещи, вам нужно изменить константу констрейнта. В этом примере мы можем настроить высоту. Обратите внимание, что нам нужно вызвать `layoutIfNeeded()`, тогда как в _Stack View_, мы этого не делаем. 44 | 45 | ![](images/height.gif) 46 | 47 | ```swift 48 | import UIKit 49 | 50 | class ViewController: UIViewController { 51 | 52 | let redView = UIView() 53 | let blueView = UIView() 54 | let button = UIButton() 55 | 56 | var heightConstraint: NSLayoutConstraint? 57 | 58 | override func viewDidLoad() { 59 | super.viewDidLoad() 60 | style() 61 | layout() 62 | } 63 | 64 | func layout() { 65 | ... 66 | heightConstraint = redView.heightAnchor.constraint(equalToConstant: 100) 67 | ... 68 | } 69 | 70 | @objc func toggleTapped() { 71 | if heightConstraint?.constant == 0 { 72 | UIView.animate(withDuration: 0.75) { [unowned self] in 73 | self.heightConstraint?.constant = 100 74 | self.view.layoutIfNeeded() 75 | } 76 | } else { 77 | UIView.animate(withDuration: 0.75) { [unowned self] in 78 | self.heightConstraint?.constant = 0 79 | self.view.layoutIfNeeded() 80 | } 81 | } 82 | } 83 | } 84 | ``` 85 | 86 | 87 | ## Анимация внутри Stack View 88 | 89 | StackView анимирует ваше содержимое, когда вы меняете его видимость и alpha. 90 | 91 | ![](images/stackView.gif) 92 | 93 | ```swift 94 | func layout() { 95 | stackView.addArrangedSubview(label) 96 | 97 | view.addSubview(stackView) 98 | view.addSubview(button) 99 | 100 | ... 101 | } 102 | 103 | @objc func toggleTapped() { 104 | UIView.animate(withDuration: 0.75) { [unowned self] in 105 | self.label.isHidden = !self.label.isHidden 106 | self.label.alpha = self.label.isHidden ? 0 : 1 107 | } 108 | } 109 | ``` 110 | 111 | Если вы хотите сцепить или расположить анимацию в шахматном порядке, вы также можете сделать это следующим образом: 112 | 113 | ```swift 114 | private func toggleHiddenElements() { 115 | let duration1 = 0.4 116 | let duration2 = 0.2 117 | 118 | let animatables = [bullet6Label, bullet7Label, bullet8Label, bullet9Label] 119 | _ = animatables.map { $0?.alpha = 0 } 120 | 121 | let animatation1 = UIViewPropertyAnimator(duration: duration1, curve: .easeInOut) { [self] in 122 | _ = animatables.map { $0?.isHidden = !showAll } 123 | } 124 | 125 | animatation1.addCompletion { position in 126 | if position == .end { 127 | let animatation2 = UIViewPropertyAnimator(duration: duration2, curve: .easeInOut) { 128 | _ = animatables.map { $0?.alpha = 1 } 129 | } 130 | animatation2.startAnimation() 131 | } 132 | } 133 | animatation1.startAnimation() 134 | } 135 | ``` 136 | 137 | 138 | 139 | ## Анимируем с помощью alpha 140 | 141 | Вот два способа анимировать некоторые элементы управления, когда пользователь касается строки `UITableView`. 142 | 143 | ![](images/games-demo.gif) 144 | 145 | ```swift 146 | UIView.animate(withDuration: 3) { 147 | self.profileImage.image = UIImage(named: game.imageName) 148 | self.titleLabel.text = game.name 149 | self.bodyLabel.text = game.description 150 | 151 | self.profileImage.alpha = 1 152 | self.titleLabel.alpha = 1 153 | self.bodyLabel.alpha = 1 154 | 155 | self.view.layoutIfNeeded() 156 | } 157 | 158 | UIViewPropertyAnimator.runningPropertyAnimator(withDuration: 3, delay: 0, options: [], animations: { 159 | self.profileImage.image = UIImage(named: game.imageName) 160 | self.titleLabel.text = game.name 161 | self.bodyLabel.text = game.description 162 | 163 | self.profileImage.alpha = 1 164 | self.titleLabel.alpha = 1 165 | self.bodyLabel.alpha = 1 166 | }) 167 | ``` 168 | 169 | ### Полезные ссылки 170 | 171 | - [Quick Guide To Property Animators](https://useyourloaf.com/blog/quick-guide-to-property-animators/) 172 | -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Observer/README.md: -------------------------------------------------------------------------------- 1 | # Observer 2 | 3 | 4 | 5 | Что такое паттерн **Observer**? Вот вы когда нибудь подписывались на газету? Вы подписываетесь, и каждый раз когда выходит новый номер газеты вы получаете ее к своему дому. Вы никуда не ходите, просто даете информацию про себя, и организация которая выпускает газету сама знает куда и какую газету отнесту. Второе название этого паттерна – Publish – Subscriber. 6 | 7 | Как описывает этот паттерн наша любимая GoF книга – Observer определяет одно-ко-многим отношение между объектами, и если изменения происходят в объекте – все подписанные на него объекты тут же узнают про это изменение. 8 | 9 | Идея проста, объект который мы называем Subject – дает возможность другим объектам, которые реализуют интерфейс Observer, подписываться и отписываться от изменений происходящик в Subject. Когда изменение происходит – всем заинетерсованным объектам высылается сообщение, что изменение произошло. В нашем случае – Subject – это издатель газеты, Observer это мы с вами – те кто подписывается на газету, ну и собсвтенно изменение – это выход новой газеты, а оповещение – отправка газеты всем кто подписался. 10 | 11 | Когда используется паттерн: 12 | 13 | Когда Вам необходимо сообщить всем объектам подписанным на изменения, что изменение произошло, при этом вы не знаете типы этих объектов. 14 | Изменения в одном объекте, требуют чтобы состояние изменилось в других объектах, при чем количество объектов может быть разное. 15 | Реализация этого паттерна возможно двумя способами: 16 | 17 | ## Notification 18 | 19 | **Notificaiton** – механизм использования возможностей *NotificationCenter* самой операционной системы. Использование *NSNotificationCenter* позволяет объектам комуницировать, даже не зная друг про друга. Это очень удобно использовать когда у вас в паралельном потоке пришел push-notification, или же обновилась база, и вы хотите дать об этом знать активному на даный момент View. 20 | 21 | Чтобы послать такое сообщение стоит использовать конструкцию типа: 22 | 23 | ```swift 24 | let broadCastMessage = NSNotification(name: "broadCastMessage", object: nil) 25 | 26 | let notificationCenter = NSNotificationCenter.defaultCenter() 27 | 28 | notificationCenter.addObserver(self, selector: #selector(update), name: "bradCastMessage", object: nil) 29 | ``` 30 | ## Стандартный метод 31 | 32 | Стандартный метод, это реализация этого паттерна тогда, когда Subject знает про всех подписчиков, но при этом не знает их типа. Давайте начнем с того, что создадим протоколы для Subject и Observer: 33 | ```swift 34 | protocol StandartObserver: class { 35 | func valueChanged(valueName: String, newValue: String) 36 | } 37 | 38 | protocol StandartSubject: class { 39 | func addObserver(observer: StandartObserver) 40 | func removeObserver(observer: StandartObserver) 41 | func notifyObject() 42 | } 43 | ``` 44 | Теперь, давайте создадим реализацию Subject: 45 | ```swift 46 | class StandartSubjectImplementation: StandartSubject { 47 | private var valueName: String? 48 | private var newValue: String? 49 | 50 | var observerCollection = NSMutableSet() 51 | 52 | func addObserver(observer: StandartObserver) { 53 | self.observerCollection.addObject(observer) 54 | } 55 | func removeObserver(observer: StandartObserver) { 56 | self.observerCollection.removeObject(observer) 57 | } 58 | 59 | func notifyObject() { 60 | for observer in observerCollection { 61 | (observer as! StandartObserver).valueChanged(self.valueName!, newValue: self.newValue!) 62 | 63 | } 64 | } 65 | 66 | func changeValue(valueName:String, andValue newValue:String) { 67 | self.newValue = newValue 68 | self.valueName = valueName 69 | notifyObject() 70 | } 71 | } 72 | ``` 73 | Ну и куда же без обсерверов: 74 | ```swift 75 | class SomeSubscriber: StandartObserver { 76 | func valueChanged(valueName: String, newValue: String) { 77 | print("Первый обозреватель говорит: Значение \(valueName) поменялось на \(newValue)") 78 | } 79 | } 80 | 81 | class OtherSubscriber: StandartObserver { 82 | func valueChanged(valueName: String, newValue: String) { 83 | print("И второй обозреватель говорит: Значение \(valueName) поменялось на \(newValue)") 84 | } 85 | } 86 | ``` 87 | Собственно – все:) теперь демо-код: 88 | ```swift 89 | let subj = StandartSubjectImplementation() 90 | let oneSub = SomeSubscriber() 91 | let twoSub = OtherSubscriber() 92 | 93 | subj.addObserver(oneSub) 94 | subj.addObserver(twoSub) 95 | 96 | subj.changeValue("Важное значение", andValue: "09 целых и триста пятьдесять восемь тысячных") 97 | 98 | //console: 99 | Первый обозреватель говорит: Значение Важное значение поменялось на 09 целых и триста пятьдесять восемь тысячных 100 | И второй обозреватель говорит: Значение Важное значение поменялось на 09 целых и триста пятьдесять восемь тысячных 101 | ``` 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /Алгоритмы/Структура данных/Hash-Table/README.md: -------------------------------------------------------------------------------- 1 | # Hash-Table 2 | 3 | ## пример таблицы для [статьи](https://habr.com/ru/post/724376/) 4 | 5 | ```swift 6 | import Foundation 7 | 8 | /* 9 | _ _ _ _____ _ _ 10 | | || |__ _ __| |_ |_ _|_ _| |__| |___ ___ 11 | | __ / _` (_-< ' \ | |/ _` | '_ \ / -_|_-< 12 | |_||_\__,_/__/_||_| |_|\__,_|_.__/_\___/__/ 13 | */ 14 | 15 | // Strings, Integers, Floating point numbers и Booleans 16 | // все хашбл по дефолту. 17 | let stringsAreHashable = "abc".hashValue 18 | 19 | struct GridPoint { 20 | var x: Int 21 | var y: Int 22 | 23 | var hashValue: Int { 24 | 25 | return x.hashValue ^ y.hashValue &* 16777619 26 | } 27 | } 28 | 29 | let mainBase = GridPoint(x: 131, y: 541) 30 | let hashCode = mainBase.hashValue 31 | 32 | // Остаток от деления 33 | let even = 2 % 2 34 | let odd = 3 % 2 // остаток 1 35 | let initialSize = 16 36 | let index = hashCode % initialSize // гарантируем что поместится 37 | let indexPositive = abs(index) 38 | 39 | 40 | // Связный список(Linked List) 41 | class HashEntry { 42 | var key: String 43 | var value: String 44 | var next: HashEntry? 45 | 46 | init(_ key: String, _ value: String) { 47 | self.key = key 48 | self.value = value 49 | } 50 | } 51 | 52 | class HashTable { 53 | private static let initialSize = 256 54 | private var entries = Array(repeating: nil, count: initialSize) 55 | 56 | func put(_ key: String, _ value: String) { 57 | // Берем по индексу 58 | let index = getIndex(key) 59 | 60 | // Create entry 61 | let entry = HashEntry(key, value) 62 | 63 | // If entry is not already there - store it 64 | if entries[index] == nil { 65 | entries[index] = entry 66 | } 67 | // else handle collision by appending to our linked list 68 | else { 69 | var collisions = entries[index] 70 | 71 | // Walk to the end 72 | while collisions?.next != nil { 73 | collisions = collisions?.next 74 | } 75 | 76 | // Add collision there 77 | collisions?.next = entry 78 | } 79 | } 80 | 81 | func get(_ key: String) -> String? { 82 | // Get the index 83 | let index = getIndex(key) 84 | 85 | // Get current list of entries for this index 86 | let possibleCollisions = entries[index] 87 | 88 | // Walk our linked list looking for a possible match on the key (that will be unique) 89 | var currentEntry = possibleCollisions 90 | while currentEntry != nil { 91 | if currentEntry?.key == key { 92 | return currentEntry?.value 93 | } 94 | currentEntry = currentEntry?.next 95 | } 96 | 97 | return nil 98 | } 99 | 100 | private func getIndex(_ key: String) -> Int { 101 | // Get the key's hash code 102 | let hashCode = abs(key.hashValue) 103 | 104 | // Normalize it into an acceptable index 105 | let index = hashCode % HashTable.initialSize 106 | print("\(key) \(hashCode) \(index)") 107 | 108 | // Forced collision for demonstration purposes 109 | if key == "John Smith" || key == "Sandra Dee" { 110 | return 152 111 | } 112 | 113 | return index 114 | } 115 | 116 | func prettyPrint() { 117 | for entry in entries { 118 | if entry == nil { 119 | continue 120 | } 121 | if entry?.next == nil { 122 | // nothing else there 123 | print("key: \(String(describing: entry?.key)) value: \(String(describing: entry?.value))") 124 | } else { 125 | // collisions 126 | var currentEntry = entry 127 | while currentEntry?.next != nil { 128 | print("💥 key: \(String(describing: currentEntry?.key)) value: \(String(describing: currentEntry?.value))") 129 | currentEntry = currentEntry?.next 130 | } 131 | print("💥 key: \(String(describing: currentEntry?.key)) value: \(String(describing: currentEntry?.value))") 132 | } 133 | } 134 | } 135 | 136 | subscript(key: String) -> String? { 137 | get { 138 | get(key) 139 | } 140 | set(newValue) { 141 | guard let value = newValue else { return } 142 | put(key, value) 143 | } 144 | } 145 | } 146 | 147 | let hashTable = HashTable() 148 | hashTable.put("John Smith", "521-1234") 149 | hashTable.put("Lisa Smith", "521-8976") 150 | hashTable.put("Sam Doe", "521-5030") 151 | hashTable.put("Sandra Dee", "521-9655") 152 | hashTable.put("Ted Baker", "418-4165") 153 | 154 | hashTable.prettyPrint() 155 | 156 | hashTable.get("John Smith") 157 | hashTable.get("Lisa Smith") 158 | hashTable.get("Sam Doe") 159 | hashTable.get("Sandra Dee") 160 | hashTable.get("Ted Baker") 161 | hashTable.get("Tim Lee") 162 | 163 | hashTable["Kevin Flynn"] = "The grid" 164 | hashTable["Kevin Flynn"] 165 | ``` 166 | 167 | 168 | -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Builder/README.md: -------------------------------------------------------------------------------- 1 | # Builder 2 | 3 | 4 | 5 | Вот представьте что у нас есть фабрика. Но в отличии от фабрики из предыдущей статьи, она умеет создавать только телефоны на базе андроида, и еще при этом различной конфигурации. Тоесть, есть один объект, но при этом его состояние может быть совершенно разным, а еще представьте если его очень трудно создавать, и во время создания этого объекта еще и создается миллион дочерних объектов. Именно в такие моменты, нам очень помогает такой паттерн как строитель. 6 | 7 | Когда использовать: 8 | 9 | 1. Создание сложного объекта 10 | 2. Процесс создания объекта тоже очень не тривиальный – к примеру получение данных из базы и манипуляция ими. 11 | 12 | Сам паттерн состоит из двух компонент – Bulilder и Director. Builder занимается именно построением объекта, а Director знает какой Builder использовать чтобы выдать необходимый продукт. 13 | 14 | Пускай у нас есть телефон, который обладает следующими свойствами: 15 | ```swift 16 | class AndriodPhone { 17 | var osVersion = "" 18 | var name = "" 19 | var cpuCodeName = "" 20 | var RAMsize = 0 21 | var osVersionCode = 0 22 | var launcher = "" 23 | 24 | 25 | func setOSVersion() { 26 | self.osVersion = "" 27 | } 28 | 29 | func setName() { 30 | self.name = "" 31 | } 32 | 33 | func setCPUCodeName() { 34 | self.cpuCodeName = "" 35 | } 36 | 37 | func setRAMsize() { 38 | self.RAMsize = 0 39 | } 40 | 41 | func setOSVersionCode() { 42 | self.osVersionCode = 0 43 | } 44 | 45 | func setLauncher() { 46 | self.osVersion = "" 47 | } 48 | } 49 | ``` 50 | Давайте создадим дженерик строителя от которого будут наследоваться конкретные строители: 51 | 52 | ```swift 53 | class BPAndroidPhoneBuilder { 54 | 55 | let phone = AndriodPhone() 56 | 57 | 58 | func getPhone() -> AndriodPhone { 59 | return self.phone 60 | } 61 | 62 | } 63 | ``` 64 | 65 | Ну а теперь напишем код для конкретных строителий. К примеру, так бы выглядел строитель для дешевого телефона: 66 | 67 | ```swift 68 | class LowPricePhoneBuilder: BPAndroidPhoneBuilder { 69 | func setOSVersion() { 70 | self.phone.osVersion = "Android 2.3" 71 | } 72 | 73 | func setName() { 74 | self.phone.name = "Ведрофон" 75 | } 76 | 77 | func setCPUCodeName() { 78 | self.phone.cpuCodeName = "Some shitty CPU" 79 | } 80 | 81 | func setRAMsize() { 82 | self.phone.RAMsize = 256 83 | } 84 | 85 | func setOSVersionCode() { 86 | self.phone.osVersionCode = 3 87 | } 88 | 89 | func setLauncher() { 90 | self.phone.launcher = "Hia Tsung" 91 | } 92 | } 93 | ``` 94 | 95 | И конечно же строительство дорогого телефона: 96 | 97 | ```swift 98 | class HighPricePhoneBuilder: BPAndroidPhoneBuilder { 99 | func setOSVersion() { 100 | self.phone.osVersion = "Android 5.0" 101 | } 102 | 103 | func setName() { 104 | self.phone.name = "Крутой лопатофон" 105 | } 106 | 107 | func setCPUCodeName() { 108 | self.phone.cpuCodeName = "Some shitty, but expensive CPU" 109 | } 110 | 111 | func setRAMsize() { 112 | self.phone.RAMsize = 2048 113 | } 114 | 115 | func setOSVersionCode() { 116 | self.phone.osVersionCode = 5 117 | } 118 | 119 | func setLauncher() { 120 | self.phone.launcher = "HTC Sence" 121 | } 122 | } 123 | ``` 124 | Кто-то же должен использовать строителей, потому давайте создадим объект который будет с помощью строителей создавать дешевые или дорогие телефоны: 125 | ```swift 126 | class FactorySalesMan { 127 | 128 | var builder = BPAndroidPhoneBuilder() 129 | 130 | func setBuilder(aBuilder: BPAndroidPhoneBuilder) { 131 | self.builder = aBuilder 132 | } 133 | 134 | func getPhone() -> AndriodPhone { 135 | return self.builder.getPhone() 136 | } 137 | 138 | 139 | 140 | func constuctPhone() { 141 | if let builder = builder as? LowPricePhoneBuilder { 142 | builder.setOSVersion() 143 | builder.setName() 144 | builder.setCPUCodeName() 145 | builder.setRAMsize() 146 | builder.setOSVersionCode() 147 | builder.setLauncher() 148 | 149 | } else if let builder = builder as? HighPricePhoneBuilder { 150 | builder.setOSVersion() 151 | builder.setName() 152 | builder.setCPUCodeName() 153 | builder.setRAMsize() 154 | builder.setOSVersionCode() 155 | builder.setLauncher() 156 | } 157 | } 158 | } 159 | ``` 160 | Ну теперь давайте посмотрим что же у нас получилось: 161 | ```swift 162 | let cheapPhoneBuilder = LowPricePhoneBuilder() 163 | let expensivePhoneBuilder = HighPricePhoneBuilder() 164 | 165 | let director = FactorySalesMan() 166 | director.setBuilder(cheapPhoneBuilder) 167 | director.constuctPhone() 168 | let phone = director.getPhone() 169 | print("Phone name \(phone.name), phone cpu: \(phone.cpuCodeName)") 170 | 171 | director.setBuilder(expensivePhoneBuilder) 172 | director.constuctPhone() 173 | let phone2 = director.getPhone() 174 | print("Phone2 name \(phone2.name), phone cpu: \(phone2.cpuCodeName)") 175 | 176 | //print console 177 | Phone name Ведрофон, phone cpu: Some shitty CPU 178 | Phone2 name Крутой лопатофон, phone cpu: Some shitty, but expensive CPU 179 | ``` -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Abstract Factory/README.md: -------------------------------------------------------------------------------- 1 | # Abstract Factory 2 | 3 | **Абстрактная фабрика** – еще один очень популярный паттерн, который как и в названии так и в реализации слегка похож на фабричный метод. 4 | 5 | Итак, что же делает абстрактная фабрика: Абстрактная фабрика дает простой интерфейс для создания объектов которые принадлежат к тому или иному сеймейству объектов. 6 | 7 | Отличия от фабричного метода: 8 | 9 | Фабричный метод порождает объекты одного и того же типа, Абстрактная фабрика же может создавать независимые объекты 10 | Чтобы добавить новый тип объекта–надо поменять интерфейс фабрики, в фабричном же методе легко просто поменять внутренности метода, который ответственный за порождение объектов. 11 | Давайте представим ситуацию: у нас есть две фабрики по производству iPhone и iPad. Одна оригинальная, компании Apple, другая – хижина дядюшки Хуа. И вот, мы хотим производить эти товары: если в страны 3-го мира – то товар от дядюшки, в другие страны – товар любезно предоставлен компанией Apple. 12 | 13 | Итак, пускай у нас есть фабрика, которая умеет производить и айпады и айфоны: 14 | 15 | ```swift 16 | class IPhoneFactory { 17 | } 18 | ``` 19 | Естественно, нам необходимо реализовать продукты, которые фабрика будет производить: 20 | ```swift 21 | class GenericIPad { 22 | var osName: String? 23 | var productName: String? 24 | var screenSize: Float? 25 | } 26 | 27 | class GenericIPhone { 28 | var osName: String? 29 | var productName: String? 30 | } 31 | ``` 32 | Но, продукты немного отличаются. Пускай у нас есть два типа продуктов, оригинальные Apple и продукты которые произведены трудолюбивым дядюшкой Сяо-Ляо: 33 | ```swift 34 | class AppleIPhone: GenericIPhone { 35 | override init() { 36 | super.init() 37 | self.productName = "iPhone" 38 | self.osName = "iOS" 39 | } 40 | } 41 | class AppleIPad: GenericIPad { 42 | override init() { 43 | super.init() 44 | self.productName = "iPad" 45 | self.osName = "iOS" 46 | self.screenSize = 7.7 47 | } 48 | } 49 | 50 | 51 | class ChinaPhone: GenericIPhone { 52 | override init() { 53 | super.init() 54 | self.productName = "Ляо-Фон" 55 | self.osName = "Ведроид" 56 | } 57 | } 58 | class ChinaPad: GenericIPad { 59 | override init() { 60 | super.init() 61 | self.productName = "Сяо-Пад" 62 | self.osName = "Окна-ЦЕ" 63 | self.screenSize = 12.1 64 | } 65 | } 66 | ``` 67 | Разные телефоны, конечно же, производятся на различных фабриках, потому мы просто обязанны их создать! Приблизительно так должны выглядеть фабрика Apple: 68 | ```swift 69 | class AppleFactory: IPhoneFactory { 70 | 71 | func getIPhone() -> GenericIPhone { 72 | let iPhone = AppleIPhone() 73 | return iPhone 74 | } 75 | 76 | func getIPad() -> GenericIPad { 77 | let iPad = AppleIPad() 78 | return iPad 79 | } 80 | 81 | } 82 | ``` 83 | Конечно же у нашего китайского дядюшки тоже есть своя фабрика: 84 | ```swift 85 | class ChinaFactory: IPhoneFactory { 86 | 87 | func getIPhone() -> GenericIPhone { 88 | let phone = ChinaPhone() 89 | return phone 90 | } 91 | 92 | func getIPad() -> GenericIPad { 93 | let pad = ChinaPad() 94 | return pad 95 | } 96 | 97 | } 98 | ``` 99 | Как видим, фабрики одинаковые, а вот девайсы у них получаются разные. 100 | 101 | Ну вот собственно и все, мы приготовили все что надо для демонстрации! Теперь, давайте напишем небольшой метод который будет возвращать нам фабрику которую мы хотим (кстати, тут фабричный метод таки будет): 102 | ```swift 103 | var isThirdWorld: Bool = true 104 | 105 | func getFactory() -> IPhoneFactory { 106 | if (isThirdWorld) { 107 | return ChinaFactory() 108 | } 109 | return AppleFactory() 110 | } 111 | ``` 112 | Теперь меняя значение переменной **isThirdWorld** можно получать те или иные девайсы. 113 | ```swift 114 | let fac = getFactory() 115 | var iPhone = GenericIPhone() 116 | var iPad = GenericIPad() 117 | 118 | if let factory = fac as? ChinaFactory { 119 | iPhone = factory.getIPhone() 120 | iPad = factory.getIPad() 121 | } 122 | if let factory = fac as? AppleFactory { 123 | iPhone = factory.getIPhone() 124 | iPad = factory.getIPad() 125 | } 126 | 127 | print("iPad: \(iPad.productName!), os name: \(iPad.osName!), screensize: \(iPad.screenSize!)") 128 | 129 | print("iPhone: \(iPhone.productName!), os name: \(iPhone.osName!)") 130 | ``` 131 | Ну и проверим что мы там понаписали… 132 | ```swift 133 | let fac = getFactory() 134 | var iPhone = GenericIPhone() 135 | var iPad = GenericIPad() 136 | 137 | if let factory = fac as? ChinaFactory { 138 | iPhone = factory.getIPhone() 139 | iPad = factory.getIPad() 140 | } 141 | if let factory = fac as? AppleFactory { 142 | iPhone = factory.getIPhone() 143 | iPad = factory.getIPad() 144 | } 145 | 146 | print("iPad: \(iPad.productName!), os name: \(iPad.osName!), screensize: \(iPad.screenSize!)") 147 | 148 | print("iPhone: \(iPhone.productName!), os name: \(iPhone.osName!)") 149 | 150 | isThirdWorld = false 151 | 152 | let fac1 = getFactory() 153 | 154 | if let factory = fac1 as? ChinaFactory { 155 | iPhone = factory.getIPhone() 156 | iPad = factory.getIPad() 157 | } 158 | if let factory = fac1 as? AppleFactory { 159 | iPhone = factory.getIPhone() 160 | iPad = factory.getIPad() 161 | } 162 | 163 | print("iPad: \(iPad.productName!), os name: \(iPad.osName!), screensize: \(iPad.screenSize!)") 164 | ``` 165 | 166 | ### Итак: 167 | 168 | Паттерн Абстрактная фабрика используется для обеспечения клиента набором родственных или зависимых объектов. «Семья» объектов, созданных на заводе-изготовителе определяются во время выполнения. -------------------------------------------------------------------------------- /Шаблоны программирования Swift/Visitor/README.md: -------------------------------------------------------------------------------- 1 | # Visitor 2 | 3 | Вот у каждого дома вероятнее всего есть холодильник. В ВАШЕМ доме, ВАШ холодильник. Что будет если холодильник сломается? Некоторые пойдут почитают в интернете как чинить холодильник, какая модель, попробуют поколдовать над ним, и разочаровавшись вызовут мастера по ремонту холодильников. Заметьте – холодильник ваш, но функцию “Чинить Холодильник” выполняет совершенно другой человек, про которого вы ничего не знаете, а попросту – обычный визитер 4 | Паттерн визитер – позволяет вынести из наших объектов логику, которая относится к этим объектам, в отдельный клас, что позволяет нам легко изменять / добавлять алгоритмы, при этом не меняя логику самого класа. 5 | Когда мы захотим использовать этот паттерн: 6 | 7 | Когда у нас есть сложный объект, в котором содержится большое количество различных элементов, и вы хотите выполнять различные операции в зависимости от типа этих элиментов. 8 | Вам необходимо выполнять различные операции над классами, и при этом Вы не хотите писать вагон кода внутри реализации этих классов. 9 | В конце–концов, вам нужно добавлять различные операции над элементами, и вы не хотите постоянно обновлять классы этих элементов. 10 | Рассмотрим пример: у нас есть несколько складов, в каждом складе можнт хранится товар. Один визитер будет смотреть склады, другой визитер будет называть цену товара в складе. 11 | Итак, для начала сам товар: 12 | ```swift 13 | class WarehouseItem { 14 | var name:String 15 | var isBroken: Bool 16 | var price: Int 17 | 18 | init(aName:String, isBrokenState: Bool, aPrice: Int) { 19 | self.name = aName 20 | self.isBroken = isBrokenState 21 | self.price = aPrice 22 | } 23 | } 24 | ``` 25 | И естественно сам склад: 26 | ```swift 27 | class Warehouse { 28 | lazy var itemsArray: [WarehouseItem] = [] 29 | 30 | func addItem(anItem: WarehouseItem) { 31 | itemsArray.append(anItem) 32 | } 33 | 34 | func accept(visitor: BasicVisitor) { 35 | visitor.visit(self) 36 | 37 | for item in itemsArray { 38 | visitor.visit(item) 39 | } 40 | } 41 | } 42 | ``` 43 | Как видим, наш склад умеет хранить и добавлять товар, но также обладает таинственным методом accept который принимает в себя визитор и вызвает его метод visit. Чтобы картинка сложилась, давайте создадим протокол BasicVisitor и различных визиторов: 44 | ```swift 45 | protocol BasicVisitor { 46 | func visit(anObject: AnyObject) 47 | } 48 | ``` 49 | Как видим, протокол требует реализацию только одного метода. Теперь давайте перейдем к самим визитерам: 50 | ```swift 51 | class QualityCheckerVisitor: BasicVisitor { 52 | func visit(anObject: AnyObject) { 53 | 54 | if let obj = anObject as? WarehouseItem { 55 | if obj.isBroken { 56 | print("Товар \(obj.name) сломан") 57 | } else { 58 | print("Товар \(obj.name) весьма не плох") 59 | } 60 | } 61 | 62 | if let _ = anObject as? Warehouse { 63 | print("Отличный склад!") 64 | } 65 | } 66 | } 67 | ``` 68 | Если почитать код, то сразу видно что визитер при вызове своего метода visit определяет тип объекта который ему передался, и выполняет определнные функции в зависимоти от этого типа. Данный объект просто говорит или вещи на складе поломаны, а так же что ему нравится склад:) 69 | ```swift 70 | class PriceCheckerVisitor:BasicVisitor { 71 | func visit(anObject: AnyObject) { 72 | if let obj = anObject as? WarehouseItem { 73 | print("Товар \(obj.name) имеет цену: \(obj.price)") 74 | } 75 | 76 | if let _ = anObject as? Warehouse { 77 | print("Я не знаю сколько стоит склад!") 78 | } 79 | } 80 | } 81 | ``` 82 | В принципе этот визитер делает тоже самое, только в случае склада он признается что растерян, а в случае товара говорит цену товара! 83 | 84 | Теперь давайте запустим то что у нас получилось! Код генерации тестовых даных: 85 | ```swift 86 | let warehouse = Warehouse() 87 | 88 | warehouse.addItem(WarehouseItem(aName: "Товар1", isBrokenState: true, aPrice: 37)) 89 | warehouse.addItem(WarehouseItem(aName: "Товар2", isBrokenState: true, aPrice: 45)) 90 | warehouse.addItem(WarehouseItem(aName: "Товар3", isBrokenState: false, aPrice: 74)) 91 | warehouse.addItem(WarehouseItem(aName: "Товар4", isBrokenState: false, aPrice: 34)) 92 | warehouse.addItem(WarehouseItem(aName: "Товар5", isBrokenState: true, aPrice: 15)) 93 | warehouse.addItem(WarehouseItem(aName: "Товар6", isBrokenState: true, aPrice: 84)) 94 | warehouse.addItem(WarehouseItem(aName: "Товар7", isBrokenState: false, aPrice: 91)) 95 | warehouse.addItem(WarehouseItem(aName: "Товар8", isBrokenState: false, aPrice: 50)) 96 | warehouse.addItem(WarehouseItem(aName: "Товар9", isBrokenState: true, aPrice: 11)) 97 | 98 | 99 | let priceVisitor = PriceCheckerVisitor() 100 | let qualityVisitor = QualityCheckerVisitor() 101 | 102 | warehouse.accept(priceVisitor) 103 | print("- - - - - - - - - - - - - - - - - - - - ") 104 | warehouse.accept(qualityVisitor) 105 | 106 | //console: 107 | Я не знаю сколько стоит склад! 108 | Товар Товар1 имеет цену: 37 109 | Товар Товар2 имеет цену: 45 110 | Товар Товар3 имеет цену: 74 111 | Товар Товар4 имеет цену: 34 112 | Товар Товар5 имеет цену: 15 113 | Товар Товар6 имеет цену: 84 114 | Товар Товар7 имеет цену: 91 115 | Товар Товар8 имеет цену: 50 116 | Товар Товар9 имеет цену: 11 117 | - - - - - - - - - - - - - - - - - - - - 118 | Отличный склад! 119 | Товар Товар1 сломан 120 | Товар Товар2 сломан 121 | Товар Товар3 весьма не плох 122 | Товар Товар4 весьма не плох 123 | Товар Товар5 сломан 124 | Товар Товар6 сломан 125 | Товар Товар7 весьма не плох 126 | Товар Товар8 весьма не плох 127 | Товар Товар9 сломан 128 | ``` 129 | -------------------------------------------------------------------------------- /PopularApps/Starbucks/Starbucks/Home/Rewards/RewardsGraphView.swift: -------------------------------------------------------------------------------- 1 | // 2 | // RewardsGraphView.swift 3 | // Starbucks 4 | // 5 | // Created by Владимир on 17.05.2022. 6 | // 7 | 8 | import UIKit 9 | 10 | class RewardsGraphView: UIView { 11 | 12 | let imageView = UIImageView() 13 | 14 | let initialFrameWidth: CGFloat = 200 // arbitrary width 15 | var actualFrameWidth: CGFloat? 16 | 17 | let height: CGFloat = 80 18 | 19 | override init(frame: CGRect) { 20 | super.init(frame: .zero) 21 | layout() 22 | } 23 | 24 | required init?(coder: NSCoder) { 25 | fatalError("init(coder:) has not been implemented") 26 | } 27 | 28 | func layout() { 29 | imageView.translatesAutoresizingMaskIntoConstraints = false 30 | 31 | drawRewardsGraph() 32 | 33 | addSubview(imageView) 34 | 35 | NSLayoutConstraint.activate([ 36 | imageView.topAnchor.constraint(equalTo: topAnchor), 37 | imageView.centerXAnchor.constraint(equalTo: centerXAnchor), 38 | imageView.centerYAnchor.constraint(equalTo: centerYAnchor), 39 | imageView.bottomAnchor.constraint(equalTo: bottomAnchor) 40 | ]) 41 | } 42 | 43 | func drawRewardsGraph() { 44 | 45 | let frameWidth: CGFloat = actualFrameWidth ?? initialFrameWidth 46 | 47 | let padding: CGFloat = 20 48 | let dotSize: CGFloat = 12 49 | let lineWidth: CGFloat = 2 50 | let numberOfDots: CGFloat = 5 51 | let numberofSections = numberOfDots - 1 52 | 53 | let spacingBetweenDots = (frameWidth - 2 * padding) / (numberofSections + 0.5) 54 | 55 | let shortSegmentLength = spacingBetweenDots * 0.25 56 | 57 | let renderer = UIGraphicsImageRenderer(size: CGSize(width: frameWidth, height: height)) 58 | 59 | var dots: [CGPoint] = [] 60 | let labels: [String] = ["25", "50", "150", "250", "400"] 61 | 62 | // Because Core Graphics straddles its frame when it draws, and we want a circle 63 | // exactly at this point, we need to offset by this amount in the y. The 50 64 | // is just to push everything down enough to make room for the green indicator. 65 | let indicatorOffset: CGFloat = 34 66 | let yOffset = (dotSize + lineWidth) / 2 + indicatorOffset 67 | 68 | let img = renderer.image { ctx in 69 | 70 | // Define our dots 71 | for index in 0...Int((numberOfDots - 1)) { 72 | let x = padding + shortSegmentLength + (spacingBetweenDots * CGFloat(index)) 73 | dots.append(CGPoint(x: x, y: yOffset)) 74 | } 75 | 76 | // Define our lines between dots 77 | ctx.cgContext.setLineWidth(lineWidth) 78 | ctx.cgContext.setStrokeColor(UIColor.systemGray4.cgColor) 79 | 80 | // Draw starting segment 81 | let firstShortSegmentBegin = padding 82 | let firstShortSegmentEnd = padding + shortSegmentLength - dotSize/2 83 | 84 | ctx.cgContext.move(to: CGPoint(x: firstShortSegmentBegin, y: yOffset)) 85 | ctx.cgContext.addLine(to: CGPoint(x: firstShortSegmentEnd, y: yOffset)) 86 | ctx.cgContext.strokePath() 87 | 88 | // Draw ending segment 89 | let lastShortSegmentEnd = frameWidth - padding 90 | let lastShortSegmentBegin = lastShortSegmentEnd - shortSegmentLength 91 | 92 | ctx.cgContext.move(to: CGPoint(x: lastShortSegmentBegin, y: yOffset)) 93 | ctx.cgContext.addLine(to: CGPoint(x: lastShortSegmentEnd, y: yOffset)) 94 | ctx.cgContext.strokePath() 95 | 96 | ctx.cgContext.addLines(between: dots) 97 | ctx.cgContext.strokePath() 98 | 99 | ctx.cgContext.setFillColor(UIColor.white.cgColor) 100 | 101 | // Draw our dots 102 | for dot in dots { 103 | let dotBounds = CGRect(x: dot.x - (dotSize * 0.5), 104 | y: dot.y - (dotSize * 0.5), 105 | width: dotSize, 106 | height: dotSize) 107 | 108 | ctx.cgContext.addEllipse(in: dotBounds) 109 | ctx.cgContext.drawPath(using: CGPathDrawingMode.fillStroke) 110 | } 111 | 112 | // Draw points consumed 113 | let pointsConsumedBegin = firstShortSegmentBegin 114 | let pointsConsumedEnd = padding + shortSegmentLength / 2 115 | 116 | ctx.cgContext.setStrokeColor(UIColor.starYellow.cgColor) 117 | 118 | ctx.cgContext.move(to: CGPoint(x: pointsConsumedBegin, y: yOffset)) 119 | ctx.cgContext.addLine(to: CGPoint(x: pointsConsumedEnd, y: yOffset)) 120 | ctx.cgContext.strokePath() 121 | 122 | // Draw green indicator 123 | let indicatorX = pointsConsumedEnd - 8 124 | let indicatorY = yOffset - 36 125 | let star = UIImage(named: "green-indicator") 126 | 127 | star?.draw(at: CGPoint(x: indicatorX, y: indicatorY)) 128 | 129 | // Draw our labels 130 | let paragraphStyle = NSMutableParagraphStyle() 131 | paragraphStyle.alignment = .center 132 | 133 | let attrs: [NSAttributedString.Key: Any] = [ 134 | .font: UIFont.preferredFont(forTextStyle: .footnote), 135 | .paragraphStyle: paragraphStyle 136 | ] 137 | 138 | for (i, dot) in dots.enumerated() { 139 | 140 | let string = labels[i] 141 | 142 | let attributedString = NSAttributedString(string: string, attributes: attrs) 143 | attributedString.draw(with: CGRect(x: dot.x - 15, y: dot.y + 16, width: 30, height: 20), options: .usesLineFragmentOrigin, context: nil) 144 | } 145 | 146 | } 147 | 148 | imageView.image = img 149 | } 150 | } 151 | 152 | -------------------------------------------------------------------------------- /База iOS/Array/Functional programming (FP)/README.md: -------------------------------------------------------------------------------- 1 | # Array 2 | 3 | Handy convenience methods 4 | 5 | ## Contains 6 | проверяет наличие элемента в массиве 7 | ```swift 8 | let hasHitron = self.orderItems.contains { $0.activationModemType == .Hitron } 9 | ``` 10 | 11 | ## forEach 12 | перебо(обход) массива, в отличии от map ничего не возвращает 13 | ```swift 14 | ["Taylor", "Paul", "Adele"].forEach { print($0) } 15 | ``` 16 | ## map 17 | позволяет применить переданное в него замыкание для каждого элемента коллекции 18 | ```swift 19 | let fruits = ["Apple", "Cherry", "Orange", "Pineapple"] 20 | let upperFruits = fruits.map { $0.uppercased() } 21 | ``` 22 | 23 | ## flatMap 24 | сначала применяет функцию к каждому элементу, а затем преобразует полученный результат в плоскую структуру и помещает в новый массив. 25 | ```swift 26 | let arr1 = ["it's Sunny in", "", "California"]; 27 | 28 | let words = arr1.map{ ($0.split(separator: " ")) } 29 | print(words) // [["it\'s", "Sunny", "in"], [], ["California"]] 30 | 31 | let flatWords = arr1.flatMap{ ($0.split(separator: " ")) } 32 | print(flatWords)// ["it's","Sunny","in", "", "California"] 33 | ``` 34 | пример собственной реализации `flatMap` 35 | ```swift 36 | extension Array { 37 | func flatMap(_ transform: (Element) -> [T]) -> [T] { 38 | var result = [T]() 39 | for element in self { 40 | result.append(contentsOf: transform(element)) 41 | } 42 | return result 43 | } 44 | } 45 | ``` 46 | Функция принимает один аргумент — замыкание преобразования, которое преобразует каждый элемент массива в новый массив другого типа. Функция перебирает массив, применяет преобразование к каждому элементу и добавляет содержимое результирующего массива в новый возвращаемый массив. 47 | ## compactMap 48 | делает тоже что и `map()`, но дополнительно «разворачивает» полученные на выходе Optional значения и удаляет из коллекции значения равные `nil`. 49 | ```swift 50 | let possibleNumbers = ["1", "2", "three", "///4///", "5"] 51 | let compactMapped = possibleNumbers.compactMap(Int.init) 52 | print (compactMapped) // [1, 2, 5] 53 | ``` 54 | пример собственной реализации `compactMap` 55 | ```swift 56 | extension Array { 57 | func compactMap(_ transform: (Element) -> T?) -> [T] { 58 | var result = [T]() 59 | for element in self { 60 | if let transformed = transform(element) { 61 | result.append(transformed) 62 | } 63 | } 64 | return result 65 | } 66 | } 67 | ``` 68 | 69 | Функция принимает один аргумент — замыкание преобразования, которое отображает каждый элемент массива в опциональное значение другого типа. Затем функция выполняет итерацию по массиву, применяет преобразование к каждому элементу, и если результат преобразования не равен nil-у, он добавляется к новому возвращаемому массиву. 70 | 71 | ## sort 72 | сортирует данные в массиве 73 | ```swift 74 | let scoresString = ["100", "95", "85", "90", "100"] 75 | let sortedString1 = scoresString.sorted() 76 | print(sortedString1) // ["100", "100", "85", "90", "95"] 77 | ``` 78 | > такой результат получился потому что копилятор считает что первая цифра 1 меньше 8 или 9 79 | 80 | ### reversed 81 | сортирует элементы в обратном порядке 82 | ```swift 83 | let names = ["Taylor", "Paul", "Adele", "Justin"] 84 | 85 | let sorted = names.sorted() 86 | print(sorted) // ["Adele", "Justin", "Paul", "Taylor"] 87 | 88 | let reversedSorted = names.sorted().reversed() 89 | print(reversedSorted) // ReversedCollection>(_base: ["Adele", "Justin", "Paul", "Taylor"]) 90 | ``` 91 | > `ReversedCollection` это _lazy_ массив, поскольку массивы это Value типы, то на самом деле Swift не работал с массивом(не сортировал в обратном порядке), поэтому данный метод очень быстрый **O(1)** 92 | Если нужен настоящий отсортированный массив, используйте следущий пример кода: 93 | ```swift 94 | let sortedArray = Array(names.sorted().reversed()) 95 | print(sortedArray) // ["Taylor", "Paul", "Justin", "Adele"] 96 | ``` 97 | 98 | ## filter 99 | используется, когда требуется отфильтровать элементы коллекции по определенному правилу 100 | ```swift 101 | let fibonacciNumbers = [1, 1, 2, 3, 5, 8, 13, 21, 34, 55] 102 | let evenFibonacci = fibonacciNumbers.filter { $0 % 2 == 0 } 103 | print(evenFibonacci) // [2, 8, 34] 104 | ``` 105 | 106 | ## reduce 107 | позволяет обьединить все элементы коллекции в одно значение в соответсвтвии с переданным замыканием 108 | ```swift 109 | let names = ["Taylor", "Paul", "Adele"] 110 | let count = names.reduce(0) { $0 + $1.count } 111 | print(count) // 15 112 | ``` 113 | 114 | ## joined 115 | сложение массивов 116 | ```swift 117 | let numbers = [[1, 2], [3, 4], [5, 6]] 118 | let joined = Array(numbers.joined()) 119 | // [1, 2, 3, 4, 5, 6] 120 | ``` 121 | > при сложении массивов убирается один уровень вложенности 122 | ## split 123 | разделить массив 124 | ```swift 125 | let multilineString = """ 126 | Есть свойства, бестелесные явленья, 127 | С двойною жизнью; тип их с давних лет, — 128 | Та двойственность, что поражает зренье: 129 | То — тень и сущность, вещество и свет. 130 | 131 | Есть два молчанья, берега и море, 132 | Душа и тело. Властвует одно 133 | В тиши. Спокойно нежное, оно 134 | Воспоминаний и познанья горе 135 | 136 | """ 137 | 138 | let words = multilineString.lowercased() 139 | .split(separator: "\n") 140 | .map{$0.split(separator: " ")} 141 | /* 142 | [["есть", "свойства,", "бестелесные", "явленья,"], 143 | ["с", "двойною", "жизнью;", "тип", "их", "с", "давних", "лет,", "—"], 144 | ["та", "двойственность,", "что", "поражает", "зренье:"], 145 | ["то", "—", "тень", "и", "сущность,", "вещество", "и", "свет."], 146 | ["есть", "два", "молчанья,", "берега", "и", "море,"], 147 | ["душа", "и", "тело.", "властвует", "одно"], 148 | ["в", "тиши.", "спокойно", "нежное,", "оно"], 149 | ["воспоминаний", "и", "познанья", "горе"] 150 | */ 151 | ``` 152 | ## first(where) 153 | Получение первого элемента, который удовлетворяет определенным условиям 154 | ```swift 155 | let numbers = [3, 7, 4, -2, 9, -6, 10, 1] 156 | let firstNegative = numbers.first(where: { $0 < 0 }) // Optional(-2) 157 | ``` 158 | ### last(where) 159 | Получение последнего элемента, который удовлетворяет определенным условиям 160 | 161 | ## isEmpty 162 | проверка массива на наличие данных 163 | ```swift 164 | let numbers = [] 165 | numbers.isEmpty // true 166 | ``` 167 | 168 | ## Полезные сслыки 169 | - [Немного практики функционального программирования в Swift для начинающих](https://habr.com/ru/post/440722/) --------------------------------------------------------------------------------