Swift Xcode Ios
Contents |
Swift
https://docs.swift.org/swift-book/GuidedTour/GuidedTour.html
let myConst = 42
var myVariable = 1
let implicitDobule = 70.0
let explicitDouble: Double = 70
// string interpolation using \()
var myStr = "My name is \(name)"
// indent is removed if it is the same as ending quotation marks
var myMultilineStr = """
I say "My name is \(name)"
"""
Arrays and dictionaries
var myArray = ["a", "b"]
var myDictionary = [
"name": "Duke",
]
// to define empty arrays you need to declare type
let emptyArray: [String] = []
let emptyDictionary: [String: Float] = [:]
}
myArray.append("first")
Control flow for loops for in
, while
, repeat while
let scores = [1, 2]
var result = 0
for score in scores {
if score > 1 {
result += 2
} else {
result += 1
}
}
// range of indexes
for i in 0..<4 { }
for i in 0...3 { }
for (_, name) in myDictionary {}
while n < 100 { n *= 2 }
repeat {
m *= 2
} while m < 100
if
statement requires boolean expression or using let
with optional string
var optionalName: String? = "a"
if let name = optionalName {
}
optionalName = nil
Handle optional values with default value using ??
operator
let greeting = "Hi \(name ?? "guest")'
If class is optional than you can use ?
before calling a method or
property, optionalSquare?.radius
returns an optional value.
Switch using case
let vegetable = "red pepper"
switch vegetable {
case "celery":
print("Add some raisins and make ants on a log.")
case "cucumber", "watercress":
print("That would make a good tea sandwich.")
case let x where x.hasSuffix("pepper"):
print("Is it a spicy \(x)?")
default:
print("Everything tastes good in soup.")
}
Functions and Closures
Arguments are parameter name and type, You can use custom argument label before
parameter name or _
to use no argument label (otherwise you need to call a
function with parameter name like greet(person: "John", day: "Wed")
if there
are more than one parameter)
func greet(_ person: String, on day: String) -> String {
return "Hello \(person) today is \(day)"
}
print(greet("John", on: "Wed"))
Return value can be a tuple
func cal(scores: [Int]) -> (min: Int, max: Int) {
var min = scores[0]
var max = scores[0]
return (min, max)
}
You can nest functions. Functions are first class type ie it can be return value from function.
func makeInc() -> ((Int) -> Int) {
func add(number: Int) -> Int {
return 1 + number
}
return add
}
var inc = makeInc()
print(inc(3))
Functions can take another function as one of its arguments
func hasAnyMatches(_ list: [Int], condition: (Int) -> Bool) -> Bool {
for item in list {
if condition(item) {
return true
}
}
return false
}
func lessThanTen(number: Int) -> Bool {
return number < 10
}
var numbers = [30, 2, 12]
print(hasAnyMatches(numbers, condition: lessThanTen))
Functions are actually a special case of closures, blocks of code that can be
called later. Closure without a name is surrounded with braces, use in
to
separate arguments and return type from the body
var numbers = [30, 2, 12]
print(numbers.map({ (number: Int) -> Int in
return 3 * number
}))
When closure type is known (in callback for a delegate) you can omit return
type. Single line can omit return. You can also omit parameters and use $0
$1
. You can omit parentheses if closure if the only argument.
var numbers = [30, 1, 12]
print(numbers.map({ number in 3 * number}))
print(numbers.map { 3 * $0})
var sorted = numbers.sorted { $0 > $1 }
print(sorted)
Classes uses same let
for constants, var
for instance property, except that
it’s in the context of a class. Use init()
for initializers (deinit()
for
deinitializer for cleanup). If there is a parameter with same name, you can use
self.name
(otherwise, it is not required when assigning instance property)
class NamedShape {
var numberOfSides: Int = 0
var name: String
init(_ name: String) {
self.name = name
}
func simpleDescription() -> String {
return "The \(name) shape has \(numberOfSides) sides."
}
}
var s = NamedShape("My")
s.numberOfSides = 2
print(s.simpleDescription())
Subclasses can override
methods. You need to manually call super.init()
.
class Circle: NamedShape {
var radius: Int = 0
init(radius: Int, name: String) {
super.init(name)
self.radius = radius
}
override func simpleDescription() -> String {
return "The \(name) circle has \(radius) radius."
}
}
In addition to simple instance properties, you can have a getter and a setter
(it uses newValue
implicit name for setter). If you need to call a method when
changing the property, you can use willSet
and didSet
class MyClass {
var length: Int
init(newLength length: Int) {
length = newLength
}
var t: Int {
get {
return length
}
set {
length = newValue / 3
}
}
}
Enumerations enum
can have methods. It starts from zero unless explicitly
specifying value. Access raw values using .rawValue
property.
Use init?(rawValue:)
initializer to make an instance of an enumeration from a
raw value.
enum Rank: Int {
case ace = 1
case two, three
func simpleDescription() -> String {
switch self {
case .ace:
return "ACE"
default:
return String(self.rawValue)
}
}
}
let ace = Rank.ace
// or let ace: Rank = .ace
print(ace)
print(ace.rawValue)
print(ace.simpleDescription())
You can use values associated with the case, which are determined when you make an instance, so they can be different for each instance of enumeration case (like stored properties of the enumeration case instance)
enum ServerResponse {
case result(String, String)
case failure(String)
}
let success = ServerResponse.result("6:00 am", "8:09 pm")
let failure = ServerResponse.failure("Out of cheese.")
switch success {
case let .result(sunrise, sunset):
print("Sunrise is at \(sunrise) and sunset is at \(sunset).")
case let .failure(message):
print("Failure... \(message)")
}
// Prints "Sunrise is at 6:00 am and sunset is at 8:09 pm."
Structires struct
are similar to class
just they are always copied, but
classes are passed by reference
Protocols can be declared with protocol
. use mutating
to mark a method that
modifies the structure.
protocol ExampleProtocol {
var simpleDescription: String { get }
mutating func adjust()
}
class SimpleClass: ExampleProtocol {
var simpleDescription: String = "A very simple class"
func adjust() {
simpleDescription += " now adjusted"
}
}
Use extension
to add functionality to an existing type.
extension Int: ExampleProtocol {
var simpleDescription: String {
return "The number \(self)"
}
mutating func adjust() {
self += 42
}
}
print(7.simpleDescription)
// Prints "The number 7"
Extension is also used to write seed sample data
struct Card {
var title: String
}
extension Card {
static let sampleData: [Card] =
[
Card(title: "First"),
Card(title: "Second"),
]
}
Error Handling is using any type that adopts Error
protocol
Use throw
to raise an error and throws
to mark a function that can throw an
error. Code that called a function (with try
prefix) handles the error with:
do catch
, catch is similar to switch Error case ...
automatic
name is error
.
enum PrinterError: Error {
case outOfPaper
case onFire
}
func send(job: Int, printerName: String) throws -> String {
if printerName == "Never has paper" {
throw PrinterError.outOfPaper
}
return "Job \(job) sent"
}
do {
let result = try send(job: 42, printerName: "Never has paper")
print(result)
} catch PrinterError.onFire {
print("Call the fireman")
} catch let printerError as PrinterError {
print("Printer error: \(printerError)")
} catch {
print(error)
}
Another way to handle errors is to use try?
to convert the result to an
optional.
let result = try? send(job: 42, printerName: "Never has paper")
Use defer
to write a block of code that’s executed after all other code in the
function, just before function returns, it is executed regardless of whether the
function throws an error. Please use this cleanup code after setup block
var fridgeIsOpen = false
let fridgeContent = ["milk", "eggs"]
func fridgeContains(_ food: String) -> Bool {
fridgeIsOpen = true
defer {
fridgeIsOpen = false
}
let result = fridgeContent.contains(food)
return result
}
print(fridgeContains("banana"))
print(fridgeIsOpen)
Generic function is created using <Name>
which is populated when it is called
func makeArray<Item>(_ item: Item, numberOfTimes: Int) -> [Item] {
var result: [Item] = []
for _ in 0..<numberOfTimes {
result.append(item)
}
return result
}
print(makeArray("asd", numberOfTimes: 3))
print(makeArray(1, numberOfTimes: 0))
You can make generic forms of functions, methods, classes, enumeration and structures
// Reimplement the Swift standard library's optional type
enum OptionalValue<Wrapped> {
case none
case some(Wrapped)
}
var possibleInteger: OptionalValue<Int> = .none
possibleInteger = .some(100)
Use where
right before the body to specify a list of requirements, for example
require type to implement a protocol, require a class to have superclass
func anyCommonElements<T: Sequence, U: Sequence>(_ lhs: T, _ rhs: U) -> Bool
where T.Element: Equatable, T.Element == U.Element
{
for lhsItem in lhs {
for rhsItem in rhs {
if lhsItem == rhsItem {
return true
}
}
}
return false
}
anyCommonElements([1, 2, 3], [3])
Ubuntu
Use official vim support
git clone [email protected]:apple/swift.git --depth 1
mkdir ~/.vim/pack/bundle/start -p
cp vim ~/.vim/pack/bundle/start/swift -r
Install swift on Ubuntu from https://www.swift.org/download/ extract to Programs and add Path
echo "PATH=~/Programs/swift-5.5.3-RELEASE-ubuntu20.04/usr/bin:$PATH" >> ~/.bashrc
. ~/.bashrc
Build
touch Package.swift
mkdir Sources
echo print("Hello, world") >> Sources/main.swift
swift build
# .build/debug/Hello
iOS in XCode
https://developer.apple.com/tutorials/app-dev-training
- right_click -> Refactor -> Rename
- cmd + click -> Embed in VStack
- cmd + right_click -> Find
- navigate Show next tab, show previous tab with cmd+shift+{} (with default key bindings cmd+{}) I need shift because of karabiner so I remaped Show next/previous tab to cmd+[] so now it works cmd+{} (also use other key kombination for conflicts like Shift left/right and Align left/right edges)
- enable vim in Editor -> Vim Mode . You can visually select and cmd+c to copy
to clipboard and paste in another program (yank paste works only inside xcode)
Add to project .gitignore
# .gitignore *.xcodeproj/
When there is an error
Select a scheme that builds a target which contains the current file, or add this file to a target that is built by the current scheme.
than you should close Xcode and remove clean the build folder
rm -rf ~/Library/Developer/Xcode/DerivedData/*
Elements:
- view ``` import SwiftUI
struct CardView: View { let card: Card var body: some View { } } struct CardView_Previews: PreviewProvider { static var card = Card.sampleData[0] static var previews: some View { CardView(card: card) .background(card.theme.mainColor) .previewLayout(.fixed(width: 400, height: 60)) } }
* stacks
VStack { Text(“a”) Spacer() HStack { Label(“Info”) Spacer() Label(“More Info”) } } .padding() .foregroundColor(scrum.theme.accentColor)
* List https://developer.apple.com/documentation/swiftui/list
* Label pick icons on https://developer.apple.com/sf-symbols/
Label(“300”, systemImage: “hourglass.bottomhalf.fill”)
to share styles use extension of LabelStyle and override makeBody
struct TrailingIconLabelStyle: LabelStyle { func makeBody(configuration: Configuration) -> some View { HStack { configuration.title configuration.icon } } }
extension LabelStyle where Self == TrailingIconLabelStyle { static var trailingIcon: Self { Self() } }
use like this
* accesibility
Image(systemName: “person”) .accessibilityLabel(“Person”)
# Errors
For
Showing Recent Messages Signing for “Scrumdinger” requires a development team. Select a development team in the Signing & Capabilities editor. ``` You need to select Team by navigating to project (left icon on left window) and find second tab on right window Signing & Capabilities and choose the team (for example Personal Team) and choose unique Bundle Indentifier and you should see: Signging Ceritficate Apple Development email (ASD123)
Tips
Open emulator by navigating to in menu bar Xcode -> Open Developer Tool -> Simulator
- icons https://developer.apple.com/sf-symbols/ or online https://github.com/cyanzhong/sf-symbols-online