{"_id":"567302825316790d001f8d6a","user":"5654ea8be0d82b0d00ab5747","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":13,"project":"5672fc989996590d00c22c65","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"},"updates":[],"next":{"pages":[],"description":""},"createdAt":"2015-12-17T18:44:18.341Z","link_external":false,"link_url":"","githubsync":"","sync_unique":"","hidden":false,"api":{"settings":"","results":{"codes":[]},"auth":"required","params":[],"url":""},"isReference":false,"order":2,"body":"Up until now operations have been discussed as being isolated units of work. However, in practice this is rarely possible. More than likely if an operation has a dependency, the result of that operation is needed in the next one.\n\nIn software engineering this is known as [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) but we wish to avoid this term to avoid confusion with operational dependencies. \n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Synchronous & literal requirements\"\n}\n[/block]\nIf the requirement for an operation is available synchronously, or perhaps is a literal value, then it can be injected into the initializer of the operation. This is following best practices for object orientated programming. \n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Asynchronous Requirements\"\n}\n[/block]\nHowever, if the requirements needed for an operations are not available when the instance is created, it must be injected sometime later, but before the operation executes.\n\nConsider a `DataProcessing` operation class. It's job is to process `NSData`, which we refer to as the *requirement*. However, the data in question must be retrieved from storage, or the network, by a `DataRetrieval` operation. In this context, the data is the *result*. \n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"class DataRetrieval: Operation, ResultOperationType {\\n    private(set) var result: NSData?\\n    \\n    override func execute() {\\n        fetchDataFromNetwork { data in\\n            result = data\\n            finish()\\n        }\\n    }\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"ResultOperationType example\"\n    }\n  ]\n}\n[/block]\nAbove is an example `DataRetrieval` class. It conforms to `ResultOperationType` which defines the `result` property. This is a generic property with no constraints. When the operation executes, before finishing it sets the result.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"class DataProcessing: Operation, AutomaticInjectionOperationType, ResultOperationType {\\n    var requirement: NSData?\\n    private(set) var result: NSData?\\n    \\n    override func execute() {\\n        processData(requirement) { processed in\\n            result = processed\\n            finish()\\n        }\\n    }\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"AutomaticInjectionOperationType example\"\n    }\n  ]\n}\n[/block]\nThe above example shows a `DataProcessing` class. Here it conforms to `AutomaticInjectionOperationType` in addition to `ResultOperationType`. `AutomaticInjectionOperationType` defines the `requirement` property, which is also a generic property with no constraints.\n\nThe next step is to chain the operations together:\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"let retrieval = DataRetrieval()\\nlet processing = DataProcessing()\\nprocessing.injectResultFromDependency(retrieval)\\nqueue.addOperations(retrieval, processing)\",\n      \"language\": \"swift\",\n      \"name\": \"Automatic Result Injection\"\n    }\n  ]\n}\n[/block]\nWhat does this do?\n\n1. The retrieval operation is automatically added as a dependency of the processing operation.\n2. We add an observer to the retrieval operation to automatically set its result as the requirement of the processing operation.\n[block:callout]\n{\n  \"type\": \"warning\",\n  \"body\": \"There is a constraint on `injectResultFromDependency` where the `ResultOperationType.Result` type must match the `AutomaticInjectionOperationType.Requirement`.\",\n  \"title\": \"Type constraint between Result and Requirement\"\n}\n[/block]\nIf the data retrieval operation finishes with errors, the processing operation will cancel with an `AutomaticInjectionError` which contains the errors from the dependency.\n[block:callout]\n{\n  \"type\": \"success\",\n  \"title\": \"Create transformation queues\",\n  \"body\": \"By constructing `Operation` classes with conformance to both `ResultOperationType` and `AutomaticInjectionOperationType`, data can be transformed through a queue of chained operations.\"\n}\n[/block]\n\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Use of optionals\"\n}\n[/block]\nThe `ResultOperationType` only defines `result` to get a generic typealias. Therefore the type of `result` can be `NSData?` or `NSData`. However, bear in mind that standard Swift rules apply here. If the property is not an optional, it must be set during initialization. This can be useful if there are default values which would be suitable. Clearly it must be a `var` if the operation will set it during the `execute` function.\n\nThe same considerations apply for the `requirement` property, except that the type of both properties must be the same. We recommend usage of optionals for these types, because even if a default value can be set on a property, which would allow for non-optional types, it might couple the two operations together as both would need the default value set.\n[block:api-header]\n{\n  \"type\": \"basic\",\n  \"title\": \"Manual Result Injection\"\n}\n[/block]\nIn some cases, representing *results* and *requirements* as single properties is not possible. In some cases an operation might have multiple requirements, or produce multiple results. For these cases, the framework provides a less automatic injection approach.\n[block:code]\n{\n  \"codes\": [\n    {\n      \"code\": \"let retrieval = DataRetrieval()\\nlet processing = DataProcessing()\\nprocessing.injectResultFromDependency(retrieval) { op, dep, errors in \\n    // Here we have access to both operations, plus any errors\\n    // from the dependency.\\n}\",\n      \"language\": \"swift\",\n      \"name\": \"Manual Result Injection\"\n    }\n  ]\n}\n[/block]","excerpt":"","slug":"injecting-results","type":"basic","title":"Injecting Results"}
Up until now operations have been discussed as being isolated units of work. However, in practice this is rarely possible. More than likely if an operation has a dependency, the result of that operation is needed in the next one. In software engineering this is known as [Dependency Injection](https://en.wikipedia.org/wiki/Dependency_injection) but we wish to avoid this term to avoid confusion with operational dependencies. [block:api-header] { "type": "basic", "title": "Synchronous & literal requirements" } [/block] If the requirement for an operation is available synchronously, or perhaps is a literal value, then it can be injected into the initializer of the operation. This is following best practices for object orientated programming. [block:api-header] { "type": "basic", "title": "Asynchronous Requirements" } [/block] However, if the requirements needed for an operations are not available when the instance is created, it must be injected sometime later, but before the operation executes. Consider a `DataProcessing` operation class. It's job is to process `NSData`, which we refer to as the *requirement*. However, the data in question must be retrieved from storage, or the network, by a `DataRetrieval` operation. In this context, the data is the *result*. [block:code] { "codes": [ { "code": "class DataRetrieval: Operation, ResultOperationType {\n private(set) var result: NSData?\n \n override func execute() {\n fetchDataFromNetwork { data in\n result = data\n finish()\n }\n }\n}", "language": "swift", "name": "ResultOperationType example" } ] } [/block] Above is an example `DataRetrieval` class. It conforms to `ResultOperationType` which defines the `result` property. This is a generic property with no constraints. When the operation executes, before finishing it sets the result. [block:code] { "codes": [ { "code": "class DataProcessing: Operation, AutomaticInjectionOperationType, ResultOperationType {\n var requirement: NSData?\n private(set) var result: NSData?\n \n override func execute() {\n processData(requirement) { processed in\n result = processed\n finish()\n }\n }\n}", "language": "swift", "name": "AutomaticInjectionOperationType example" } ] } [/block] The above example shows a `DataProcessing` class. Here it conforms to `AutomaticInjectionOperationType` in addition to `ResultOperationType`. `AutomaticInjectionOperationType` defines the `requirement` property, which is also a generic property with no constraints. The next step is to chain the operations together: [block:code] { "codes": [ { "code": "let retrieval = DataRetrieval()\nlet processing = DataProcessing()\nprocessing.injectResultFromDependency(retrieval)\nqueue.addOperations(retrieval, processing)", "language": "swift", "name": "Automatic Result Injection" } ] } [/block] What does this do? 1. The retrieval operation is automatically added as a dependency of the processing operation. 2. We add an observer to the retrieval operation to automatically set its result as the requirement of the processing operation. [block:callout] { "type": "warning", "body": "There is a constraint on `injectResultFromDependency` where the `ResultOperationType.Result` type must match the `AutomaticInjectionOperationType.Requirement`.", "title": "Type constraint between Result and Requirement" } [/block] If the data retrieval operation finishes with errors, the processing operation will cancel with an `AutomaticInjectionError` which contains the errors from the dependency. [block:callout] { "type": "success", "title": "Create transformation queues", "body": "By constructing `Operation` classes with conformance to both `ResultOperationType` and `AutomaticInjectionOperationType`, data can be transformed through a queue of chained operations." } [/block] [block:api-header] { "type": "basic", "title": "Use of optionals" } [/block] The `ResultOperationType` only defines `result` to get a generic typealias. Therefore the type of `result` can be `NSData?` or `NSData`. However, bear in mind that standard Swift rules apply here. If the property is not an optional, it must be set during initialization. This can be useful if there are default values which would be suitable. Clearly it must be a `var` if the operation will set it during the `execute` function. The same considerations apply for the `requirement` property, except that the type of both properties must be the same. We recommend usage of optionals for these types, because even if a default value can be set on a property, which would allow for non-optional types, it might couple the two operations together as both would need the default value set. [block:api-header] { "type": "basic", "title": "Manual Result Injection" } [/block] In some cases, representing *results* and *requirements* as single properties is not possible. In some cases an operation might have multiple requirements, or produce multiple results. For these cases, the framework provides a less automatic injection approach. [block:code] { "codes": [ { "code": "let retrieval = DataRetrieval()\nlet processing = DataProcessing()\nprocessing.injectResultFromDependency(retrieval) { op, dep, errors in \n // Here we have access to both operations, plus any errors\n // from the dependency.\n}", "language": "swift", "name": "Manual Result Injection" } ] } [/block]