๐ŸŽ
ios.dev
ios.dev
  • ๐ŸŽios.dev
    • ๐Ÿ› ๏ธtools
    • ๐Ÿ“ฐNews
    • ๐Ÿ“…Events
      • WWDC22
    • ๐Ÿ”ฒtodo
      • ๐Ÿ“–to read ...
      • ๐Ÿงช็ ”็ฉถไธญ ...
        • Formatter
        • Dependency Injection
        • ๐Ÿ”ธNever
        • ๐ŸงชGoogle Sheet as JSON
      • ๐Ÿ’ˆExamples
        • ๐Ÿ’ˆMonthView
        • ๐Ÿ’ˆCircleText
        • ๐Ÿ’ˆCollapsible
      • ๐Ÿ““่ชฒ็จ‹็ญ†่จ˜
        • ๐Ÿ“šSwiftUI Tutorials
          • Tutorials โŸฉ Model
          • Tutorials โŸฉ Views
          • Tutorials โŸฉ Extensions
        • ๐Ÿ“šSwift Animation Mastery
          • Triggers
            • ๐Ÿ’ˆexample โŸฉ Picker
            • ๐Ÿ’ˆexample โŸฉ SubButtons
        • Emoji Memory Game ๐Ÿ“š
        • ่จญ่จˆๅก็‰‡ ๐Ÿ“š
          • ๆŽ’็‰ˆ
          • ๅ…ƒไปถๅŒ–
          • ่จญๅฎšๅ‹•็•ซ
          • ่จญๅฎšๆ‰‹ๅ‹ข
          • ๅ‹•็•ซ็š„ๅฑฌๆ€ง
        • ๆ–ฐๆ“ฌ็‰ฉ้ขจ (Neumorphic Design)
          • ๆผธๅฑค่จญ่จˆ
            • Neu ๐Ÿ”ธ
          • ๅก็‰‡่จญ่จˆ
            • NeuCard ๐Ÿ“ฆ
          • ๆŒ‰้ˆ•่จญ่จˆ
            • IconCard ๐Ÿ“ฆ
            • ButtonUp, ButtonDown ๐Ÿ“ฆ
          • ่จญ่จˆ้€ฒๅบฆๆข
            • NeuProgressBarTitle ๐Ÿ“ฆ
            • MyProgressBar2 ๐Ÿ“ฆ
            • NeuProgressBar2 ๐Ÿ“ฆ
      • ่‡ช่จ‚ๅž‹ๅˆฅ
        • @KilometersPerHour
        • ๐ŸถPlaygroundConsole
        • ๐Ÿ‘”EmojiTextFieldStyle
        • ๐ŸŒ…Outlined
        • ๐ŸŒ…BlurView
        • ๐ŸŒ… SystemImage
        • ๐ŸŒ… Fit
        • ๐ŸŒ… Unwrap
        • โœจCustom Circle
    • ๐Ÿ”ฐtemplates
      • ๐Ÿ—’๏ธpage template
    • ๐Ÿงชlab
    • ๐Ÿ”ฐterms
      • ๐Ÿ”ฐroles
        • ๐Ÿ”ธimplementer
        • ๐Ÿ”ธuser
      • ๐Ÿ”ธstate
      • ๐Ÿ”ธdata separation
      • ๐Ÿ”ธdata model
      • ๐Ÿ”ธsource of truth
      • ๐Ÿ”ธuser interaction
      • ๐Ÿ”ธuser interface
  • โญfeatures
    • โญSwift
      • โญ๏ธ Swift 5.6
        • any
        • type placeholders
      • โญ๏ธ Swift 5.7
    • โญSwiftUI
      • โญSwiftUI 4.0
    • โญXcode
      • Xcode 14
    • โญiOS
      • โญ๏ธ iOS 15
        • โญ๏ธ Live Text
      • โญ๏ธ iOS 16
    • Global Variables
    • Destructuring
    • Variadic Parameter
    • autoclosure
    • ๐Ÿ”ฐKey Path
      • Key Path Expressions as Functions
    • Calling Types As Functions
  • ๐Ÿ‘”custom
    • ๐ŸŒ€extension
      • ๐ŸŒ€View+
        • ๐Ÿ‘”view.if(_:then:)
        • ๐Ÿ‘”view.if(let:then:)
        • ๐Ÿ‘”view.inverseMask()
        • ๐Ÿ‘”view.overlayText()
        • ๐Ÿ‘”view.resizableFont()
        • ๐Ÿ‘”view.watermark()
        • ๐Ÿšซview.foreground()
      • ๐ŸŒ€Color+
        • ๐ŸŒ€system colors
          • ๐Ÿ–ผ๏ธSystemColorsView
          • ๐Ÿ–ผ๏ธSwatch_0
        • ๐ŸŒ€Color.rgb()
        • ๐ŸŒ€color.hue
      • ๐ŸŒ€Gradient+
        • ๐ŸŒ€Gradient.linear()
        • ๐ŸŒ€Gradient + View
      • ๐ŸŒ€Image+
        • ๐ŸŒ€Image(playground:)
      • ๐ŸŒ€Formatter+
      • ๐ŸŒ€RoundedRectangle+
      • ๐ŸŒ€Text+
        • ๐ŸŒ€Text(symbol:)
    • ๐Ÿ”ฐsnippets
      • ๐Ÿ’พview + previews
      • ๐Ÿ’พview modifier (template)
    • ๐ŸŽpackage
      • ๐Ÿ“•ๅฆ‚ไฝ•่‡ช่ฃฝ Swift package
      • ๐Ÿ›๏ธGeometryKit
        • ๐Ÿ…ฟ๏ธMetricSpace
        • ๐Ÿ…ฟ๏ธVector
        • ๐Ÿ…ฟ๏ธComplexNumber
        • ๐Ÿ…ฟ๏ธVector2D
        • ๐Ÿ…ฟ๏ธFrame
    • ๐Ÿ…ฟ๏ธprotocol
      • ๐Ÿ…ฟ๏ธRepeatable
    • ๐Ÿ–ผ๏ธview
      • ๐Ÿ‘”HLine / VLine
      • ๐Ÿ‘”Swatch
      • ๐Ÿ‘”ShapeStyleView
    • ๐ŸŽ›๏ธcontrol
      • ๐ŸŽ›๏ธSlidersForSize
      • ๐ŸŽ›๏ธSliderWithLabel
  • ๐ŸฆSwift
    • ๐ŸŽฒmath functions
      • abs()
      • .rounded()
      • .squareRoot()
      • pow()
    • ๐Ÿ”ฐscope
      • ๐Ÿ”ธglobal scope
      • ๐Ÿ”ธlocal scope
      • ๐Ÿ”ธmodule
      • ๐Ÿ”นimport
      • ๐Ÿ”ธframework
        • ๐Ÿงฉbuilt-in frameworks
          • ๐ŸงฉFoundation
            • ๐Ÿ“ฆCalendar
            • ๐Ÿ“…Date
              • .sevenDaysOut
              • Date.from(year:month:day:)
              • Date.roundedHoursFromNow(hours)
            • ๐Ÿ“ฆURL
              • ๐ŸŒ€ URL+ext
              • .isImage
            • ๐Ÿ—ƒ๏ธFileManager
              • ๐ŸŒ€ FileManager+ext
              • .documentDirectory
            • ๐ŸŽBundle
            • ๐Ÿ…ฟ๏ธFormatStyle
          • ๐ŸงฉCore Graphics
            • ๐ŸŒ€CGRect
              • rect.inset(by:)
            • ๐ŸŒ€CGSize
            • ๐ŸŒ€CGVector
            • ๐ŸŒ€CGPoint
          • ๐ŸงฉSpriteKit
          • ๐ŸงฉCombine
            • ๐Ÿ…ฟ๏ธPublisher
              • ๐ŸถFuture
              • ๐Ÿ“ฆURLSession.DataTaskPublisher
            • โš™๏ธ Promise
            • ๐Ÿ”ธResult
            • โฐTimer
              • โœจcancellable timer
              • ๐Ÿ‘”TimerView
              • ๐Ÿ‘”TimerView (scheduledTimer)
          • ๐ŸงฉAVFoundation
          • ๐ŸงฉSwift Charts
          • ๐ŸงฉMetal
          • ๐ŸงฉWeatherKit
    • โž•operator
      • ๐Ÿ”ธcompound assignment operator
      • โœ–๏ธCharacter * Int
      • โœ–๏ธa^^n
      • โž•ternary conditional operator (a ? b : c)
    • ๐Ÿ€type
      • ๐Ÿ€type category
        • ๐Ÿ€basic types
          • โœ…Bool
            • .iOS14
          • โ‰๏ธOptional
            • optional binding
            • optional chaining
            • nil coalescing
            • compare with Optional
          • ๐Ÿ”คString
            • ๐Ÿ”ฐString Interpolation
              • Custom String Interpolation
              • Expressible by String Interpolation
              • specifier / formatter
            • ๐Ÿ“ฆAttributedString
            • ๐Ÿ˜ƒEmojis
            • String.Index
            • str.capitalized
            • str.split()
            • str.trim()
            • str[i], str[i..<j], str[i...j]
            • str.pad()
          • ๐Ÿ“ฆInt
          • ๐Ÿ“ฆArray
            • ๐ŸŒ€arr.split(size:)
            • ๐ŸŒ€arr.first()
            • arr.split(where:)
            • arr.index(of:)
            • arr.allElementsEqual
            • .allElementsSameLength
          • ๐Ÿ“ฆenum
            • โญComparable Enums
            • compound cases
            • ๐Ÿ’กfilter cases
            • ๐Ÿ’ก็”จ enum ๅฐ่ฃไธๅŒๅž‹ๅˆฅ
          • ๐Ÿšฅtuple
          • ๐Ÿ”ฐfunction
            • ๐Ÿ”ธdefault parameter
            • ๐Ÿ”ธargument label
            • ๐Ÿ”ธreturn value
              • #๏ธdiscardable result
            • ๐Ÿ”ฐfunction as variable
            • ๐Ÿ”ฐfully qualified name
          • ๐Ÿ”ฐclosure
            • ๐Ÿ”ฐclosure expression
            • ๐Ÿ”ฐescaping closure
          • ๐Ÿ„class
            • ๐Ÿ”ฐweak self
          • ๐Ÿ”ขNumbers
            • ๐Ÿ…ฟ๏ธFloatingPoint
              • ๐ŸŒ€floating +โˆ’โจ‰รท int
              • .decimalPlaces()
            • ๐Ÿ…ฟ๏ธBinaryFloatingPoint
              • .binaryBitPattern
              • ๐Ÿ–ผ๏ธBinaryBitPatternView
            • ๐Ÿ…ฟ๏ธBinaryInteger
              • .binary(digits:)
            • range.contains()
          • โš–๏ธstruct vs. class
        • ๐Ÿ…ฟ๏ธprotocol
          • ๐Ÿ”ฐprotocol inheritance
            • ๐Ÿ”ฐprotocol hierarchy
            • ๐Ÿšซcan't change builtin hierarchy
          • ๐Ÿ”ฐprotocol requirements
          • ๐Ÿ”ดProtocol Extensions
          • ๐Ÿ”ฐgeneric protocol
            • ๐Ÿ“˜some, any
          • ๐Ÿ”ฐassociated type
          • ๐Ÿ”ดConditional Conformance
          • ๐Ÿ”ดCombining Protocols
          • ๐Ÿ”ฐTypecasting with Protocols
          • โš ๏ธretroactive conformance
          • ๐Ÿ…ฟ๏ธAny
          • ๐Ÿ…ฟ๏ธComparable
            • .clamped(in:)
          • ๐Ÿ…ฟ๏ธHashable
          • ๐Ÿ…ฟ๏ธIdentifiable
          • ๐Ÿ…ฟ๏ธCaseIterable+ext
          • ๐ŸŽฌPOP ไป‹็ดน
          • ExpressibleByLiteral
        • โš–๏ธsomeโ•ฑanyโ•ฑgenerics
          • ๐Ÿ”ธsome (opaque type)
          • ๐Ÿ”ธany (boxed protocol type)
        • ๐Ÿ€nested types
          • extension of nested types
          • โ“to nest or not to nestโ“
        • ๐Ÿ€generics
          • โš ๏ธgenerics & subtypes
          • โ—specialize generic function
          • โ“default type parameter
        • ๐Ÿ€non-nominal types
      • ๐Ÿ”ฐproperty
        • ๐Ÿ”ธpublic property
        • ๐Ÿ”ธstored property
          • ๐Ÿ”ธproperty observer (willSet/didSet)
        • ๐Ÿ”ฐcomputed property (get/set)
          • local computed variables
          • mutating getter / nonmutating setter
        • โš–๏ธstored vs. computed
        • โš–๏ธwillSet/didSet vs. get/set
        • ๐Ÿ”ฐproperty wrapper
          • โœจClamped
          • โœจTrimmed
          • โœจUnitInterval
      • ๐Ÿฃinheritance
        • ๐Ÿ”ธSelf
      • ๐Ÿ”ฐtype alias
      • ๐Ÿ”ฐextension
        • extension of typealiasโ“
      • โญimplicit return
      • ๐Ÿ”ฐtype erasure
      • ๐Ÿ”ฐinitialization
        • ๐Ÿ”ฐinitializers
          • ๐Ÿ”ธrequired initializer
        • ๐Ÿ”ฐclass initializer inheritance
          • ๅ…ฉ้šŽๆฎตๅˆๅง‹ๅŒ–
          • ่‡ชๅ‹•็นผๆ‰ฟๅˆๅง‹ๅŒ–็จ‹ๅบ
    • ๐Ÿ”ฐstatement
      • ๐Ÿ“˜do
      • ๐Ÿ”คsemicolon (;)
      • ๐Ÿ”ฐsimple statement
        • ๐Ÿ”ฐexpression
          • ๐Ÿ”ฐprimary expressions
        • ๐Ÿ”ฐdeclaration
      • ๐Ÿ”ฐcompiler control statement
    • ๐Ÿ”ฐflow control
      • ๐Ÿ”„loop
        • ๐Ÿ“˜for...in
        • ๐Ÿ”ฐfor...in vs. forEach
      • ๐Ÿ”€branch
        • ๐Ÿ“˜if
        • ๐Ÿ“˜guard
        • ๐Ÿ”นswitch
      • โ†ฉ๏ธcontrol transfer
        • ๐Ÿ“˜break
        • ๐Ÿ“˜continue
        • ๐Ÿ“˜return
        • ๐Ÿ“˜throw
        • ๐Ÿ“˜fallthrough
    • ๐Ÿ”ฐCollections
      • ๐Ÿ…ฟ๏ธSequence
        • seq.forEach()
        • seq.reduce(_:_:)
        • seq.reduce(into:_:)
        • reduce() vs. reduce(into:)
        • seq.grouped(by:)
        • seq.sorted()
        • seq.sorted(by:)
        • seq.sorted(_:)
        • seq.foldMap(_:_:)
        • seq.stateMap(_:_:)
        • seq.sum
      • ๐Ÿ…ฟ๏ธCollection
        • collection[safe: index]
        • collection.allElementsEqual
        • collection.allElementsSameLength
        • collection.lengthsOfElements
        • collection.columnWidths
      • ๐Ÿ…ฟ๏ธIteratorProtocol
      • ๐Ÿ…ฟ๏ธOptionSet
      • Collection Types
    • ๐Ÿ”ฐSubscripts
      • Subscripts with Default Arguments
    • ๐Ÿ”ฐAttributes
      • โญResult Builders
        • result-building methods
        • various result types
        • result builder transform
        • custom result-builder attributes
    • ๐Ÿ”ฐPattern Matching
      • ๐Ÿ”ดSentence Patterns
        • ... as! ...
        • (... as? ...)?.method()
        • if let ... as?
        • if/guard case let
        • for case let ... where
        • switch case
        • switch case is ...
        • switch case let ... where
        • switch case let ... as
        • switch on other types
      • operator (~=)
      • enum case pattern
    • ๐Ÿ”ฐExceptions
    • ๐Ÿ›๏ธStandard Library
      • ๐Ÿ…ฟ๏ธCodable
    • ๐Ÿ”ฐConcurrency
      • ๐Ÿ…ฟ๏ธSendable
        • ๐Ÿžhas non-Sendable type
    • ๐Ÿ”ฐFile System
    • ๐Ÿ”ฐNetworking
    • ๐ŸžDebugging
      • ๐Ÿ”ฎMirror
        • Mirror.handleChildren()
      • ๐Ÿ‘”Logger
      • ๐Ÿ‘”HasMirrors
      • ๐Ÿ‘”log()
      • ๐Ÿ‘”CaseReflectable
      • ๐Ÿ‘”NonNominalTypeWrapper
      • Metatype
    • ๐Ÿ”ฐInput/Output
    • ๐Ÿ”ฐRegex
    • ๐Ÿ”ฐAccess Control
  • ๐Ÿ”ฐSwiftUI
    • ๐Ÿ”ฐSwiftUI terms
      • ๐Ÿ”ธbuilt-in view
    • ๐Ÿ”ฐintroduction
      • SwiftUI Essentials
    • ๐Ÿšฉapp
      • ๐Ÿ…ฟ๏ธApp
      • ๐Ÿ”ฐscenes
        • ๐Ÿ…ฟ๏ธScene
      • ๐Ÿ”ฐwindows
        • ๐Ÿ“ฆWindowGroup
    • ๐Ÿ”ฐviews
      • ๐Ÿ”ฐview hierarchy
        • ๐Ÿ”ธcontainer view
        • ๐Ÿ”ธcomposed view
        • ๐Ÿ”ธroot view
        • ๐Ÿ”ธchild view
        • ๐Ÿ”ธparent view
        • ๐Ÿ”ธdestination view
      • ๐Ÿ”ฐview state
        • ๐Ÿ”ธstate value
          • ๏ผ State
            • ๐Ÿ”ฐinit State
            • โœจdynamic underline
        • ๐Ÿ”ธstate object
          • @StateObject
        • ๐Ÿ”ธobservable object
          • ๐Ÿ…ฟ๏ธObservableObject
          • ๐Ÿ”ธpublished value
          • ๐Ÿ”ธobserver
          • @Published
        • ๐Ÿ”ฐanimate state changes
        • ๐Ÿ”ธbinding
          • ๏ผ Binding
            • ๐Ÿ”ฐBinding State
            • ๐Ÿ”ฐBinding from StateObject
            • ๐Ÿ”ฐinit Binding
            • โ—return Binding
      • ๐Ÿ”ฐview layout
        • ๐Ÿ”น.padding( )
        • ๐Ÿ”ดPosition
        • ๐Ÿ”ธframe
          • ๐ŸŒ€view + .frame()
          • ๐Ÿ”น.frame()
            • โœจTestIdealSizeView
            • โœจTestFrameView
        • ๐Ÿ”ธview size
          • ๐Ÿ”ดSize Classes
          • ๐Ÿ”ดDynamic Type Sizes
            • ๐ŸŒ€DynamicTypeSize+ext
          • ๐Ÿ”ธideal size
        • ๐ŸŽstacks
          • ๐Ÿ“ฆZStack
          • ๐Ÿ‘”AdaptiveHStack
          • ๐Ÿ‘”StackForEach
        • ๐ŸŽgrids
          • ๐Ÿ“ฆLazyVGrid
            • ๐Ÿ–ผ๏ธStandardGradientGrid
          • ๐ŸŸ grid layout algorithm
          • ๐Ÿ“ฆGridItem
            • ๐Ÿ”ฐadaptive column
            • ๐Ÿ”ฐflexible column
            • โœจNColumns
          • ๐Ÿ‘”VGridForEach
            • โœจTestLittleSquares
          • ๐Ÿ‘”ScrollVGridForEach
            • โœจTestSVGFE
          • โœจGrids โŸฉ examples
            • โœจSmileys
            • โœจGrid
              • ๐Ÿ“ฆGridLayout
            • โœจMyGrid
              • โ›”Generic parameter '...' could not be inferred.
            • ๐Ÿžproblem with .readSize()
            • โœจItemsView
              • ๐Ÿ–ผ๏ธTestItemsView
              • ๐Ÿ“ฆRatioRetainingLayout
              • ๐ŸŽ›๏ธSizeRatioControl
              • ๐Ÿ…ฟ๏ธIndexedGridLayout
        • Adaptive Layout
        • Alignment
          • Implicit Alignment
          • Custom Alignment within ZStack
          • ๐Ÿ”ฐๅ„็จฎๅฐ้ฝŠ (alignment)
        • ๐ŸŒฟLayout โŸฉ Types
          • ๐Ÿ“ฆTimelineView
        • โ›”Cannot convert value of type 'Self' to expected argument type 'Binding<C>'
      • ๐Ÿ”ฐview actions
        • ๐Ÿ”ฐdelete item from list
        • ๐Ÿ”ฐadd item to list
      • ๐Ÿ”ฐview environment
        • ๐Ÿ”ธenvironment object
        • ๐Ÿ”ธenvironment value
          • ๐Ÿ“ฆdismiss
        • @Environment
          • .editMode
        • @EnvironmentObject
      • ๐Ÿ”ฐview groupings
        • ๐Ÿ–ผ๏ธForEach
          • ๐Ÿ”น.onDelete
          • โš–๏ธList vs. ForEach
          • โœจForEach examples
      • ๐Ÿ”ฐnavigation
        • ๐Ÿ”ธnavigation bar
        • ๐Ÿ“ฆNavigationStack
        • ๐Ÿ“ฆNavigationSplitView
        • ๐Ÿ“ฆNavigationLink
      • ๐Ÿ”ฐview modifier
        • โœจexamples
          • .nsfw()
          • .roundedBorder()
          • .neumorphic()
        • ๐Ÿ”ฐadd modifiers to Xcode
        • ๐Ÿ”ฐconditional modifier
        • ๐Ÿ”ฐlayout modifier
        • ๐Ÿ”ฐrendering modifier
        • ๐Ÿ”ฐadjusting text
        • ๐Ÿ…ฟ๏ธViewModifier
      • ๐Ÿ”ฐdrawing views
        • ๐Ÿ”ธforeground
          • ๐Ÿ”ธforeground element
          • ๐Ÿ”ธforeground style
            • ๐Ÿ”นview.foregroundStyle()
            • ๐Ÿ”นShapeStyle.foreground
        • ๐Ÿ”ธbackground
          • ๐Ÿ”ธbackground style
          • ๐Ÿ”น.background()
        • ๐Ÿ”ธblend mode
          • โœจ.destinationOut
        • ๐Ÿ”ธmask
          • ๐Ÿ”นview.mask()
        • ๐Ÿ”ธshadow
          • ๐Ÿ”ฐcontainer + shadow
          • ๐Ÿ“ฆShadowStyle
          • ๐Ÿ”นview.shadow()
        • ๐Ÿ”นview.clipShape()
          • ๐Ÿžmismatching types
        • ๐Ÿ”นveiw.compositingGroup()
      • ๐Ÿ”ฐmeasuring views
        • ๐Ÿ“ฆGeometryProxy
          • ๐ŸŒ€GeometryProxy+ext
        • ๐Ÿ“ฆ GeometryReader
          • ๐Ÿ”ฐGeometryReader ็š„ๅฐ้ฝŠๆ–นๅผ
      • ๐Ÿ”ฐConfiguring Views
      • ๐Ÿ”ฐevents
        • ๐Ÿ”น.allowsHitTesting()
      • ๐Ÿ“ฆViewBuilder
        • ViewBuilder transforms
        • support for stored properties
      • ๐Ÿ”ฐOptional Views
      • ๐Ÿ…ฟ๏ธView
        • .dimension()
          • ๐ŸŒ€Path+
          • ๐Ÿ‘”DimensionPositions
          • ๐Ÿ‘”WidthDimension
          • ๐Ÿ‘”HeightDimension
          • ๐Ÿ‘”LeftArrow
          • ๐Ÿ‘”LeftArrowShape
          • ๐Ÿ‘”UpArrow
          • ๐Ÿ‘”UpArrowShape
        • id(_:)
        • .badge()
        • .border(), .borderLeft() ...
        • .hideIf()
        • .logType()
        • .getSize()
        • .grids()
        • .offset()
        • .onChangeSize()
        • .onDrag
        • โŒ.readSize()
        • resizableFont()
        • .show(if:)
        • .shadowedBorder()
        • .testFrame()
        • view.actOnSelfWidth()
      • ๐Ÿ“ฆLink
      • ๐Ÿ”ฐSwipe Actions
      • ๐Ÿ”ฐ3D transform
      • โญLive Activites
      • ๐Ÿ”ฐlife cycle
    • ๐Ÿ”ฐstyles
      • ๐Ÿ”ธcurrent style
    • ๐Ÿ”ฐlists
      • ๐Ÿ“ฆList
        • ๐Ÿ…ฟ๏ธListStyle
        • โญlist background color
    • ๐ŸŽ›๏ธcontrols
      • ๐Ÿ”ฐpickers
        • ๐ŸŽ›๏ธPicker
        • ๐ŸŽ›๏ธDatePicker
      • ๐Ÿ”ฐtoolbar
      • ๐Ÿ”ฐFocusState
      • ๐Ÿ“ฆDivider
      • ๐Ÿ“ฆText
        • ๐Ÿ“ฆFont
          • ๐Ÿ”ฐcustom font
        • ๐Ÿ”ฐtext formats
          • ๐Ÿ”ธno wrap
        • ๐Ÿ”ฐMarkdown
        • โ“math equationsโ“
        • โญnumber of lines
      • ๐Ÿ“ฆImage
        • ๐Ÿ”นimage.renderingMode()
        • ๐Ÿ”ธtemplate image
        • ๐Ÿ”ฐSF Symbols
        • ๐Ÿ„ImageRenderer
      • ๐Ÿ“ฆLabel
        • Label Styles
          • Label โŸฉ custom styles
      • ๐Ÿ“ฆGroupBox
      • ๐Ÿ“ฆControlGroup
      • ๐Ÿ“ฆSection
      • ๐Ÿ“ฆScrollView
      • โญShareLink
      • ๐ŸŽ›๏ธButton
        • ๐Ÿ”ฐButton Roles
        • ๐Ÿ”ฐButton Styles
          • ๐Ÿ…ฟ๏ธPrimitiveButtonStyle
          • ๐Ÿ”ฐButton with Materials
          • Button โŸฉ custom styles
      • ๐ŸŽ›๏ธEditButton
      • ๐ŸŽ›๏ธProgressView
      • ๐ŸŽ›๏ธTextField
        • TextField โŸฉ formats
          • โœจ.currency
        • TextField โŸฉ styles
          • textField.style(_:)
      • ๐ŸŽ›๏ธToggle
        • ๐Ÿ”ฐToggle Styles
      • ๐ŸŽ›๏ธSecureField
      • ๐ŸŽ›๏ธSlider
        • ๐Ÿ”ฐSlider label position
      • ๐ŸŽ›๏ธGauge
    • ๐Ÿ”ฐshapes
      • ๐Ÿ”ฐtransform shape
        • ๐Ÿ”นshape.stroke()
          • ๐ŸŒ€StrokeStyle
          • โœจMarchingAnts
      • ๐Ÿ’ˆๆญฃๅœ“่ฎŠๆˆๆญฃไบ”้‚Šๅฝข
      • ๐Ÿ…ฟ๏ธShape
        • ๐Ÿ“ฆAnyShape
        • ๐Ÿ”ธfill
          • โœจeven-odd fill mode
          • .evenOddFill
        • ๐ŸŒ€Shape + ext
          • shape.outlined()
        • โœจRoundedCorners
        • โœจHelper Shapes
          • ๐Ÿ’œLineShape
          • ๐Ÿ’œGridLinesShape
          • ๐Ÿ–ผ๏ธGridLines
          • ๐Ÿ–ผ๏ธLine
          • ๐Ÿ–ผ๏ธPin
          • ๐Ÿ–ผ๏ธPoint
        • โœจSports Car in Sunset
          • ๐Ÿ’œVehicle.CarBodyShape
          • ๐Ÿ–ผ๏ธVehicle
        • ๐Ÿ‘”Polygon
      • ๐Ÿ…ฟ๏ธShapeStyle
        • ๐Ÿ“ฆColor
          • ๐Ÿ”ธcolor.gradient
          • ๐Ÿ”ฐTheme
        • ๐Ÿ“ฆGradient
        • ๐Ÿ“ฆImagePaint
        • โ™ฆ๏ธ.shadow()
        • .white()
        • ShapeStyle+LinearGradient
        • ๐Ÿ“ฆMaterial
      • ๐Ÿ”ฐMatched Geometry Effect
        • โœจMGE โŸฉ animation
      • ๐Ÿ“ฆPath
        • path.fit()
        • path.line()
        • path.transform
      • ๐Ÿ“ฆCanvas
      • ๐Ÿ“ฆAnchor<T>
    • ๐ŸŽcontainer
      • ๐ŸŽcollection
      • ๐ŸŽlayout
        • โญGrid
        • โญViewThatFits
        • โญAnyLayout
        • โญLayout
      • ๐ŸŽpresentation
        • โญbottom sheet
        • ๐ŸŽTabView
          • โœจtabs with tag
    • ๐Ÿšฆdata flow
      • ๐ŸšฅPreferences
        • ๐Ÿ‘”ViewPreference
        • ๐Ÿ…ฟ๏ธPreferenceKey
          • FirstNonNil<T>
          • AllValues<T>
          • MaxValue<T>
        • ๐ŸšฅAnchor Preferences
        • โœจPreferences โŸฉ examples
          • โœจviews with same width
            • .reportWidth() ...
          • โœจselected button with underline
    • ๐ŸŽ๏ธanimations
      • ๐Ÿ”ฐimplicit vs. explicit
      • ๐Ÿ…ฟ๏ธAnimatable
        • ๐Ÿ…ฟ๏ธGeometryEffect
        • ๐Ÿ”ธAnimatable Modifiers
          • โœจ.tapToShake()
      • ๐Ÿ“ฆAnimation
      • ๐Ÿ”ฐdelay
      • ๐Ÿ”ธAnimation Curves
        • ๐Ÿ”ธBezier Curves
        • easeInOutExp
      • โœจAnimations โŸฉ examples
        • โœจSpinner
        • โœจWheel of Fortune
        • โœจLoading Indicators
      • ๐Ÿ”ฐTransitions
        • ๐Ÿ”ฐcustom transitions
        • ๐Ÿ“ฆAnyTransition
          • AnyTransition.combined()
        • โœจtransition โŸฉ scale
        • โœจcombining transitions
    • ๐Ÿ‘†Gestures
      • ๐Ÿ”ฐupdate gesture states
      • ๐Ÿ”ฐupdate view states
      • ๐ŸšฅGestureState
      • ๐Ÿ‘†Long Press
      • ๐Ÿ‘†Drag
        • ๐Ÿ‘”.draggable()
          • ๐Ÿ–ผ๏ธHandlePoint
      • ๐Ÿ”ฐCombining Gestures
        • ๐Ÿ‘†.sequenced()
          • โœจlong press + drag
    • ๐Ÿ”ฐPresentations
      • ๐Ÿ”ฐLaunch Screen
      • ๐Ÿ”ฐExternal Screens
      • ๐Ÿ”ฐRefreshable Views
      • ๐Ÿ”ฐAlert
      • ๐ŸŽ›๏ธConfirmation Dialog
    • ๐Ÿ”ฐDebugging in SwiftUI
    • ๐ŸŽนkeyboard
    • ๐Ÿ”ฐfor mac
    • ๐Ÿšซdeprecated
      • ๐ŸŽNavigationView
        • .navigationViewStyle(_:)
  • ๐ŸŽ›๏ธwidgets
  • ๐ŸŽData Structures
    • Graph
      • Tree
  • ๐Ÿง Algorithms
    • Searching
      • Binary Search
    • Hashing
    • Sorting
      • sort using key paths
      • ranking list
      • Merge Sort
    • Filtering
    • Path Finding
      • A*
  • โ›ฑ๏ธSwift Playgrounds
    • Playground Book
      • Structuring Content
    • ๆช”ๆกˆ็ตๆง‹
      • ๐Ÿ’พManifest.plist
    • ไฝฟ็”จๆจก็ต„
    • ๐Ÿ“šLearn to Code 2
      • ๅž‹ๅˆฅ
        • ๐Ÿ”ธCharacterName
        • ๐Ÿ„NodeWrapper
        • ๐Ÿ‘”ItemID
        • ๐Ÿ…ฟ๏ธLearn to Code 2 โŸฉ Animatable
        • ๐Ÿ…ฟ๏ธItem
        • ๐Ÿ„Actor
        • ๐Ÿ„Expert
        • ๐Ÿ„Portal
      • ้—œๅก
        • Variables
          • ๆชขๆŸฅ็›ธ็ญ‰ๅ€ผ
          • ่จˆ็ฎ—้–‹้—œๆ•ธ้‡
          • ๆ”ถ้›†็ธฝๆ•ธ
        • Types
          • ้–‹ๅ•Ÿ่ˆ‡้—œ้–‰ๅ‚ณ้€้–€
          • ้—œ้–‰ๅ‚ณ้€้–€
        • ๅ‰ต้€ ไธ–็•Œ
    • ็ทจ็ขผ็คพ็พค
    • Swift Playgrounds Subscription
  • ๐ŸฅAudio / Video
    • .speak()
    • Language Tags
  • โ›”Errors
    • โ›”CompileDylibError: Failed to build XXX.swift
    • โ›”Fatal error: String index is out of bounds
    • โŒInternal error: missingPackageDescriptionModule
    • โŒArgument type 'xxx' does not conform to expected type '_FormatSpecifiable'
    • โ›”๏ธ escaping closure captures mutating 'self' parameter
    • โ“iPad/iPhone is Busy: Fetching debug symbols for ...
    • โ“Class _PointQueue is implemented in both ...
    • โ›”Protocol '...' can only be used as a generic constraint because it has Self or associated type
    • โ›”non-nominal type `...` cannot be extended
    • โ›”cannot assign value of type 'T' to type 'T'
  • ้™„้Œ„
    • ๐ŸงฉSwift Package
      • Package.swift
      • version number
      • Swift Package Index
      • 3rd party packages
    • ๐Ÿ”ฐDesign Patterns
      • MVC
      • MVVM
      • DIP
    • ๐Ÿ› ๏ธXcode
      • ๐Ÿ”ฐbuild schemes
      • ๐Ÿ”งInstruments
      • ๐Ÿค–Compiler Directives
        • @available, #available
        • #if ... #else ... #endif
        • #file, #line, #function
      • ๐ŸŽนshortcuts
      • ๐Ÿ”ฐDocumentation
        • ๐Ÿ”ฐDocC
      • Source Control
        • Merge
      • Preview
        • Preview Devices
      • App Icon
      • Simulator
    • ๐Ÿ’ผProjects
    • โœ…Testing System
      • โœ…Swift Testing
      • โœ…XCTest
        • XCTAssertEqual (==)
        • XCTUnwrap
      • Fixtures
    • Prototyping
    • ๐Ÿ’กTips
      • iOS version
      • Swift version
    • JSON
      • Load JSON
    • Terms
      • reachability
    • ๅ…ถไป–
      • ๅพ…่งฃๅ•้กŒโ“
      • ๆธฌ่ฉฆ็”จ ๐Ÿงช
      • ้—œๆณจๅฐ่ฑก
      • ้‡่ฆ่ชž้Œ„
      • ๅœ–ไพ‹
    • ้›œ่จ˜ ๐Ÿ“ฅ
      • ๐Ÿ“ฆMeasurement
      • Replicating Types in Swift
      • ๅญ—ๅž‹ๅฐˆๆœ‰ๅ่ฉž
      • State Machine
