extension PredefinedString {
var snakeCasedValue: String {
let pattern = "([a-z0-9])([A-Z])"
return rawValue.replacingOccurrences(of: pattern, with: "$1_$2", options: .regularExpression).lowercased()
}
}
[카테고리:] swift
When you want to use ‘continue’ in map
Answer by ChatGPT
In Swift, you cannot use continue
statement inside the map
function because map
function traverses each element of an array and executes a closure for each element, and continue
statement can only be used inside a loop. However, there is a way to skip a specific element and continue to the next iteration inside the map
function. You can achieve this by using a conditional statement inside the closure to skip the element. For example, if you want to skip odd numbers and process only even numbers in an array, you can write the following code:
let numbers = [1, 2, 3, 4, 5, 6] let evenNumbers = numbers.map { number in if number % 2 != 0 { return nil // skip the element by returning nil } return number * 2 // process even numbers by returning a value }.compactMap { $0 } // remove nil values print(evenNumbers) // [4, 8, 12]
In the code above, we return nil
to skip odd numbers and return a value to process even numbers inside the map
function. Then, we use the compactMap
function to remove nil
values and print the result.
Therefore, although you cannot use continue
statement inside the map
function, you can skip a specific element and continue to the next iteration by using a conditional statement inside the closure.
If you gets error “Generic parameter ‘ElementOfResult’ could not be inferred”, add return type to the map closure
from
let monthlyDividendViewModels = dividendResponse.monthlyDividends
.map { monthlySummary in
guard let month = monthlySummary.paymentMonth else {
return nil
}
return MonthlyDividendViewModel(sum: sum, stockDividends: stockDividends)
}
.compactMap { $0 }
to
let monthlyDividendViewModels = dividendResponse.monthlyDividends
.map { monthlySummary -> MonthlyDividendViewModel? in
guard let month = monthlySummary.paymentMonth else {
return nil
}
return MonthlyDividendViewModel(sum: sum, stockDividends: stockDividends)
}
.compactMap { $0 }
When cannot access property before init
- Set requisite property
- call super init
- Then change the property accessing the property needed.
override init() {
self.initialState = State(
trendColorType: .korea
)
super.init()
initialState.trendColorType = userDefaultSettings.trendColorType ?? initialState.trendColorType
}
Make enum with associated values equatable
enum ErrorType: Equatable {
case networkError
case serverError(_ error: NeoServerError)
case unknownError(_ error: Error)
static func == (lhs: ErrorType, rhs: ErrorType) -> Bool {
switch (lhs, rhs) {
case (.networkError, .networkError),
(.serverError, .serverError),
(.unknownError, .unknownError):
return true
default:
return false
}
}
}
swift generate boilerplate code with automation using gyb
- gyb stands for Generate Your Boilerplate https://nshipster.co.kr/swift-gyb/
- its python
- python comment out: #
- Download gyb from https://github.com/apple/swift/blob/main/utils/gyb.py
- Add script to run gyb files into Build Phases or Add to shell script which runs gyb file to make Swift files.
find . -name '*.gyb' | \
while read file; do \
${SCRIPT_DIR}/gyb.py --line-directive '' -o "${file%.gyb}" "$file"; \
done
- Add “.gyb” to the name of Swift file you want to make
- Except for the swift code to put you need to prefix %, and you have to write “end” in the same depth of condition
enum AppEventComponent: String {
% for component in appEventComponents:
% if component[0].isdigit():
case _${component} = "${component}"
% else:
case ${component}
% end
% end
}
4. set doesn’t have .sort() function. use sorted instead. Because Set does not have order, sorted() returns list.
appEventModules = sorted(appEventModules)
5. If you want to change cases in Swift to list for python, it’s convenient to use “replace regex” with “()”, “$1”.
6. To prevent duplication, use Enum. duplication in Enum makes compile error but Set doesn’t. If name is value, use “auto”
It’s a script which makes enum case if you put event name with format of “screen_button_action”
//
// This file is auto-generated.
// Run ./scripts/generate-gyb.bash
//
%{
from enum import Enum, auto
class Event(Enum):
# Add new statistics events
market_filter__main__enter = auto()
class AppEventModule(Enum):
add_buy = auto()
class AppEventComponent(Enum):
_1y = auto()
class AppEventAction(Enum):
enter = auto()
appEventModules = set()
appEventComponents = set()
appEventActions = set()
for event in Event:
for (index, value) in enumerate(event.name.split('__')):
if index == 0: appEventModules.add(value)
elif index == 1: appEventComponents.add(value)
elif index == 2: appEventActions.add(value)
for module in AppEventModule:
appEventModules.add(module.name)
for component in AppEventComponent:
if component.name.startswith('_'):
appEventComponents.add(component.name[1:])
else:
appEventComponents.add(component.name)
for action in AppEventAction:
appEventActions.add(action.name)
appEventModules = sorted(appEventModules)
appEventComponents = sorted(appEventComponents)
appEventActions = sorted(appEventActions)
}%
import Foundation
enum AppEventModule: String {
% for module in appEventModules:
case ${module}
% end
}
enum AppEventComponent: String {
% for component in appEventComponents:
% if component[0].isdigit():
case _${component} = "${component}"
% else:
case ${component}
% end
% end
}
enum AppEventAction: String {
% for action in appEventActions:
case ${action}
% end
}
when want to use map just to do iteration
use forEach instead
assert
https://developer.apple.com/documentation/swift/assert(_:_:file:line:)
assert(condition)
if condition is not true -> crashes on debug mode.
What is “==” when it’s reference type
That is what is written in equatable protocol’s method.
static func == (lhs: A, rhs: A) -> Bool {
}
To use “==” that type always needs to implement equatable.
For struct, if that type has only equatable properties, just writing “: equatable” makes the struct equatable. But for class, event though it only has equatable properties, you needs to implement “==” method to implement equatable.
How to not wait await function
Use Task
Task {
self.userActionsCount = try await UsersMeActionsCountRepository().count()
UserActionManager.shared.userActionsCount = userActionsCount
self.updateTitleAndObserve()
}
let result = try await EvaluationRepository().videoOrWebtoonContents(page: 0, size: size, unrated: false, isVideo: true) // <- this line executes not waiting UsersMeActionsCountRepository().count() function
Reference: https://stackoverflow.com/a/69846696
- But here’s a pitfall
do { Task { self.userActionsCount = try await UsersMeActionsCountRepository().count() //If a error occurs here, it's not catched UserActionManager.shared.userActionsCount = userActionsCount self.updateTitleAndObserve() } let result = try await EvaluationRepository().videoOrWebtoonContents(page: 1, size: size, unrated: false, isVideo: true) nextPage = result.nextPage let contents = result.cells contentActionCells = contents cellViewModels = cellViewModelsFromContents(contents) } catch { self.error = error }
optional 변수에 대한 flatMap
- 왜 flatMap이지? flatMap은 flat하게 만드는 기능이 있는 거 아니야?
- 맞음.
- 근데 flatMap에 또다른 기능이 있음. array가 아닐 때.
- optional한 애를 인자로 받아서, 또 안에서 연산을 통해 optional한 애로 리턴해줄 때임.
- optional하지 않다면(nil로 리턴해줄 일이 없다면) 그냥 map을 쓰면 됨. 근데 이때 유의점은 그냥 map을 써도 optional이긴 함
- 그럼 compactMap? 은 optional한 변수 자체에 대해서는 없는 기능임.
- 잠깐만 deprecated 됐던거 아니야?
- deprecated된건 compactMap처럼 optional element의 array일 때 사용되는 거. 이때는 flatMap을 써야 함.