<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Marco Longobardi on Medium]]></title>
        <description><![CDATA[Stories by Marco Longobardi on Medium]]></description>
        <link>https://medium.com/@marco.longobardi997?source=rss-90fff0c53699------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*kJsmCDXaMXSdylGEkBAzMg.png</url>
            <title>Stories by Marco Longobardi on Medium</title>
            <link>https://medium.com/@marco.longobardi997?source=rss-90fff0c53699------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Sat, 30 May 2026 09:18:51 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@marco.longobardi997/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Meet PaperKit, but with a working demo]]></title>
            <link>https://medium.com/@marco.longobardi997/meet-paperkit-but-with-a-working-demo-349e62e5587c?source=rss-90fff0c53699------2</link>
            <guid isPermaLink="false">https://medium.com/p/349e62e5587c</guid>
            <category><![CDATA[uikit]]></category>
            <category><![CDATA[apple]]></category>
            <category><![CDATA[swiftui]]></category>
            <category><![CDATA[ipad]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Marco Longobardi]]></dc:creator>
            <pubDate>Thu, 25 Sep 2025 18:13:17 GMT</pubDate>
            <atom:updated>2025-09-25T18:13:17.384Z</atom:updated>
            <content:encoded><![CDATA[<h4>Hands-on with Apple’s new PaperKit: UIKit and SwiftUI demo projects you can actually run</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*I2HHkdz1774yrtzBc1_BnQ.png" /><figcaption>Handwriting isn’t my strong suit</figcaption></figure><p>At the latest WWDC, Apple introduced a new framework called <strong>PaperKit</strong>, described in the documentation as:</p><blockquote>PaperKit builds on top of <a href="https://developer.apple.com/documentation/PencilKit">PencilKit</a> and <a href="https://developer.apple.com/documentation/PDFKit">PDFKit</a> to provide a consistent way to add drawing and shapes in your app.</blockquote><p>Having recently bought an <strong>iPad</strong> and being curious about how to make the most of the Apple Pencil, I immediately followed the session video to start testing what this new <strong>framework</strong> had to offer.</p><p><a href="https://www.youtube.com/watch?v=A31vmupv1eo&amp;t=96s&amp;pp=ygUOcGFwZXJraXQgc3dpZnQ%3D">WWDC25: Meet PaperKit | Apple</a></p><p>However, I quickly noticed a problem: there was no <strong>demo project</strong> provided along with the presentation, and the code shown in the video was rather ambiguous. On top of that, <strong>Apple’s documentation</strong> was not particularly clear. Overall, the introduction of this new framework felt a bit rushed and under-documented.</p><p>So, I decided to spend some time building demo projects for both <strong>UIKit</strong> and <strong>SwiftUI</strong>, so developers can have a proper starting point for experimenting with PaperKit.</p><h3>Issues in the Video</h3><p>The main issue with the UIKit implementation shown in the session was making the <strong>tool picker</strong> appear correctly. Using Apple’s suggested code, the toolkit wouldn’t show up, making it impossible to use the Pencil effectively.</p><p>To work around this, I used an implementation based on <strong>PencilKit</strong>, while waiting for Apple to release more details on this part of the API:</p><pre>let toolpicker = PKToolPicker()<br>toolpicker.colorMaximumLinearExposure = 4<br>toolpicker.setVisible(true, forFirstResponder: paperVC)<br>toolpicker.addObserver(paperVC)<br>paperVC.pencilKitResponderState.activeToolPicker = toolpicker<br>paperVC.pencilKitResponderState.toolPickerVisibility = .visible<br>paperVC.becomeFirstResponder()</pre><p>By combining <strong>PaperKit</strong> with <strong>PencilKit</strong>, I was able to achieve the desired result.</p><p>You can check out the <strong>UIKit demo project</strong> on GitHub:</p><p><a href="https://github.com/Longo97/PaperKit-UIKit-Demo">GitHub - Longo97/PaperKit-UIKit-Demo: A demo project that follows what was presented in Apple&#39;s video.</a></p><h3>SwiftUI Implementation</h3><p>As for the <strong>SwiftUI implementation</strong>, the video completely skipped over the details, leaving developers on their own to come up with a working demo.</p><p>Once I had a stable UIKit version, I ported the implementation to SwiftUI using a UIViewControllerRepresentable with a Coordinator, acting as a bridge between the two frameworks.</p><p>The code is not perfectly polished yet, but it works and lets you start experimenting with PaperKit.</p><p>You can find the <strong>SwiftUI demo project</strong> here:</p><p><a href="https://github.com/Longo97/PaperKit-Demo-SwftUI">GitHub - Longo97/PaperKit-Demo-SwftUI</a></p><h3>Conclusions</h3><p>Despite the rough start, <strong>PaperKit looks like a very promising framework</strong>. For now, we’ll just have to wait and see what updates Apple will release in the coming months.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=349e62e5587c" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Testing a Swift Package]]></title>
            <link>https://medium.com/@marco.longobardi997/testing-a-swift-package-08be3d166b75?source=rss-90fff0c53699------2</link>
            <guid isPermaLink="false">https://medium.com/p/08be3d166b75</guid>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[programming]]></category>
            <dc:creator><![CDATA[Marco Longobardi]]></dc:creator>
            <pubDate>Thu, 17 Jul 2025 10:49:09 GMT</pubDate>
            <atom:updated>2025-07-17T10:50:15.823Z</atom:updated>
            <content:encoded><![CDATA[<h4>How I Added Unit Tests and GitHub Actions to My Swift Package</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/907/1*ZRYOdabWoNVVeuGlm7GEwQ.png" /></figure><p>In the <a href="https://medium.com/@marco.longobardi997/swiftnetworking-building-and-publishing-a-lightweight-network-layer-with-spm-cbbf3f9adaee">previous article</a>, I introduced <strong>SwiftNetworking</strong>, a lightweight and reusable networking package built with <strong>Swift</strong> and distributed via <strong>Swift Package Manager (SPM)</strong>.</p><p><a href="https://github.com/Longo97/SwiftNetworking">GitHub - Longo97/SwiftNetworking: A lightweight and testable asynchronous REST client built with Swift and `async/await`</a></p><p>We explored how to modularize networking code, structure a Swift package, and publish it for other projects.</p><p>But building a package is just the beginning.</p><p>To make it truly reliable and production-ready, we need to ensure:</p><ul><li>Functionality is covered by <strong>automated unit tests</strong>;</li><li>Contributions go through a <strong>pull request</strong> review process;</li><li>Every commit to main is validated automatically using <strong>GitHub Actions</strong>.</li></ul><p>In this follow-up article, I’ll walk you through how I:</p><ul><li>Added unit tests to validate the core networking logic;</li><li>Created a <strong>custom mock protocol</strong> for controlled network simulation;</li><li>Set up <strong>CI workflows</strong> using GitHub Actions to automate testing.</li></ul><p>Whether you’re building your first Swift package or maintaining an open-source library, these steps will help ensure quality and maintainability.</p><h3>Unit Testing in Swift: A Quick Overview</h3><p>Swift provides a built-in testing framework called <strong><em>XCTest</em></strong>, which supports unit, integration, and UI testing. When working with Swift Packages, testing becomes even simpler thanks to native support from the Swift Package Manager (SPM).</p><p>A basic test target looks like this:</p><pre>Sources/<br>└── SwiftNetworking/<br>    └── NetworkProvider.swift<br><br>Tests/<br>└── SwiftNetworkingTests/<br>    ├── NetworkProviderTests.swift<br>    └── MockURLProtocol.swift</pre><p>Your test classes subclass <em>XCTestCase</em>, and use assertions like <em>XCTAssertEqual</em> and <em>XCTAssertThrowsError</em> to validate outcomes. You can run tests via Xcode or by using <strong>swift test</strong> in the terminal.</p><h3>Writing Unit Tests for SwiftNetworking</h3><p>Once the package was ready, I added a set of unit tests to validate the most critical features. One such test verifies that a valid <strong>JSON response </strong>is correctly <strong>decoded</strong> into a Swift model:</p><pre>/// ## testSuccessfulDecoding<br>/// Tests that the `NetworkProvider` correctly decodes a valid JSON response into a Decodable model.<br>///<br>/// The test ensures:<br>/// - The mocked JSON is returned and decoded properly.<br>/// - The decoded value matches the expected model.<br>  func testSuccessfulDecoding() async throws {<br>        let json = &quot;&quot;&quot;<br>        {<br>          &quot;message&quot;: &quot;Hello world&quot;<br>        }<br>        &quot;&quot;&quot;.data(using: .utf8)!<br>        <br>        MockURLProtocol.stubResponseData = json<br>        <br>        let config = URLSessionConfiguration.ephemeral<br>        config.protocolClasses = [MockURLProtocol.self]<br>        let session = URLSession(configuration: config)<br>        <br>        let baseURL = URL(string: &quot;https://api.example.com&quot;)!<br>        let network = NetworkProvider&lt;DefaultNetworkError&gt;(<br>            configuration: .init(baseURL: baseURL, session: session)<br>        )<br>        <br>        let endpoint = Endpoint(path: &quot;/greeting&quot;, method: .get)<br>        <br>        struct Response: Decodable {<br>            let message: String<br>        }<br>        <br>        let result: Response = try await network.send(endpoint, as: Response.self)<br>        XCTAssertEqual(result.message, &quot;Hello world&quot;)<br>    }</pre><p><strong>What This Test Verifies</strong></p><ul><li>A fake JSON is returned by a mocked session;</li><li>The network layer successfully decodes it into a Swift model;</li><li>No real API call is made;</li><li>The decoded value matches the expected content.</li></ul><h3><strong>Using MockURLProtocol for Isolated Network Testing</strong></h3><p>To simulate different network conditions without hitting a real API, I created a custom subclass of URLProtocol called <strong>MockURLProtocol</strong>.</p><p>Here’s its core implementation:</p><pre>final class MockURLProtocol: URLProtocol {<br>    static var stubResponseData: Data?<br>    static var error: Error?<br>    static var responseStatusCode: Int = 200<br><br>    override class func canInit(with request: URLRequest) -&gt; Bool { true }<br>    override class func canonicalRequest(for request: URLRequest) -&gt; URLRequest { request }<br><br>    override func startLoading() {<br>        if let error = Self.error {<br>            client?.urlProtocol(self, didFailWithError: error)<br>            return<br>        }<br><br>        if let data = Self.stubResponseData {<br>            client?.urlProtocol(self, didLoad: data)<br>        }<br><br>        let response = HTTPURLResponse(<br>            url: request.url!,<br>            statusCode: Self.responseStatusCode,<br>            httpVersion: nil,<br>            headerFields: nil<br>        )!<br>        client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)<br>        client?.urlProtocolDidFinishLoading(self)<br>    }<br><br>    override func stopLoading() {}<br>}</pre><h4>How to Use It</h4><p>During test setup, inject the mock protocol into a custom URLSession:</p><pre>let config = URLSessionConfiguration.ephemeral<br>config.protocolClasses = [MockURLProtocol.self]<br>let session = URLSession(configuration: config)</pre><p>This technique allows you to simulate:</p><ul><li>Successful responses;</li><li>Network errors (e.g., URLError.notConnectedToInternet);</li><li>Server-side failures like 500 Internal Server Error.</li></ul><p>All without touching the network.</p><h3>Setting Up GitHub Actions for CI</h3><p>To validate code on every commit or pull request, I configured GitHub Actions with a workflow like this:</p><pre>name: CI<br><br>on:<br>  push:<br>    branches: [main]<br>  pull_request:<br>    branches: [main]<br><br>jobs:<br>  test:<br>    runs-on: macos-13<br><br>    steps:<br>      - uses: actions/checkout@v3<br><br>      - name: Set up Xcode<br>        uses: maxim-lobanov/setup-xcode@v1<br>        with:<br>          xcode-version: &#39;15.2&#39;<br><br>      - name: Setup Swift<br>        uses: fwal/setup-swift@v1<br>        with:<br>          swift-version: &#39;5.8&#39;<br><br>      - name: Run tests<br>        run: xcodebuild test -scheme SwiftNetworking -destination &#39;platform=iOS Simulator,name=iPhone 14,OS=17.0&#39; -enableCodeCoverage YES -parallel-testing-enabled YES</pre><p>This workflow runs on macOS 13 with Xcode 15.2 and simulates an iOS 17 environment using an iPhone 14 simulator. It ensures all tests pass before merging any change into the main branch.</p><h3>Protecting the main Branch</h3><p>To enforce <strong>CI</strong> and <strong>code quality</strong>, I added branch protection rules on GitHub:</p><ol><li>Go to Settings &gt; Branches &gt; <strong>Branch Protection Rules</strong>;</li><li>Select main;</li><li>Enable:</li></ol><ul><li>✅ Require a pull request before merging;</li><li>✅ Require status checks to pass (CI must succeed);</li><li>✅ Optionally, require code review.</li></ul><p>Now, contributors must go through a proper review and testing pipeline — improving reliability and trust for all users.</p><h3>Wrapping Up</h3><p>In this article, I showed how to test the networking layer of your Swift package using XCTest and a custom MockURLProtocol. These tools allow you to simulate real-world network conditions in a fast and safe way — no actual API calls needed.</p><p>I also configured GitHub Actions to automatically run unit tests for every push and pull request on the main branch. This ensures the package stays stable and production-ready as it evolves.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=08be3d166b75" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[SwiftNetworking: Building and Publishing a Lightweight Network Layer with SPM]]></title>
            <link>https://medium.com/@marco.longobardi997/swiftnetworking-building-and-publishing-a-lightweight-network-layer-with-spm-cbbf3f9adaee?source=rss-90fff0c53699------2</link>
            <guid isPermaLink="false">https://medium.com/p/cbbf3f9adaee</guid>
            <category><![CDATA[mobile-app-development]]></category>
            <category><![CDATA[networking]]></category>
            <category><![CDATA[swift-package-manager]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[open-source]]></category>
            <dc:creator><![CDATA[Marco Longobardi]]></dc:creator>
            <pubDate>Thu, 10 Jul 2025 15:11:22 GMT</pubDate>
            <atom:updated>2025-07-10T15:11:22.529Z</atom:updated>
            <content:encoded><![CDATA[<h4>How I modularized my iOS network layer into an open-source Swift package</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*21A_Fh5rllJeeXw3FGqozA.png" /></figure><h3>Introduction</h3><p>As an iOS Engineer, I’ve often worked with external frameworks and packages. After some time, driven by curiosity, I decided to explore this topic more deeply, especially in the context of Swift. My main motivation was to move beyond the theoretical knowledge I had about package creation and get hands-on experience building one myself.</p><p>To make the process more concrete, I chose to use one of my personal projects — a football widget app <a href="https://apps.apple.com/it/app/versus-football-widgets/id6689520443"><strong>Versus</strong></a><strong> </strong>— and extract one of its core components that could be generalized and benefit from a more solid and testable structure: the Network Manager.</p><p>The result is SwiftNetworking: a Swift Package designed to provide a minimal, type-safe, asynchronous networking layer that is compatible with older iOS/macOS versions. I’ve made it open source so that others can dive into the topic, use it, or contribute improvements.</p><p><a href="https://github.com/Longo97/SwiftNetworking">GitHub - Longo97/SwiftNetworking: A lightweight and testable asynchronous REST client built with Swift and `async/await`</a></p><h3>What Is a Package?</h3><p>Before diving into how to build a Swift package, let’s clarify some key terms often encountered when dealing with code modularization:</p><ul><li><strong>Module</strong>: All iOS and macOS projects are composed of modules — reusable, isolated units of code. Swift Packages and Frameworks are examples of modules;</li><li><strong>Library</strong>: A type of module that contains a set of related classes. Libraries can be <strong>static</strong> (linked at build time) or <strong>dynamic</strong> (linked at runtime);</li><li><strong>Framework</strong>: A type of module that typically bundles resources, compiled code, and dependencies. It’s commonly used in Apple platforms;</li><li><strong>Swift Package</strong>: Similar to a library, but with built-in dependency and versioning support, making it easier to manage via Swift Package Manager (SPM).</li></ul><h3>Creating a Package in Xcode</h3><p>Thanks to Xcode, creating a package is quite simple. Just go to <strong>File &gt; New &gt; Package</strong>:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*fUg9hz3t9T-gMs5D2pfxug.png" /></figure><p>In the next window, you’ll choose whether to create a <strong>library</strong>, select the <strong>test framework</strong>, and define the <strong>name and location</strong> for the package.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*Oq_O22Fnjbh1Vqm982DqFw.png" /></figure><h3>Package Structure</h3><p>This is the basic file structure you’ll see once the package is created:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/456/1*AHOAfKdCMPJ5DOLtTAd-ZQ.png" /></figure><p>The Package.swift file is the manifest of the project and contains metadata about the package. Here&#39;s what you’ll typically find:</p><ul><li><strong>swift-tools-version</strong>: Defines the minimum version of Swift tools required;</li><li><strong>Products and Targets</strong>: A <strong>target</strong> is a module that can be imported. In the file system, it corresponds to a folder with source files;</li><li><strong>Platforms</strong>: Lists the minimum supported platform versions;</li><li><strong>Dependencies</strong>: Lists other packages this one depends on.</li></ul><h3>Package Content: The NetworkProvider</h3><p>Without going into every file in the repository, let’s focus on the core of SwiftNetworking: the NetworkProvider.</p><p>This class provides a generic, asynchronous network layer built on top of URLSession. It supports custom error mapping via a NetworkErrorConvertible protocol and is compatible with macOS 10.15 / iOS 13 and later.</p><blockquote><em>📌 You can find the full implementation in the GitHub repository.</em></blockquote><p>Here is the class definition:</p><pre>import Foundation<br><br>/// # NetworkProvider<br>/// A generic, asynchronous network client that sends requests using `URLSession` and decodes responses into strongly-typed models.<br>///<br>/// `NetworkProvider` supports:<br>/// - Custom decoding error mapping via a user-defined `NetworkErrorConvertible`<br>/// - Asynchronous networking with backward compatibility to macOS 10.15 / iOS 13<br>/// - Customizable configuration including base URL, session, and decoder<br>///<br>/// ## Generics<br>/// - `ErrorType`: A type conforming to `NetworkErrorConvertible`, used to map decoding and unknown errors into app-specific error cases.<br>///<br>/// ## Initialization<br>/// Create an instance by providing a `NetworkConfiguration`:<br>///<br>/// ```swift<br>/// let config = NetworkConfiguration(baseURL: URL(string: &quot;https://api.example.com&quot;)!)<br>/// let provider = NetworkProvider&lt;MyCustomError&gt;(configuration: config)<br>/// ```<br>///<br>/// ## Conforms to<br>/// - `NetworkClientProtocol`<br>///<br>/// ## Usage<br>/// Use the `send(_:as:)` method to make a network request and decode the response:<br>///<br>/// ```swift<br>/// struct Response: Decodable {<br>///     let message: String<br>/// }<br>///<br>/// let endpoint = Endpoint(path: &quot;/hello&quot;, method: .get)<br>/// let response: Response = try await provider.send(endpoint, as: Response.self)<br>/// print(response.message)<br>/// ```<br>///<br>/// ## Error Handling<br>/// - If the server returns an invalid status code, `HTTPResponseValidator` throws a validation error.<br>/// - If decoding fails, the error is mapped using `ErrorType.fromDecodingError(_:)`.<br>/// - Any unknown errors are mapped to `ErrorType.unknown`.<br>@available(iOS 13.0.0, *)<br>public final class NetworkProvider&lt;ErrorType: NetworkErrorConvertible&gt;: NetworkClientProtocol {<br>    private let configuration: NetworkConfiguration<br><br>    /// Initializes the `NetworkProvider` with a given network configuration.<br>    ///<br>    /// - Parameter configuration: The configuration that includes base URL, session, and decoder.<br>    public init(configuration: NetworkConfiguration) {<br>        self.configuration = configuration<br>    }<br><br>    /// Sends a request to the provided `Endpoint` and decodes the response into the expected type.<br>    ///<br>    /// - Parameters:<br>    ///   - endpoint: The `Endpoint` describing the path, method, headers, query, and body.<br>    ///   - type: The expected `Decodable` type for the response.<br>    /// - Returns: A decoded object of type `T`.<br>    /// - Throws:<br>    ///   - A `URLError` if networking fails.<br>    ///   - An error thrown by `HTTPResponseValidator` if status code is invalid.<br>    ///   - A mapped decoding error using `ErrorType.fromDecodingError`.<br>    ///   - `ErrorType.unknown` for unexpected decoding failures.<br>    @available(macOS 10.15, *)<br>    public func send&lt;T&gt;(_ endpoint: Endpoint, as type: T.Type) async throws -&gt; T where T: Decodable {<br>        let request = try endpoint.asURLRequest(baseURL: configuration.baseURL)<br>        let (data, response): (Data, URLResponse)<br><br>        if #available(macOS 12.0, *) {<br>            (data, response) = try await configuration.session.data(for: request)<br>        } else {<br>            // Fallback for macOS &lt; 12<br>            (data, response) = try await withCheckedThrowingContinuation { continuation in<br>                configuration.session.dataTask(with: request) { data, response, error in<br>                    if let error = error {<br>                        continuation.resume(throwing: error)<br>                    } else if let data = data, let response = response {<br>                        continuation.resume(returning: (data, response))<br>                    } else {<br>                        continuation.resume(throwing: URLError(.badServerResponse))<br>                    }<br>                }.resume()<br>            }<br>        }<br><br>        try HTTPResponseValidator.validate(response)<br><br>        LogUtilities.log(&quot;RESPONSE: \(String(data: data, encoding: .utf8) ?? &quot;Unable to decode data to string&quot;)&quot;)<br><br>        do {<br>            return try configuration.decoder.decode(T.self, from: data)<br>        } catch let decodingError as DecodingError {<br>            throw ErrorType.fromDecodingError(decodingError)<br>        } catch {<br>            throw ErrorType.unknown<br>        }<br>    }<br>}</pre><p>The goal of this package was to provide a networking layer that requires minimal setup to use. As it stands, the NetworkProvider only needs a configuration at initialization to be ready for use. Each call then takes an Endpointinstance to define the request.</p><h3>Defining an Endpoint</h3><p>The Endpoint struct encapsulates all the information needed to create a URLRequest: path, HTTP method, query parameters, headers, and body.</p><pre>import Foundation<br><br>/// Represents a REST API endpoint, encapsulating the URL path, HTTP method,<br>/// query parameters, headers, and optional body data.<br>///<br>/// This struct simplifies the creation of `URLRequest` objects by<br>/// constructing the full URL and encoding the request body if provided.<br>///<br>/// # Properties<br>/// - `path`: The URL path component appended to the base URL.<br>/// - `method`: The HTTP method to use (e.g., GET, POST). Defaults to `.get`.<br>/// - `query`: Optional query parameters as an array of `URLQueryItem`.<br>/// - `headers`: Optional HTTP headers as a dictionary `[String: String]`.<br>/// - `body`: Optional request body conforming to `Encodable`.<br>///<br>/// # Usage Example<br>/// ```swift<br>/// let endpoint = Endpoint(<br>///     path: &quot;/teams&quot;,<br>///     method: .post,<br>///     query: [URLQueryItem(name: &quot;season&quot;, value: &quot;2024&quot;)],<br>///     headers: [&quot;Authorization&quot;: &quot;Bearer TOKEN&quot;],<br>///     body: Team(name: &quot;Napoli&quot;, year: 1926)<br>/// )<br>/// ```<br>///<br>/// # Errors<br>/// Throws `DefaultNetworkError.cannotBuildURL` if the composed URL is invalid.<br>public struct Endpoint {<br>    /// The path component appended to the base URL.<br>    public let path: String<br>    <br>    /// The HTTP method used for the request.<br>    public let method: HTTPMethod<br>    <br>    /// Query parameters included in the URL.<br>    public let query: [URLQueryItem]?<br>    <br>    /// HTTP headers included in the request.<br>    public let headers: [String:String]?<br>    <br>    /// The body payload encoded as JSON, if provided.<br>    public let body: Encodable?<br>    <br>    /// Creates a new `Endpoint` instance.<br>    ///<br>    /// - Parameters:<br>    ///   - path: The URL path component (e.g., &quot;/teams&quot;).<br>    ///   - method: The HTTP method to use (default is `.get`).<br>    ///   - query: Optional query parameters to append to the URL.<br>    ///   - headers: Optional HTTP headers to include in the request.<br>    ///   - body: Optional request body conforming to `Encodable`.<br>    public init(path: String,<br>                method: HTTPMethod = .get,<br>                query: [URLQueryItem]? = nil,<br>                headers: [String: String]? = nil,<br>                body: Encodable? = nil) {<br>        self.path = path<br>        self.method = method<br>        self.query = query<br>        self.headers = headers<br>        self.body = body<br>    }<br>    <br>    /// Constructs a `URLRequest` from the endpoint and a base URL.<br>    ///<br>    /// - Parameter baseURL: The base URL to which the endpoint path and query are appended.<br>    /// - Returns: A configured `URLRequest` with method, headers, and body set.<br>    /// - Throws: `DefaultNetworkError.cannotBuildURL` if URL construction fails.<br>    internal func asURLRequest(baseURL: URL) throws -&gt; URLRequest {<br>        var components: URLComponents? = nil<br>        if #available(iOS 16.0, macOS 13.0, *) {<br>            components = URLComponents(url: baseURL.appending(path: path),<br>                                       resolvingAgainstBaseURL: false)<br>        } else {<br>            components = URLComponents(url: baseURL.appendingPathComponent(path),<br>                                       resolvingAgainstBaseURL: false)<br>        }<br>        <br>        components?.queryItems = query<br>        <br>        guard let components = components, let url = components.url else {<br>            throw DefaultNetworkError.cannotBuildURL<br>        }<br>        <br>        guard let scheme = url.scheme, let host = url.host, !scheme.isEmpty, !host.isEmpty else {<br>            LogUtilities.log(&quot;Invalid URL: \(url)&quot;)<br>            throw DefaultNetworkError.cannotBuildURL<br>        }<br>        <br>        var request = URLRequest(url: url)<br>        LogUtilities.log(&quot;Request URL: \(method.rawValue) \(url.absoluteString)&quot;)<br>        request.httpMethod = method.rawValue<br>        <br>        if let body = body {<br>            request.httpBody = try JSONEncoder().encode(body)<br>            request.setValue(&quot;application/json&quot;, forHTTPHeaderField: &quot;Content-Type&quot;)<br>            if let data = request.httpBody {<br>                LogUtilities.log(&quot;Body: \n\(String(data: data, encoding: .utf8) ?? &quot;Unable to convert body to string&quot;)&quot;)<br>            }<br>        }<br>        <br>        headers?.forEach { request.setValue($0.value, forHTTPHeaderField: $0.key) }<br>        <br>        return request<br>    }<br>}</pre><p>This approach makes body, query, and headers configuration entirely transparent to the user.</p><h3>Error Abstraction</h3><p>To allow for customized error handling, the package introduces a protocol called NetworkErrorConvertible. By extending this protocol, each project can define and handle its own business logic errors.</p><p>For convenience, the package includes a default implementation (DefaultNetworkError) that you can use if you don’t need advanced error mapping.</p><h3>Publishing the Package</h3><p>Once your package is working and ready for integration, it’s time to make it available via Swift Package Manager (SPM). Here’s how:</p><ol><li><strong>Create a Git repository</strong> — I used GitHub;</li><li><strong>Push your package code;</strong></li><li>Navigate to the repository’s main page and click <strong>“Create a new release”;</strong></li><li>Add a title and description for your release and — most importantly — create a <strong>tag</strong> (e.g., v1.0.0).</li></ol><p>This tag is what SPM will use to identify which commit/version of your package to use during integration.</p><p>To add the package to an Xcode project, use:<br>File &gt; Add Package Dependencies…,</p><p>then paste the repository URL:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*zrC4CpJ07rQhOtGpsa5U6w.png" /></figure><p>You can also specify the exact version tag, helping you avoid potential breaking changes from future updates.</p><h3>Conclusion</h3><p>Building SwiftNetworking has been a valuable learning experience. It allowed me to deepen my understanding of Swift Package Manager, modular architecture, and asynchronous networking in a clean and testable way.</p><p>If you’re working on iOS/macOS apps and want a lightweight, customizable networking solution, feel free to explore and integrate the package — or contribute to its development.</p><p>🔗 <a href="https://github.com/Longo97/SwiftNetworking">GitHub Repository — SwiftNetworking</a></p><p><strong>Coming soon:</strong> I’ll publish a follow-up article where I’ll cover how to add automated tests and set up GitHub workflows to validate all pushes to the main branch.</p><p>Happy coding! 🚀</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=cbbf3f9adaee" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Effortless WordPress Recovery: Streamlining Local Server Restoration with the WP-Duplicator-Docker…]]></title>
            <link>https://medium.com/@marco.longobardi997/effortless-wordpress-recovery-streamlining-local-server-restoration-with-the-wp-duplicator-docker-94ce30e8dadb?source=rss-90fff0c53699------2</link>
            <guid isPermaLink="false">https://medium.com/p/94ce30e8dadb</guid>
            <category><![CDATA[wordpress]]></category>
            <category><![CDATA[docker]]></category>
            <category><![CDATA[wordpress-web-development]]></category>
            <category><![CDATA[web-development]]></category>
            <category><![CDATA[backup]]></category>
            <dc:creator><![CDATA[Marco Longobardi]]></dc:creator>
            <pubDate>Mon, 06 Nov 2023 12:03:36 GMT</pubDate>
            <atom:updated>2023-11-06T12:03:36.116Z</atom:updated>
            <content:encoded><![CDATA[<h3>Effortless WordPress Recovery: Streamlining Local Server Restoration with the WP-Duplicator-Docker Script</h3><h4>A script that automates the creation of a local WordPress server based on a Duplicator backup using Docker</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*MpgIRau71qz3fvUB1fxqzg.png" /></figure><p>Have you ever found yourself in a situation where you wanted to test local changes for a website developed with WordPress? Or perhaps you had the desire to have a local backup of your site so that it’s always accessible? This process, especially when starting with a site that already has its own visual identity and structure, can become lengthy and complex. The script presented in this article aims to address this need by seeking to simplify this process as much as possible.</p><h3><strong>Prerequisites</strong></h3><p>The only prerequisite required to use the script is to have Docker installed on your system. Docker is a containerization platform that will be used to create the local server on which the site will be hosted. To install it, you can visit the following <a href="https://docs.docker.com/get-docker/">link</a>.</p><h3>Usage</h3><p>Once you’ve downloaded the script’s repository, you’ll need the files generated by the <strong>Duplicator</strong> plugin, namely the<strong> zip</strong> file and <strong>‘installer.php’</strong>. It’s essential for the script to function that the PHP file has the exact name ‘installer.php’. At this point, you just need to place these two files inside the <strong>‘Source’</strong> folder of the script’s directory and run it using the following shell command inside the script’s directory:</p><pre>source docker_wp_create.sh</pre><p>Now you only have to follow the prompts inside the terminal. Once the server is up and running the page to restore the Duplicator backup will open.</p><p>When you are asked to connect to the database, the values that you need to insert are:</p><ul><li><strong>Host:</strong> db</li><li><strong>Database:</strong> wordpress</li><li><strong>User:</strong> The user you choose inside the terminal (Default is admin)</li><li><strong>Password:</strong> The password you choose inside the terminal (Default is admin)</li></ul><p>You can see an example in the following image:</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*VQukNfHlLttNInaY.png" /></figure><p>At the end of the restore process, the site will be up and running locally, and the server files can be found inside a folder with the name you specified in the <strong>‘Projects’</strong> directory within the script’s folder. To create new sites, you can simply replace the Duplicator files inside the <strong>‘Source’</strong> folder.</p><p>You can find the script in the following <strong>repository</strong>:</p><p><a href="https://github.com/Longo97/WP-Duplicator-Backup-Local-Restore">GitHub - Longo97/WP-Duplicator-Backup-Local-Restore: A script that automates the creation of a local WordPress server based on a Duplicator backup using Docker.</a></p><p>For any issues or ideas regarding future developments, feel free to reach out to me.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=94ce30e8dadb" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How to set up an Xcode 16 project without Storyboard dependency]]></title>
            <link>https://medium.com/@marco.longobardi997/how-to-set-up-an-xcode-project-without-storyboard-dependency-d39fbe11a8f0?source=rss-90fff0c53699------2</link>
            <guid isPermaLink="false">https://medium.com/p/d39fbe11a8f0</guid>
            <category><![CDATA[xcode]]></category>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[storyboard]]></category>
            <category><![CDATA[apple]]></category>
            <category><![CDATA[swift]]></category>
            <dc:creator><![CDATA[Marco Longobardi]]></dc:creator>
            <pubDate>Mon, 09 Oct 2023 15:30:41 GMT</pubDate>
            <atom:updated>2025-03-26T08:48:04.007Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/0*n4ebkM9R9Dl5UJk8.png" /></figure><p>A <strong>storyboard</strong> is a <strong>graphical user interface (GUI)</strong> provided by Apple within the Xcode development environment. It’s a visual representation of an application’s user interface, allowing programmers to visually design and organize the various screens and views of the app. It provides a way to visually organize and connect different scenes, screens, and their respective elements such as buttons, labels, view controllers, and more. Its main features include:</p><ul><li>The ability to design individual <strong>scenes</strong>, representing specific screens or views of the app, and link these scenes to create the <strong>app’s flow</strong>;</li><li><strong>Segues</strong> define transitions between scenes based on specific actions;</li><li>Links can be created between interface elements in the storyboard and Swift code using <strong>outlets</strong> and <strong>actions</strong>.</li></ul><p>Everything that can be done within a storyboard can, of course, be replicated through code, but storyboards provide a simplified interface for creating them. However, this comes with disadvantages as the project complexity grows. These files tend to become larger and more complex, making it increasingly difficult to modify or add new parts. They also bring about challenges in resolving conflicts when multiple developers make simultaneous changes.</p><p>Given this, it’s not always certain that using storyboards in your project will lead to long-term benefits. Therefore, the steps to initialize a new Xcode project while removing the initial dependency on storyboards will now be listed.</p><h4>1. Create a new Xcode project</h4><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bIl3WbzZT61tj0DC_-qSnw.png" /></figure><p>When creating the new project, make sure to select <strong>Storyboard</strong> as Interface and <strong>Swift</strong> as Language.</p><h4>2. Change project settings</h4><p>Now, you have to remove the dependency onthe <strong>Main</strong> storyboard. First, inside your P<strong>roject Target &gt; Build Settings &gt; Info.plist Values</strong>, remove the <strong>UIKit Main Storyboard File Base Name</strong>. By default, it contains a reference to the <strong>Main</strong> storyboard.</p><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*bHe9I-Qe58fiHoAD9U93iA.png" /></figure><p>You are now free to delete the <strong>Main.storyboard</strong> file. The last thing to do inside the project settings is to update the <strong>info.plist</strong> file. You have to remove the <strong>Main.storyboard</strong> filename inside <strong>Information Property List &gt; Application Scene Manifest &gt; Scene Configuration &gt; Window Application Session Role &gt; Item 0 &gt; Storyboard Name</strong>.</p><h4>3. Update SceneDelegate</h4><p>When working with a storyboard, the window property is automatically initialized and the root view controllers are set as the initial view controller in the storyboard. When removing the storyboard, you will have to do it by yourself. This can be done inside the <strong>SceneDelegate.swift</strong> file, modifying the <strong>scene function:</strong></p><pre>func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {<br>        // Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.<br>        // If using a storyboard, the `window` property will automatically be initialized and attached to the scene.<br>        // This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).<br>        guard let windowScene = (scene as? UIWindowScene) else { return }<br>        let window = UIWindow(windowScene: windowScene)<br>        window.rootViewController = ViewController()<br>        window.makeKeyAndVisible()<br>        self.window = window<br>    }</pre><p>Now your project is ready to go! As we conclude this guide, remember that the choice of whether to use storyboards or not ultimately depends on the specific needs and scale of your project. Each approach has its merits and considerations. Whether you choose to stick with a purely programmatic interface or leverage the convenience of storyboards for certain aspects, the key is to make an informed decision based on the requirements and goals of your application.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=d39fbe11a8f0" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[PodsAnalyzer: A script to collect all the infos about installed CocoaPods]]></title>
            <link>https://medium.com/@marco.longobardi997/podsanalyzer-a-script-to-collect-all-the-infos-about-installed-cocoapods-1195a5a56b2c?source=rss-90fff0c53699------2</link>
            <guid isPermaLink="false">https://medium.com/p/1195a5a56b2c</guid>
            <category><![CDATA[ios]]></category>
            <category><![CDATA[swift]]></category>
            <category><![CDATA[cocoapods]]></category>
            <category><![CDATA[gdpr-compliance]]></category>
            <category><![CDATA[gdpr]]></category>
            <dc:creator><![CDATA[Marco Longobardi]]></dc:creator>
            <pubDate>Mon, 25 Sep 2023 14:36:39 GMT</pubDate>
            <atom:updated>2023-09-27T09:20:54.427Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*pwFjuPH7qJqgkVTRQJvjzg.jpeg" /></figure><p>In recent months, there has been much talk about the latest updates to the <strong>GDPR</strong> and how these could affect the world of Open Source. If you’ve never heard this term before, the <strong>General Data Protection Regulation (GDPR)</strong> is a comprehensive and strict data privacy and protection law enacted by the European Union (EU). It is designed to strengthen and unify data protection for individuals within the EU and addresses the export of personal data outside the EU and EEA areas. GDPR regulates how organizations collect, use, process, and store personal data, imposing requirements to ensure individuals’ privacy rights and control over their data. Naturally, this regulation also impacts the world of <strong>app development</strong>, so it’s important to be well-prepared on the subject. Among the various things to consider to deem an app fully GDPR compliant is the necessity to display various information regarding all the <strong>third-party libraries</strong> that have been used for the development of our app. Collecting and displaying this data can be a long and tedious task, especially for iOS applications that use <strong>CocoaPods</strong>. To simplify your life, I’ve developed this small Python script, <strong>PodsAnalyzer</strong>, which will automate the collection of this information.</p><p><strong>PodsAnalyzer</strong> allows you to analyze the installed CocoaPods in the project, providing a <strong>Property List (Plist)</strong> file as output containing information for each pod. To do this, it uses the <strong>CLI command <em>pod spec</em></strong>, iterating through all the pods in the project and producing an output file containing the following information for each pod:</p><ul><li><strong>Name</strong></li><li><strong>Version</strong></li><li><strong>License</strong></li><li><strong>Git Source</strong></li></ul><figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*YikDXKocHdZaplbLIkPYtA.png" /><figcaption>An example of the resulting output</figcaption></figure><p>This file can be easily imported into the project to then display the required information.</p><p>You can find the script in the following <strong>repository</strong>:</p><p><a href="https://github.com/Longo97/PodsAnalyzer">GitHub - Longo97/PodsAnalyzer: This script allows you to analyze the installed CocoaPods in the project, providing a Property List (Plist) file as output containing information for each pod.</a></p><p>In the <strong>README</strong> file, you’ll find a guide on how to use the script.</p><p>For any issues or ideas regarding future developments, feel free to reach out to me.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1195a5a56b2c" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>