Powered by GitBook
On this page

Was this helpful?

  1. Swift
  2. Debugging

Logger

PreviousMirror.handleChildren()NextHasMirrors

Last updated 3 years ago

Was this helpful?

๐Ÿ’พ ็จ‹ๅผ๏ผš โฌ†๏ธ ้œ€่ฆ๏ผš str.pad(), collection.columnWidths

// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// 2022.01.27 * (v.1) + line, spaces, prefixDoubleSlash, log, underline, doubleline, debug
// 2022.01.28 / line()       replace "-" by "โ”€" (longer dash), 
//            r line()       renmaed to "_line()"
//            / log()        `dot`: Bool -> String?
//            + line()       draw line 
//            + topline()    line on top of message
//            + error()      error message
// 2022.01.29 + codeBlock()  `///` prefixed code block
//            + table()      draw a table for 2D data
// 2022.01.30 / table()      + param options: TableOptions
//            / table()      + return value (Bool), + @discardableResult
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// #todo: โ–  โ–ก โ–จ 
// - table()     + โ–  dot  โ–ก vertical borders  โ–ก vertical grid lines
// - codeBlock() + โ–ก padding before code  โ–ก comments after code

// import Extensions            // for String + .pad()

// โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
// โ”‚    Logger    โ”‚
// โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

