{"id":17279510,"url":"https://github.com/devmeremenko/easycalls","last_synced_at":"2025-04-14T09:30:17.878Z","repository":{"id":56909697,"uuid":"123794717","full_name":"devMEremenko/EasyCalls","owner":"devMEremenko","description":"A number of methods over Swift API to use it safely.","archived":false,"fork":false,"pushed_at":"2018-08-02T14:00:29.000Z","size":68,"stargazers_count":9,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-04-13T15:42:05.369Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/devMEremenko.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-03-04T14:09:07.000Z","updated_at":"2020-05-06T10:38:42.000Z","dependencies_parsed_at":"2022-08-20T20:20:39.154Z","dependency_job_id":null,"html_url":"https://github.com/devMEremenko/EasyCalls","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devMEremenko%2FEasyCalls","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devMEremenko%2FEasyCalls/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devMEremenko%2FEasyCalls/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/devMEremenko%2FEasyCalls/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/devMEremenko","download_url":"https://codeload.github.com/devMEremenko/EasyCalls/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248854036,"owners_count":21172281,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-15T09:17:50.046Z","updated_at":"2025-04-14T09:30:17.839Z","avatar_url":"https://github.com/devMEremenko.png","language":"Swift","funding_links":[],"categories":[],"sub_categories":[],"readme":"# EasyCalls\n\n![Build Status](https://travis-ci.org/devMEremenko/EasyCalls.svg?branch=master)\n[![codecov.io](https://codecov.io/github/devmeremenko/EasyCalls/coverage.svg?branch=master)](https://codecov.io/github/devmeremenko/EasyCalls?branch=master)\n[![codebeat badge](https://codebeat.co/badges/9a996a4d-e42e-43b7-ba9a-d18c4d361409)](https://codebeat.co/projects/github-com-devmeremenko-easycalls-master)\n[![Version](https://img.shields.io/cocoapods/v/EasyCalls.svg?style=flat)](http://cocoapods.org/pods/EasyCalls)\n[![Platform](https://img.shields.io/cocoapods/p/EasyCalls.svg?style=flat)](http://cocoapods.org/pods/EasyCalls)\n[![GitHub license](https://img.shields.io/github/license/devmeremenko/EasyCalls.svg)](https://github.com/devMEremenko/EasyCalls/blob/master/LICENSE)\n[![GitHub forks](https://img.shields.io/github/forks/devmeremenko/EasyCalls.svg)](https://github.com/devmeremenko/EasyCalls/network)\n[![GitHub stars](https://img.shields.io/github/stars/devmeremenko/EasyCalls.svg)](https://github.com/devmeremenko/EasyCalls/stargazers)\n\n\n### Hi there,\n\nThis repository contains a number of methods over Swift API to use it safely. \u003cbr /\u003e\n\n#### Contents\n\n- [`DispatchQueue` management ](#queues)\n- [`Swift` errors handling](#swift-errors-handling)\n- [`Realm`. Safe write and read transactions](#realm)\n- [`UIAlertController` easiest presentation](#uialertcontroller)\n\n## Queues\n\nThese methods are used to dispatch execution to the specified queue.\n\n```swift\nDispatchQueue.toMain {\n    // update UI\n}\n\nDispatchQueue.toBackground {\n    // load data\n}\n\nDispatchQueue.runAfter(time: 1) {\n    // performs work on the main queue after 1 sec\n}\n```\n\nCustomization\n\n```swift\nDispatchQueue.toBackground(qos: .utility) { // Separate queue }\n\nDispatchQueue.toBackground(label: \"\",\n              qos: .background,\n              attr: .concurrent,\n              frequency: .inherit,\n              target: DispatchQueue.global()) { // Separate queue }\n```\n\n```swift\nDispatchQueue.runAfter(time: 1) { // Main thread }\n\nDispatchQueue.runAfter(time: 1, qos: .userInteractive) { // Separate queue }\n\nDispatchQueue.runAfter(time: 1,\n              qos: .userInteractive,\n              attr: .concurrent,\n              frequency: .inherit,\n              target: DispatchQueue.global()) { // Separate queue }\n```\n\n## DispatchQueue.toMain \u003cbr /\u003e\n`DispatchQueue.toMain` call safely dispatches execution to the main queue.\u003cbr /\u003e\u003cbr /\u003e\nSince being on the main thread does not guarantee to be on the main queue, the `DispatchQueue.toMain` call checks whether the current queue is main. The operations of the main queue are always executed on the main thread.\u003cbr /\u003e\nAs described in the [libdispatch](https://github.com/apple/swift-corelibs-libdispatch/commit/e64e4b962e1f356d7561e7a6103b424f335d85f6), `dispatch_sync` performs work on the current queue. It can cause a situation when the main queue will wait for completion of another sync operation.\n\nHere is an example when the main thread is able to execute operations **from other queues**:\n\n```swift\nDispatchQueue.main.async {\n    // Main Queue\n    DispatchQueue(label: \"\").sync {\n        // Background Queue\n        \n        if Thread.isMainThread {\n            // The thread is Main, but the current queue is NOT Main.\n            // UI should NOT be updated here.\n            \n            // The 'DispatchQueue.toMain' call prevents this situation.\n        }\n    }\n}\n```\n\nTo sum up, `DispatchQueue.toMain` guarantees that the passed block will be executed on the main queue and, therefore, on the main thread.\nIn addition, if the current queue and thread are not main, the operation will be synchronously added to the main queue to prevent a race condition.\n\n\n## DispatchQueue.toBackground\n`DispatchQueue.toBackground` asynchronously dispatches an execution to the separate queue with `default` QoS.\n\n## DispatchQueue.runAfter\nThe `DispatchQueue.runAfter(time: 1)` call performs a block on the main queue after the passed time.\u003cbr /\u003e\nHowever, `runAfter(time: qos:)` with specified `QoS` performs the given block on the **separate queue**. Do not update UI on it.\n\n## Swift Errors Handling\n\nThe syntactic sugar methods help to make the code more clear.\n\n```swift\ntryCatch({\n    try call()\n})\n```\n\n```swift\ntryCatch({\n    try call()\n    try anotherCall()\n}) { error in\n    // handle an error\n}\n```\n\nThese are simple wrappers over the Optional type.\n\n```swift\nif error.isExist {\n    // handle\n}\n\nif error.isNil {\n    // success\n}\n```\n\n## Realm\n\n```swift\nRealm.read(transaction: { realm in\n    // use realm\n})\n\nRealm.write(transaction: { realm in\n    // use realm\n})\n```\nThe safe write transaction:\n- returns the default realm instance\n- contains an **autorelease pool** to prevent an uncontrolled increase of the file size of database.\nIt might happen if objects are created inside of a GCD operation. The GCD only drains the queue-level autorelease pools relatively infrequently which can result in the lifetimes of Realm objects being significantly longer.\n- updates Realm objects to the most recent data at the end of transaction.\n\nThe *error handling* is also supported by attaching an `error` closure.\n\n## UIAlertController\n\nThere is a number of calls to present `UIAlertController` (including `ActionSheet`)\u003cbr /\u003e\n* it is implemented as an extension for `UIViewController`\n* uses `DispatchQueue.toMain` under the hood to guarantee a presentation on the main queue\n* parameters of the `show()` method can be combined in different ways\n\n```swift\n// Alert\nshow(title: \"Title\", actions: Action.ok)\n\n// ActionSheet\nshow(title: \"Action Sheet\", style: .actionSheet, actions: Action.ok)\n```\n\n```swift\n// Alert with Message\nshow(message: \"Message\", actions: Action.ok, Action.cancel)\n\n// Alert with Title and Message, Ok and Cancel buttons\nshow(title: \"Title\", message: \"Message\", actions: Action.ok, Action.cancel)\n```\n\n**Actions Handling**\n\n```swift\nlet ok = Action.ok { _ in\n    // handle ok\n}\n\nlet cancel = Action.cancel { _ in\n    // handle cancel\n}\n\nshow(title: \"Alert with ok/cancel buttons\", actions: cancel, ok)\n```\n\nThe `Action` factory can be used to create a `UIAlertAction` or you can pass your own.\n\n```swift\nlet next = Action.with(title: \"Next\") { action in\n    // handle\n}\n\nlet delete = UIAlertAction(title: \"Delete\", style: .destructive) { _ in\n    // handle\n}\n\nshow(title: \"Are you sure?\", actions: next, delete)\n```\n\n**Full control on the alert presentation**\n```swift\nshow(title: \"Title\", message: \"Message\", style: .actionSheet, completion: {\n    // That is called when the alert has been presented\n}, actions: [action])\n```\n\nPlease note, the `actions` parameter **takes *Array* of actions instead of a variadic function**\n\n\nPresentation of the custom alert\n```swift\nlet alert = UIAlertController()\n\n// configure\n\nshow(alert: , {\n    /* handle */\n})\n```\n\nThe `Configuration` model provides an ability to override defaults for localization or other reasons.\n\n```swift\npublic struct Configuration {\n    public static var ok: String = \"OK\"\n    public static var cancel: String = \"Cancel\"\n\n    public struct Action {\n        public static var defaultStyle = UIAlertActionStyle.default\n        public static var cancelStyle = UIAlertActionStyle.cancel\n    }\n    public struct Alert {\n        public static var style = UIAlertControllerStyle.alert\n    }\n}\n```\n\n\n## Installation\n\n**Do not forget to import the module**\n```swift\nimport EasyCalls\n```\n\n\n### CocoaPods\nEasyCalls is available through [CocoaPods](http://cocoapods.org).\n\nEach module works independently so you can install the modules you need right now\n\n```ruby\n\npod 'EasyCalls/TryCatch'\npod 'EasyCalls/Queues'\npod 'EasyCalls/Realm'\npod 'EasyCalls/Alert'\n\n\npod 'EasyCalls' # contains 'TryCatch' and 'Queues' by default\n```\n\n### Manually\n\n* Open up Terminal, `cd` into your top-level project directory, and run the following command *if* your project is not initialized as a git repository:\n\n```\n$ git init\n```\n\n* Add EasyCalls as a git [submodule](http://git-scm.com/docs/git-submodule) by running the following commands:\n\n```\n$ git submodule add https://github.com/devmeremenko/EasyCalls.git\n```\n\n* Open the new EasyCalls folder, and drag the necessary sources into the Project Navigator of your project.\n\n## Change Log\n\n`Version` is the same for **CocoaPods** and **GitTag**.\n\n|  Version  | Function |             Description            |              Migration               |\n| ---------- | ---------- | -----------------------------  | -------------------------------|\n|    1.2.1    |  Queues  | **Extensions** for `DispatchQueue` were used instead of **global functions**.\u003cbr /\u003e\u003cbr /\u003e The `SpecificKey` for the main queue is set **only once** now. | Please add `DispatchQueue.` expression before all `toMain`, `toBackground`, and `runAfter`  calls.|\n|    1.1.1    |  Alert  | `EasyCalls/Alert` were added |                                |\n\n\n## Author\n \n[Maksym Eremenko](https://www.linkedin.com/in/maxim-eremenko/), devmeremenko@gmail.com\n\n## License\n\nEasyCalls is available under the MIT license.\n\n```\n# Copyright (c) 2018 Maxim Eremenko \u003cdevmeremenko@gmail.com\u003e\n#\n# Permission is hereby granted, free of charge, to any person obtaining a copy\n# of this software and associated documentation files (the \"Software\"), to deal\n# in the Software without restriction, including without limitation the rights\n# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\n# copies of the Software, and to permit persons to whom the Software is\n# furnished to do so, subject to the following conditions:\n#\n# The above copyright notice and this permission notice shall be included in\n# all copies or substantial portions of the Software.\n#\n# THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\n# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\n# THE SOFTWARE.\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevmeremenko%2Feasycalls","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdevmeremenko%2Feasycalls","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdevmeremenko%2Feasycalls/lists"}