{"_id":"567344caf65d9c0d002e3c89","project":"5672fc989996590d00c22c65","user":"5654ea8be0d82b0d00ab5747","category":{"_id":"5673018a06b19d0d0010691b","pages":["567302825316790d001f8d6a","5673029345185e0d008bd1c2","5676d59a12ea5a2300726aba"],"project":"5672fc989996590d00c22c65","__v":3,"version":"5672fc989996590d00c22c68","sync":{"url":"","isSync":false},"reference":false,"createdAt":"2015-12-17T18:40:10.078Z","from_sync":false,"order":4,"slug":"intermediate","title":"Advanced"},"version":{"_id":"5672fc989996590d00c22c68","__v":7,"project":"5672fc989996590d00c22c65","createdAt":"2015-12-17T18:19:04.699Z","releaseDate":"2015-12-17T18:19:04.699Z","categories":["5672fc999996590d00c22c69","567301169d4c060d009da8b3","56730183547bee0d00997d1a","5673018a06b19d0d0010691b","567301b53054630d00fe9288","567400638565060d009a86fb","5674017bf79ca90d00ad2f67"],"is_deprecated":false,"is_hidden":false,"is_beta":false,"is_stable":true,"codename":"","version_clean":"2.5.0","version":"2.5.0"},"__v":10,"updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-12-17T23:27:06.520Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"results":{"codes":[]},"settings":"","auth":"required","params":[],"url":""},"isReference":false,"order":0,"body":"`CapabilityType` is a protocol which represents an aspect of the device or user account. It supports querying for the current authorization status and explicitly requesting authorization to access the capability. A `CapabilityType` might also have a `Requirement` associated with its permission.\n\nOperations has the following `CapabilityType`s\n[block:parameters]\n{\n  \"data\": {\n    \"h-0\": \"CapabilityType\",\n    \"3-0\": \"`Capability.Location`\",\n    \"h-1\": \"Device or Account Capability\",\n    \"3-1\": \"Access Location Services for the device's current location.\",\n    \"0-0\": \"`Capability.Calendar`\",\n    \"0-1\": \"Access EventKit for the user's calendars etc.\",\n    \"1-0\": \"`Capability.Cloud`\",\n    \"1-1\": \"Access a CloudKit container.\",\n    \"2-0\": \"`Capability.Health`\",\n    \"2-1\": \"Access to HealthKit for reading and writing samples.\",\n    \"4-0\": \"`Capability.Passbook`\",\n    \"4-1\": \"PassKit does not have access controls, but the capability can confirm whether it is enabled or not.\",\n    \"5-0\": \"`Capability.Photos`\",\n    \"5-1\": \"Access the user's Photo Library.\"\n  },\n  \"cols\": 2,\n  \"rows\": 6\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Authorizing\"\n}\n[/block]\nLet's say you wish perform a task using the user's calendars. This task should be written as a `Operation` subclass, and it will add a condition.  \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"class ReminderOperation: Operation {\\n   override init() {\\n       super.init()\\n       name = \\\"Reminder Operation\\\"\\n       addCondition(AuthorizedFor(Capability.Calendar(.Reminder)))\\n   }\\n   \\n   override func execute() {\\n       // do something with EventKit here\\n       finish()\\n   }\\n}\",\n      \"language\": \"swift\"\n    }\n  ]\n}\n[/block]\n`AuthorizedFor` is an `OperationCondition` which is initialized with a `CapabilityType`. If the current authorization status is unknown, it will request permission to access the capability as a dependency. When the attached operation (`ReminderOperation` in this case) evaluates its conditions, `AuthorizedFor` will then check the authorization status again, and if the requirements of the `CapabiltiyType` are met, the condition is satisfied. In this case, the requirement was access to the user's reminders. \n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Checking the current Authorization Status\"\n}\n[/block]\nSometimes, it is beneficial to test the current status of a `CapabilityType` without requesting authorization. For example, it is nice to present your users with information about why the application is requesting permission to access their Reminders. Operations make it very easy to do this, by using the `GetAuthorizationStatus` operation. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"func updateForStatus(enabled: Bool, status: EKAuthorizationStatus) {\\n    // etc - note that the status is specific to EventKit\\n}\\n\\nfunc checkReminderAuthorization() {\\n    let capability = Capability.Calendar(.Reminder) \\n    let check = GetAuthorizationStatus(capability, completion: updateForStatus)\\n    queue.addOperation(check)\\n}\",\n      \"language\": \"swift\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Requesting authorization\"\n}\n[/block]\nTo explicitly request authorization to access a `CapabilityType` use the `Authorize` operation. It is a subclass of `GetAuthorizationStatus` with the same initializer. This allows the same completion block to be used to update or progress your user interface. Consider the following:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"func requestReminderAuthorization() {\\n    let capability = Capability.Calendar(.Reminder) \\n    let request = Authorize(capability, completion: updateForStatus)\\n    queue.addOperation(request)\\n}\",\n      \"language\": \"swift\"\n    }\n  ]\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Combine with SilentCondition\"\n}\n[/block]\nIndeed, the `AuthorizedFor` condition returns an `Authorize` operation as its dependency, which means it will always request access. However, in some situations it can make for a nicer user experience if permission requests are delayed until later on. In which case, compose `AuthorizedFor` inside a `SilentCondition`.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"func doBonusReminderStuff() {\\n    let doReminderStuff = ReminderOperation() // from earlier\\n    let operation = ComposedOperation(doReminderStuff)\\n    let capability = Capability.Calendar(.Reminder)\\n    operation.addCondition(SilentCondition(AuthorizedFor(capability)))\\n    queue.addOperation(operation)\\n}\",\n      \"language\": \"swift\"\n    }\n  ]\n}\n[/block]\nIn the above example, we want to execute the `ReminderOperation`, but only if the user has already authorized the application to access their reminders. The operation already adds a \"noisy\" `AuthorizedFor` condition, however, we can pre-empt this by composing the `ReminderOperation` inside `ComposedOperation`. This operation exists purely to wrap other `NSOperation` subclasses. It is very useful to attach observers and conditions to `NSOperation` subclasses which are not `Operation` subclasses, such as you might get from Cocoa frameworks. In this case however, we can use it to attach a condition to check for the calendar capability. The important difference is, that we will suppress the `Authorize` dependency by using `SilentCondition`. \n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Combine with NegatedCondition\"\n}\n[/block]\nIn the above example we performed an operation only when the user had already authorized access to a their reminders, without asking for permission if they had not. Another common scenario is to perform an operation only if the user has not authorized access to the capability. For this, we can use a `NegatedCondition`.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"func fallbackGracefullyWithoutReminders() {\\n    let fallback = FallbackOperation() // assume we have this `Operation` subclass\\n    let capability = Capability.Calendar(.Reminder)\\n    let condition = NegatedCondition(SilentCondition(AuthorizedFor(capability)))\\n\\t\\tfallback.addCondition(condition)\\n    queue.addOperation(fallback)\\n}\\n\\n\",\n      \"language\": \"swift\"\n    }\n  ]\n}\n[/block]\nFor more examples of device capabilities, check out the example project called *Permissions* in the repository.","excerpt":"","slug":"capabilities","type":"basic","title":"Capabilities"}
`CapabilityType` is a protocol which represents an aspect of the device or user account. It supports querying for the current authorization status and explicitly requesting authorization to access the capability. A `CapabilityType` might also have a `Requirement` associated with its permission. Operations has the following `CapabilityType`s [block:parameters] { "data": { "h-0": "CapabilityType", "3-0": "`Capability.Location`", "h-1": "Device or Account Capability", "3-1": "Access Location Services for the device's current location.", "0-0": "`Capability.Calendar`", "0-1": "Access EventKit for the user's calendars etc.", "1-0": "`Capability.Cloud`", "1-1": "Access a CloudKit container.", "2-0": "`Capability.Health`", "2-1": "Access to HealthKit for reading and writing samples.", "4-0": "`Capability.Passbook`", "4-1": "PassKit does not have access controls, but the capability can confirm whether it is enabled or not.", "5-0": "`Capability.Photos`", "5-1": "Access the user's Photo Library." }, "cols": 2, "rows": 6 } [/block] [block:api-header] { "type": "basic", "title": "Authorizing" } [/block] Let's say you wish perform a task using the user's calendars. This task should be written as a `Operation` subclass, and it will add a condition. [block:code] { "codes": [ { "code": "class ReminderOperation: Operation {\n override init() {\n super.init()\n name = \"Reminder Operation\"\n addCondition(AuthorizedFor(Capability.Calendar(.Reminder)))\n }\n \n override func execute() {\n // do something with EventKit here\n finish()\n }\n}", "language": "swift" } ] } [/block] `AuthorizedFor` is an `OperationCondition` which is initialized with a `CapabilityType`. If the current authorization status is unknown, it will request permission to access the capability as a dependency. When the attached operation (`ReminderOperation` in this case) evaluates its conditions, `AuthorizedFor` will then check the authorization status again, and if the requirements of the `CapabiltiyType` are met, the condition is satisfied. In this case, the requirement was access to the user's reminders. [block:api-header] { "type": "basic", "title": "Checking the current Authorization Status" } [/block] Sometimes, it is beneficial to test the current status of a `CapabilityType` without requesting authorization. For example, it is nice to present your users with information about why the application is requesting permission to access their Reminders. Operations make it very easy to do this, by using the `GetAuthorizationStatus` operation. [block:code] { "codes": [ { "code": "func updateForStatus(enabled: Bool, status: EKAuthorizationStatus) {\n // etc - note that the status is specific to EventKit\n}\n\nfunc checkReminderAuthorization() {\n let capability = Capability.Calendar(.Reminder) \n let check = GetAuthorizationStatus(capability, completion: updateForStatus)\n queue.addOperation(check)\n}", "language": "swift" } ] } [/block] [block:api-header] { "type": "basic", "title": "Requesting authorization" } [/block] To explicitly request authorization to access a `CapabilityType` use the `Authorize` operation. It is a subclass of `GetAuthorizationStatus` with the same initializer. This allows the same completion block to be used to update or progress your user interface. Consider the following: [block:code] { "codes": [ { "code": "func requestReminderAuthorization() {\n let capability = Capability.Calendar(.Reminder) \n let request = Authorize(capability, completion: updateForStatus)\n queue.addOperation(request)\n}", "language": "swift" } ] } [/block] [block:api-header] { "type": "basic", "title": "Combine with SilentCondition" } [/block] Indeed, the `AuthorizedFor` condition returns an `Authorize` operation as its dependency, which means it will always request access. However, in some situations it can make for a nicer user experience if permission requests are delayed until later on. In which case, compose `AuthorizedFor` inside a `SilentCondition`. [block:code] { "codes": [ { "code": "func doBonusReminderStuff() {\n let doReminderStuff = ReminderOperation() // from earlier\n let operation = ComposedOperation(doReminderStuff)\n let capability = Capability.Calendar(.Reminder)\n operation.addCondition(SilentCondition(AuthorizedFor(capability)))\n queue.addOperation(operation)\n}", "language": "swift" } ] } [/block] In the above example, we want to execute the `ReminderOperation`, but only if the user has already authorized the application to access their reminders. The operation already adds a "noisy" `AuthorizedFor` condition, however, we can pre-empt this by composing the `ReminderOperation` inside `ComposedOperation`. This operation exists purely to wrap other `NSOperation` subclasses. It is very useful to attach observers and conditions to `NSOperation` subclasses which are not `Operation` subclasses, such as you might get from Cocoa frameworks. In this case however, we can use it to attach a condition to check for the calendar capability. The important difference is, that we will suppress the `Authorize` dependency by using `SilentCondition`. [block:api-header] { "type": "basic", "title": "Combine with NegatedCondition" } [/block] In the above example we performed an operation only when the user had already authorized access to a their reminders, without asking for permission if they had not. Another common scenario is to perform an operation only if the user has not authorized access to the capability. For this, we can use a `NegatedCondition`. [block:code] { "codes": [ { "code": "func fallbackGracefullyWithoutReminders() {\n let fallback = FallbackOperation() // assume we have this `Operation` subclass\n let capability = Capability.Calendar(.Reminder)\n let condition = NegatedCondition(SilentCondition(AuthorizedFor(capability)))\n\t\tfallback.addCondition(condition)\n queue.addOperation(fallback)\n}\n\n", "language": "swift" } ] } [/block] For more examples of device capabilities, check out the example project called *Permissions* in the repository.