public struct Logger {
    public static var prefixDoubleSlash = false
}

// helper
extension Logger {
    /// `Logger.line(3) == "-" * 3 == "---"` 
    static func _line  (_ n: Int) -> String { return "โ”€" * n }
    /// `Logger.spaces(3) == " " * 3 == "   "`
    static func spaces(_ n: Int) -> String { return " " * n }
}

extension Logger {
    public struct TableOptions: OptionSet {
        
        public let rawValue: Int
        
        public init(rawValue: Int) {
            self.rawValue = rawValue
        }
        
        // โญ๏ธ unit sets (containing only one element)
        public static let dot    = TableOptions(rawValue: 1 << 0)
    }
}

extension Logger {
    
    /// `Logger.log(msg)`
    public static func log(
        _ message: String = "", 
        padding n: Int = 0,
        dot: String? = nil
    ) {
        let prefix = prefixDoubleSlash ? "// " : ""
        let padding = spaces(n)
        let dotted = (dot == nil) ? "" : "\(dot!) "
        print(prefix + padding + dotted + message)
    }
    
    /// `Logger.error(msg)`
    public static func error(
        _ message: String = "", 
        padding n: Int = 0
    ) {
        Logger.log(message, padding: n, dot: "โ›”")
    }
    
    /// `Logger.line(n)`
    public static func line(_ n: Int, padding p: Int = 0) {
        log(Logger._line(n), padding: p)
    }
    
