├── .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 |
9 |
10 |
11 |
12 |
13 | ## Dynamic System Colors
14 |
15 | Apple также имеет семантически определенные системные цвета для использования в фоновых областях, содержимом переднего плана и собственных элементах управления, таких как метки, разделители и заливка. Они автоматически адаптируются как к темным, так и к темным режимам пользовательского интерфейса.
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
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 | 
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 | 
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 | 
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 | 
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/)
--------------------------------------------------------------------------------