    /// `Logger.box(title)`
    public static func box(_ title: String, padding: Int = 4) {
        let w = title.count + padding * 2
        let line = "โ”€" * w
        let spaces = " " * padding
        
        Logger.log("โ”Œ" + line + "โ”")
        Logger.log("โ”‚" + spaces + title + spaces + "โ”‚")
        Logger.log("โ””" + line + "โ”˜")
    }
    
    /// `Logger._drawline(msg)`
    static func _drawline(
        _ message : String, 
        length   n: Int? = nil,         // line length
        padding  p: Int  = 0,           // padding on both sides of message
        topline   : Bool = false,       // draw top line
        bottomline: Bool = true         // draw bottom line
    ) {
        let defaultLength = message.count + p * 2
        let line = Logger._line(n ?? defaultLength)
        let padding = spaces(p)
        
        if topline { log(line) }
        log(padding + message + padding)
        if bottomline { log(line) }
    }
    
    /// `Logger.underline(msg)`
    public static func underline(_ message: String, length n: Int? = nil, padding p: Int = 0) {
        _drawline(message, length: n, padding: p)
    }
    
    /// `Logger.doubleline(msg)`
    public static func doubleline(
        _ message: String, 
        length  n: Int? = nil,         // line length
        padding p: Int  = 4,           // padding on both sides of message
        newline  : Bool = true         // newline before message
    ) {
        if newline { log() }           // new line
        _drawline(message, length: n, padding: p, topline: true)
    }
    
    /// `Logger.topline(msg)`
    public static func topline(
        _ message: String, 
        length  n: Int? = nil,         // line length
        padding p: Int  = 0            // padding on both sides of message
    ) {
        _drawline(message, length: n, padding: p, topline: true, bottomline: false)
    }
    
    /// `Logger.debug(msg)`
    public static func debug(
        _ message: String  = "",
        file     : String  = #file,         // โญ file name
        line     : Int     = #line,         // โญ line number
        function : String  = #function,     // โญ function name
        note     : String? = nil            // additional info
    ) {
        let msgStr = "๐Ÿž \(message)"
        let funcStr = "func: '\(function)'"
        let lineStr = "line: \(line)"
        let fileStr = "file: '\(file)'"
        let debugInfo = "   [\(funcStr), \(lineStr), \(fileStr)]"
        
        log()
        log(msgStr)
        log(debugInfo)
        if let note = note { log(note) }
    }
    
    /// print a `///` + ```-delimited code block to console.
    /// #todo: + 1. padding before code, 2. comments after code
    public static func codeBlock(_ code: [String]) {
        print("/// ```")
        code.forEach { print("/// " + $0) }
        print("/// ```")
    }
    
    /// log a table of data
    @discardableResult
    public static func table(
        _ data: [[String]], 
        padding p: Int = 2, 
        alignments: [Int:String.PadAlign] = [:],
        options: TableOptions = []
    ) -> Bool {
        // ๐ŸŒ€ Collection+
        guard let w = data.columnWidths else {
            return false        // Logger.table() failed
        }
        
        // all widths + spacing
        var lineLength = w.reduce(0, +) + (w.count) * 2 * p
        if options.contains(.dot) { lineLength += 1 + p }        // + (padding) + (dot) on left-side of 1st cell
        
        let hr = "โ”€" * lineLength        // horizontal line
        let padding = " " * p
        
        // table top border
        Logger.log(hr)
        
        // for each row in the data
        for i in data.indices {
            var line = ""
            let row = data[i]
            // dot before each line
            let dotted = options.contains(.dot) 
                ? padding + (i == 0 ? " " : "๐Ÿ”ธ")    // header without dot
                : ""
            // for each string in the row
            for j in row.indices {
                let str = row[j]        // string in cell
                let width = w[j]        // cell width
                let align = i == 0 ? .center : alignments[j+1] ?? .left    // header is always centered
                // ๐ŸŒ€ String+
                let cell = str.pad(width: width, align: align)             // padded cell
                // padding on both sides of each cell
                line += padding + cell + padding
            }
            line = dotted + line
            Logger.log(line)
            if i == 0 { Logger.log(hr) }    // header line
        }
        
        // table bottom border
        Logger.log(hr)

        return true         // Logger.table() successful
    }
}
func testLogger() {
    
    Logger.log("log message prefixed with a `dot`.", dot: "๐Ÿ”ธ")
    Logger.debug("`debug` info from Logger.")

    // topline, underline, doubleline
    Logger.topline("`topline`")
    Logger.doubleline("`doubleline` without a newline before it.", newline: false)
    Logger.doubleline("`doubleline` (defalult: newline before it)")

    // box
    Logger.box("`box`")

    // table
    Logger.box("(dotted) table")
    Logger.table(MockData.persons, 
        alignments: [2: .right, 3: .center], 
        options: [.dot]
    )

    let data = [["a"],["b","c"]]

    // failed Logger.table()
    let successful = Logger.table(data)
    if !successful {
        Logger.debug("Rows have different lengths or empty data.")
        Logger.log("data = \(data)", dot: "๐Ÿ”ธ")
        Logger.log("lengths of rows = \(data.lengthsOfElements)", dot: "๐Ÿ”ธ")
    }
}

Result:

// ๐Ÿ”ธ log message prefixed with a `dot`.
// 
// ๐Ÿž `debug` info from Logger.
//    [func: 'testLogger()', line: 4, file: 'test/testLogger.swift']
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// `topline`
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
//     `doubleline` without a newline before it.    
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// 
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
//     `doubleline` (defalult: newline before it)    
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
// โ”‚    `box`    โ”‚
// โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
// โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
// โ”‚    (dotted) table    โ”‚
// โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
//      Name     Age       Type     
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
//   ๐Ÿ”ธ  Joe        8       Boy      
//   ๐Ÿ”ธ  May       24    Young Lady  
//   ๐Ÿ”ธ  Peter    123     Old Man    
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// 
// ๐Ÿž Rows have different lengths or empty data.
//    [func: 'testLogger()', line: 25, file: 'test/testLogger.swift']
// ๐Ÿ”ธ data = [["a"], ["b", "c"]]
// ๐Ÿ”ธ lengths of rows = [1, 2]
  • #file, #line, #function

  • used by HasMirrors.

  • .logType() - inspect a view's type.

  • Logger.TableOptions is an OptionSet.

  • Mirror.handleChildren()

  • log()

History

  1. (2022.01.25) * (v.1) as a global function.

  2. (2022.01.28) + topline(), error()

// ----------------------
//     โญ log function 
// ----------------------

func log(
    _ message: String  = "",
    file     : String  = #file,         // โญ file name
    line     : Int     = #line,         // โญ line number
    function : String  = #function,     // โญ function name
    note     : String? = nil            // additional info
) {
    let noteString = (note == nil) ? "" : "\n \(note!)" 
    print("\n๐Ÿ“ \(message)\n ( func: '\(function)', line: \(line), file: '\(file)' )\(noteString)")
}
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
// 2022.01.27 * (v.1) + line, spaces, prefixDoubleSlash, log, underline, doubleline, debug
// 2022.01.28 - line: replace "-" by "โ”€" (longer dash), renamed "_line"
//            / log(dot:): `dot`: Bool -> String?
//            + line (draw line), topline (line on top of message)
//            + error(msg)`
// โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€

// โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
// โ”‚    Character * Int    โ”‚
// โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

/// `"-" * 3 == "---"`
func * (a: Character, n: Int) -> String {
    return String(repeating: a, count: n)
}

// โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
// โ”‚    Logger    โ”‚
// โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

public struct Logger {
    public static var prefixDoubleSlash = false
}

// helper
extension Logger {
    /// `Logger.line(3) == "-" * 3 == "---"` 
    static func _line  (_ n: Int) -> String { return "โ”€" * n }
    /// `Logger.spaces(3) == " " * 3 == "   "`
    static func spaces(_ n: Int) -> String { return " " * n }
}

extension Logger {
    
    /// `Logger.log(msg)`
    public static func log(
        _ message: String = "", 
        padding n: Int = 0,
        dot: String? = nil
    ) {
        let prefix = prefixDoubleSlash ? "// " : ""
        let padding = spaces(n)
        let dotted = (dot == nil) ? "" : "\(dot!) "
        print(prefix + padding + dotted + message)
    }
    
    /// `Logger.error(msg)`
    public static func error(
        _ message: String = "", 
        padding n: Int = 0
    ) {
        Logger.log(message, padding: n, dot: "โ›”")
    }
    
    /// `Logger.line(n)`
    public static func line(_ n: Int, padding p: Int = 0) {
        log(Logger._line(n), padding: p)
    }
    
    /// `Logger.box(title)`
    public static func box(_ title: String, padding: Int = 4) {
        let w = title.count + padding * 2
        let line = "โ”€" * w
        let spaces = " " * padding
        
        Logger.log("โ”Œ" + line + "โ”")
        Logger.log("โ”‚" + spaces + title + spaces + "โ”‚")
        Logger.log("โ””" + line + "โ”˜")
    }
    
    /// `Logger._drawline(msg)`
    static func _drawline(
        _ message : String, 
        length   n: Int? = nil,         // line length
        padding  p: Int  = 0,           // padding on both sides of message
        topline   : Bool = false,       // draw top line
        bottomline: Bool = true         // draw bottom line
    ) {
        let defaultLength = message.count + p * 2
        let line = Logger._line(n ?? defaultLength)
        let padding = spaces(p)
        
        if topline { log(line) }
        log(padding + message + padding)
        if bottomline { log(line) }
    }
    
    /// `Logger.underline(msg)`
    public static func underline(_ message: String, length n: Int? = nil, padding p: Int = 0) {
        _drawline(message, length: n, padding: p)
    }
    
    /// `Logger.doubleline(msg)`
    public static func doubleline(
        _ message: String, 
        length  n: Int? = nil,         // line length
        padding p: Int  = 4,           // padding on both sides of message
        newline  : Bool = true         // newline before message
    ) {
        if newline { log() }           // new line
        _drawline(message, length: n, padding: p, topline: true)
    }
    
    /// `Logger.topline(msg)`
    public static func topline(
        _ message: String, 
        length  n: Int? = nil,         // line length
        padding p: Int  = 0            // padding on both sides of message
    ) {
        _drawline(message, length: n, padding: p, topline: true, bottomline: false)
    }
    
    /// `Logger.debug(msg)`
    public static func debug(
        _ message: String  = "",
        file     : String  = #file,         // โญ file name
        line     : Int     = #line,         // โญ line number
        function : String  = #function,     // โญ function name
        note     : String? = nil            // additional info
    ) {
        let msgStr = "๐Ÿ“ \(message)"
        let funcStr = "func: '\(function)'"
        let lineStr = "line: \(line)"
        let fileStr = "file: '\(file)'"
        let debugInfo = "   [\(funcStr), \(lineStr), \(fileStr)]"
        
        log()
        log(msgStr)
        log(debugInfo)
        if let note = note { log(note) }
    }
}

๐Ÿ’พ ็จ‹ๅผ๏ผš

Ficow Shen โŸฉ

Swift Ref โŸฉ Expressions โŸฉ โŸฉ Literal Expression

- custom log function using โญ๏ธ

๐Ÿ’พ ็จ‹ๅผ๏ผš

๐Ÿฆ
๐Ÿž
๐Ÿ‘”
replit
replit
Swift ไธญ็š„ #function ๅˆฐๅบ•ๆ˜ฏไป€ไนˆ๏ผŸ
Primary Expressions
Weird value of #function literal in Swift 3.1
Macros in Swift?
#file, #line, #function
replit