{"id":1895,"url":"https://github.com/lukhnos/objectiveflickr","last_synced_at":"2025-05-16T14:07:24.342Z","repository":{"id":544895,"uuid":"174922","full_name":"lukhnos/objectiveflickr","owner":"lukhnos","description":"ObjectiveFlickr, a Flickr API framework for Objective-C","archived":false,"fork":false,"pushed_at":"2015-11-13T05:57:39.000Z","size":709,"stargazers_count":773,"open_issues_count":18,"forks_count":148,"subscribers_count":33,"default_branch":"master","last_synced_at":"2025-04-12T11:55:30.694Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/lukhnos.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2009-04-13T18:26:30.000Z","updated_at":"2025-03-03T10:44:41.000Z","dependencies_parsed_at":"2022-07-07T14:45:10.575Z","dependency_job_id":null,"html_url":"https://github.com/lukhnos/objectiveflickr","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukhnos%2Fobjectiveflickr","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukhnos%2Fobjectiveflickr/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukhnos%2Fobjectiveflickr/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/lukhnos%2Fobjectiveflickr/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/lukhnos","download_url":"https://codeload.github.com/lukhnos/objectiveflickr/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254544146,"owners_count":22088807,"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-01-05T20:15:58.394Z","updated_at":"2025-05-16T14:07:24.325Z","avatar_url":"https://github.com/lukhnos.png","language":"Objective-C","funding_links":[],"categories":["SDK","Unofficial","非官方"],"sub_categories":["Unofficial","Other free courses"],"readme":"ObjectiveFlickr\n===============\n\nObjectiveFlickr is a Flickr API framework designed for Mac and iPhone apps.\n\n\nOAuth Support\n=============\nObjectiveFlickr now supports Flickr's new OAuth-based authentication process.\nI'll post more about it in the coming week. The SnapAndRun sample is updated\nto reflect the usage. A new Mac sample, OAuthTransitionMac, demonstrates\nhow to use the new OAuth-based API and also how to migrate your existing\nauth tokens. OAuthTransitionMac uses ARC and therefore also shows how to \nuse ObjectiveFlickr, which is a non-ARC library, with an ARC app.\n\niOS support in ObjectiveFlickr was developed mostly during the iPhone OS 2.0\ndays and it shows. More update work will be required to reflect the changes\nin the iOS development process. Your contribution (like updating this\nREADME, submitting new samples or test cases) is greatly welcome -- and it\nwill benefit the iOS open source development community, too!\n\n**Update**. Please refer to [my blog post](http://blog.lukhnos.org/post/11275346353/flickr-oauth-support-in-objectiveflickr)\nfor the steps you need to take for the transition.\n\n\nWhat's New in 2.0\n=================\n\nVersion 2.0 is a complete rewrite, with design integrity and extensibility in\nmind. Differences from 0.9.x include:\n\n* The framework now builds with all major Apple SDKs: Mac OS X 10.4,\n  10.5, iPhone OS 2.2.x, and other beta version platforms to which I have \n  access. It also builds on both 32-bit and 64-bit platforms.\n* Ordinary request and upload request are now unified into one \n  OFFlickrAPIRequest class\n* 2.0 no longer depends on NSXMLDocument, which is not available in iPhone \n  SDK. It now maps Flickr's XML response into an NSDictionary using only \n  NSXMLParser, which is available on all Apple platforms.\n* Image uploading employs temp file. This allows ObjectiveFlickr to operate\n  in memory-constrained settings.\n* Error reporting now uses NSError to provide more comprehensive information,\n  especially error code and message from Flickr.\n  \nIf you already use ObjectiveFlickr 0.9.x, the bad news is that 2.0 is not\nbackward compatible. The good news, though, is that it uses a different set\nof class names. Some migration tips are offered near the end of this document.\n\n\nWhat's Not (Yet) There\n======================\n\nThere are of course quite a few to-do's:\n\n* In-source API documentation\n* Unit testings\n* Flickr API coverage tests (challenging though—how do you test a moving\n  target?)\n* ObjectiveFlickr 0.9.x has a few convenient methods and tricks to simplify \n  method calling; they are not ported here (yet, or will never be)\n\n\nQuick Start: Example Apps You Can Use\n=====================================\n\n**UPDATE 2.0.4**: If you use [CocoaPods](https://cocoapods.org/), you should\ncheck out [the new sample projects](https://github.com/lukhnos/objectiveflickr/tree/master/Examples/CocoaPodsSampleProjects)\nthat make use of the tool to manage ObjectiveFlickr for you.\n\n\n1. Check out the code from github:\n\n  ```bash\n  git clone git://github.com/lukhnos/objectiveflickr.git\n  ```\n\n2. Supply your own API key and shared secret. You need to copy\n   `SampleAPIKey.h.template` to `SampleAPIKey.h`, and fill in the two\n   macros there. If you don't have an API key, apply for yours at:\n   \u003chttp://www.flickr.com/services/api/keys/apply/\u003e .\n   Make sure you have understood their terms and conditions.\n\n3. Remember to make your API key a \"web app\", and set the *Callback URL*\n   (not the *Application URL*!) to:\n\n  ```xml\n  snapnrun://auth?\n  ```\n\n4. Build and run SnapAndRun for iPhone. The project is located at \n   `Examples/SnapAndRun-iPhone`\n\n5. Build and run RandomPublicPhoto for Mac. The project is at \n   `Examples/RandomPublicPhoto`\n\n\nAdding ObjectiveFlickr to Your Project\n======================================\n\n**UPDATE 2.0.4**: This section shows its age and needs updating. Pull requests\non an up-to-date instruction will be appreciated! Meanwhile, if you use\n[CocoaPods](https://cocoapods.org/), you can easily add ObjectiveFlickr to your\nproject by adding this one line to you `podfile`:\n\n    pod 'objectiveflickr'\n\nThen just run `pod install` and start using ObjectiveFlickr.\n\n\nAdding ObjectiveFlickr to Your Mac App Project\n----------------------------------------------\n\n1. `Add ObjectiveFlickr.xcodeproj` to your Mac project (from Xcode menu \n   **Project \u003e Add to Project...**)\n2. On your app target, open the info window (using **Get Info** on the \n   target), then in the **General** tab, add `ObjectiveFlickr (framework)`\n   to **Direct Dependencies**\n3. Add a new **Copy Files** phase, and choose **Framework** for the \n   **Destination** (in its own info window)\n4. Drag `ObjecitveFlickr.framework` from the Groups \u0026 Files panel in Xcode \n   (under the added `ObjectiveFlickr.xcodeproj`) to the newly created **Copy \n   Files** phase\n5. Drag `ObjecitveFlickr.framework` once again to the target's **Linked Binary \n   With Libraries** group\n6. Open the Info window of your target again. Set **Configuration** to **All \n   Configurations**, then in the **Framework Search Paths** property, add \n   `$(TARGET_BUILD_DIR)/$(FRAMEWORKS_FOLDER_PATH)`\n7. Use `#import \u003cObjectiveFlickr/ObjectiveFlickr.h\u003e` in your project\n\nAdding ObjectiveFlickr to Your iPhone App Project\n-------------------------------------------------\n\nBecause iPhone SDK does not allow dynamically linked frameworks and bundles, we need to link against ObjectiveFlickr statically.\n\n1. `Add ObjectiveFlickr.xcodeproj` to your Mac project (from Xcode menu \n   **Project \u003e Add to Project...**)\n2. On your app target, open the info window (using **Get Info** on the \n   target), then in the **General** tab, add `ObjectiveFlickr (library)` to \n   **Direct Dependencies**\n3. Also, in the same window, add `CFNetwork.framework` to\n   **Linked Libraries**\n4. Drag `libObjecitveFlickr.a` to the target's **Linked Binary With Libraries\n   group**\n5. Open the Info window of your target again. Set **Configuration** to **All \n   Configurations**, then in the **Header Search Paths** property, add these \n   two paths, separately (`\u003cOF root\u003e` is where you checked out\n   ObjectiveFlickr):\n\n  ```xml\n  \u003cOF root\u003e/Source\n  \u003cOF root\u003e/LFWebAPIKit   \n  ```\n       \n6. Use `#import \"ObjectiveFlickr.h\"` in your project\n\n\nKey Ideas and Basic Usage\n=========================\n\n**ObjectiveFlickr is an asynchronous API.** Because of the nature of GUI \napp, all ObjectiveFlickr requests are asynchronous. You make a request, then \nObjectiveFlickr calls back your delegate methods and tell you if a request \nsucceeds or fails.\n\n**ObjectiveFlickr is a minimalist framework.** The framework has essentially\nonly two classes you have to deal with: `OFFlickrAPIContext` and\n`OFFlickrAPIRequest`. Unlike many other Flickr API libraries, ObjectiveFlickr \ndoes *not* have classes like FlickrPhoto, FlickrUser, FlickrGroup or \nwhathaveyou. You call a Flickr method, like `flickr.photos.getInfo`, and get back a dictionary (hash or map in other languages) containing the key-value \npairs of the result. The result is *directly mapped from Flickr's own \nXML-formatted response*. Because they are already *structured data*, \nObjectiveFlickr does not  translate further into other object classes. \n\nBecause of the minimalist design, you also need to have basic understanding of\n**how Flickr API works**. Refer to \u003chttp://www.flickr.com/services/api/\u003e for \nthe details. But basically, all you need to know is the methods you want to\ncall, and which XML data (the key-values) Flickr will return.\n\nTypically, to develop a Flickr app for Mac or iPhone, you need to follow the following steps:\n\n1. Get you Flickr API key at \u003chttp://www.flickr.com/services/api/keys/apply/\u003e\n2. Create an OFFlickrAPIContext object\n\n  ```obj-c\n  OFFlickrAPIContext *context = [[OFFlickrAPIContext alloc] initWithAPIKey:YOUR_KEY sharedSecret:YOUR_SHARED_SECRET];\n  ```\n\n3. Create an OFFlickrAPIRequest object where appropriate, and set the delegate\n\n  ```obj-c\n  OFFlickrAPIRequest *request = [[OFFlickrAPIRequest alloc] initWithAPIContext:context];\n  \n  // set the delegate, here we assume it's the controller that's creating the request object\n  [request setDelegate:self];\n  ```\n\n4. Implement the delegate methods.\n\n  ```obj-c\n  - (void)flickrAPIRequest:(OFFlickrAPIRequest *)inRequest didCompleteWithResponse:(NSDictionary *)inResponseDictionary;\n  - (void)flickrAPIRequest:(OFFlickrAPIRequest *)inRequest didFailWithError:(NSError *)inError;\n  - (void)flickrAPIRequest:(OFFlickrAPIRequest *)inRequest imageUploadSentBytes:(NSUInteger)inSentBytes totalBytes:(NSUInteger)inTotalBytes;\n  ```\n\n    All three methods are optional (\"informal protocol\" in old Objective-C \n    speak; optional protocol methods in newspeak). *Nota bene*: If you\n    are using Mac OS X 10.4 SDK, or if you are using 10.5 SDK but targeting\n    10.4, then the delegate methods are declared as informal protocols.\n    In all other cases (OS X 10.5 and above or iPhone apps), you need to\n    specify you are adopting the OFFlickrAPIRequestDelegate protocol. *E.g.*:\n  ```obj-c    \n  @interface MyViewController : UIViewController \u003cOFFlickrAPIRequestDelegate\u003e\n  ```\n\n5. Call the Flickr API methods you want to use. Here are a few examples.\n\n    Calling `flickr.photos.getRecent` with the argument `per_page` = `1`:\n\n  ```obj-c    \n  [request callAPIMethodWithGET:@\"flickr.photos.getRecent\" arguments:[NSDictionary dictionaryWithObjectsAndKeys:@\"1\", @\"per_page\", nil]]\n  ```\n\n    Quite a few Flickr methods require that you call with HTTP POST\n    (because those methods write or modify user data):\n\n  ```obj-c\n  [request callAPIMethodWithPOST:@\"flickr.photos.setMeta\" arguments:[NSDictionary dictionaryWithObjectsAndKeys:photoID, @\"photo_id\", newTitle, @\"title\", newDescription, @\"description\", nil]];\n  ```\n\n6. Handle the response or error in the delegate methods. If an error\n   occurs, an NSError object is passed to the error-handling delegate \n   method. If the error object's domain is `OFFlickrAPIReturnedErrorDomain`,\n   then it's a server-side error. You can refer to Flickr's API documentation\n   for the meaning of the error. If the domain is\n   `OFFlickrAPIRequestErrorDomain`, it's client-side error, usually caused\n   by lost network connection or transfer timeout.\n   \n   We will now talk about the response.\n\n\nHow to Upload a Picture\n=======================\n\nTo upload a picture, create an NSInputStream object from a file path\nor the image data (NSData), then make the request. Here in the example\nwe assume we already have obtained the image data in JPEG, and we set\nmake private the uploaded picture:\n\n```obj-c\nNSInputStream *imageStream = [NSInputStream inputStreamWithData:imageData];\n[request uploadImageStream:imageStream suggestedFilename:@\"Foobar.jpg\" MIMEType:@\"image/jpeg\" arguments:[NSDictionary dictionaryWithObjectsAndKeys:@\"0\", @\"is_public\", nil]];\n```\n      \nUpload progress will be reported to the delegate method\n`flickrAPIRequest:imageUploadSentBytes:totalBytes:`\n\nThe reason why ObjectiveFlickr asks for an NSInputStream object as input\nis that we don't want to read in the whole image into memory for the \npreparation of upload data. With NSInputStream you have the flexibility\nof feeding ObjectiveFlickr an in-memory image data, a file, or even a\nvirtualized image byte stream that comes from different (e.g. partitioned)\nsources.\n\nMake sure you have read [Flickr's upload API documentation](\nhttp://www.flickr.com/services/api/upload.api.html) so that you understand\nhow to pick up the upload result. Please note that between the completion\nof uploading and the completion of the HTTP POST request itself (the moment\nat which you receive the response), there can be a *long* wait. So make sure\nyou have a long timeout interval, especially when you upload a large image,\nand also design your UI accordingly.\n\n\nAuth Considerations\n===================\n\n**Deprecated**. The original authentication process is now deprecated by Flickr.\nPlease refer to [my blog post](http://blog.lukhnos.org/post/11275346353/flickr-oauth-support-in-objectiveflickr)\nfor the steps you need to take for the new setup.\n\n\nIf your app does not just read public photos, your app will need to get \nuser permission for accessing their photos. You need to use Flickr's\nauthentication/authorization mechanism (hereafter \"auth\" to cover both\nsteps) to get the *authToken* for your later access.\n\nThis is, frankly, the most difficult part in using the whole Flickr API;\nanything that comes after that is easy and (usually) smooth. That alone\nis worth a whole tutorial, but I'll try to explain the essentials.\n\nBefore that, get to know Flickr's own doc here:\n\u003chttp://www.flickr.com/services/api/misc.userauth.html\u003e.\n\nThere are two types of app auth:\n\n* [Desktop app](http://www.flickr.com/services/api/auth.howto.desktop.html)\n* [Web app](http://www.flickr.com/services/api/auth.howto.web.html)\n\nThere is actually a \"mobile app\" auth, designed for feature phones or\nsmart phones that aren't, well, not really smart, if you buy what Apple\nsays. But since we are talking about *Mac* and *iPhone* apps, and they\naren't any ye olde mobile platform, we'll skip that one and go straight\ninto the two major types of app auth.\n\n\nDesktop App Auth, the Old Way (Deprecated)\n------------------------------------------\n\n**Deprecated**. The original authentication process is now deprecated by Flickr.\nPlease refer to [my blog post](http://blog.lukhnos.org/post/11275346353/flickr-oauth-support-in-objectiveflickr)\nfor the steps you need to take for the new setup.\n\n\nBefore, Mac developers were only interested in Desktop app auth. If you \nhave used any Mac Flickr app before (FlickrExport, HoudahGeo, Posterino, and\nmany others), you know how it works:\n\n1. Open the app\n2. The app presents a dialog box, telling you it's going to open the web\n   browser. You log into Flickr, Flickr asks you if you grant permission\n   to the app currently asking for your permission (read, write, or\n   delete access).\n3. After you grant the permission, you *switch back* to the app, \n   hit some \"Continue\" button on the app the dialog box.\n4. The app fetches the auth token from Flickr, and completes the process.\n\nTo map that into your app's internal workings, you need to do these:\n\n1. Call [flickr.auth.getFrob](\n   http://www.flickr.com/services/api/flickr.auth.getFrob.html)\n2. After you receive the frob, pass the whole `inResponseDictionary` to\n   `-[OFFlickrAPIContext loginURLFromFrobDictionary:requestedPermission:]`\n   and get the returned NSURL object.\n3. Tell user that you're going to open the browser for them, prompt for\n   action.\n4. Open the browser with the URL you just got, then wait\n5. After user completes the auth, she will click on the \"Continue\" button\n   (or something like that).\n6. Your app then calls [flickr.auth.getToken](\n   http://www.flickr.com/services/api/flickr.auth.getToken.html) to get\n   the auth token\n7. Assign the auth token to your current Flickr API context with\n   `-[OFFlickrAPIContext setAuthToken:]`\n8. That's it. ObjectiveFlickr will add the `auth_token` argument to all \n   your subsequent API calls, and you now have the access to all the APIs\n   to which the user has grant you permission.\n\n\niPhone App Auth and the New Way (Deprecated)\n--------------------------------------------\n\n**Deprecated**. The original authentication process is now deprecated by Flickr.\nPlease refer to [my blog post](http://blog.lukhnos.org/post/11275346353/flickr-oauth-support-in-objectiveflickr)\nfor the steps you need to take for the new setup.\n\n\niPhone and iPod Touch posed a challenge to the auth model above: Opening\nup Mobile Safari then ask the forgetful user to come back is a bad idea.\n\nSo many iPhone developers have come up with this brilliant idea: Use \nURL scheme to launch your app. It turns out that Flickr's web app auth\nserves the idea well. Here is how it works:\n\n1. The app prompts user that it's going to open up browser to ask for\n   permission.\n2. The user taps some \"Open\" button, and the app closes, Mobile Safari\n   pops up with Flickr's login (and then app auth) page.\n3. Then magically, Mobile Safari closes, and the app is launched again.\n4. There's no Step 4.\n\nWhat's behind the scene is that the iPhone app in question has registered\na URL scheme, for example `someapp://` in its `Info.plist` and the app\ndeveloper has configured their Flickr API key, so that when the user\ngrants the app permission, Flickr will redirect the web page to that *URL*\nthe app developer has previously designated. Mobile Safari opens that\nURL, and then the app is launched.\n\nIn fact, Mac app can do that, too!\n\nHere's what you need to do:\n\n1. Register the URL scheme. Take a look at my own SnapAndRun-iPhone \n   example app's `SnapAndRun-Info.plist` and this [CocoaDev article](\n   http://www.cocoadev.com/index.pl?HowToRegisterURLHandler) for details.\n2. Configure your Flickr API key so that the *callback URL* is set to \n   that URL scheme.\n3. Get a login URL by calling\n   `-[OFFlickrAPIContext loginURLFromFrobDictionary:requestedPermission:]`,\n   note that you don't need to have a frob dictionary for getting web app\n   login (auth) URL, so just pass nil. You still need to pass the\n   permission argument, of course.\n4. Now, in your app launch URL handler (Mac and iPhone apps do it\n   differently, see Apple doc for details), get the frob that Flickr\n   has passed to you with the URL.\n5. Your app then calls [flickr.auth.getToken](\n  http://www.flickr.com/services/api/flickr.auth.getToken.html) to get\n  the auth token\n6. Assign the auth token to your current Flickr API context with\n  `-[OFFlickrAPIContext setAuthToken:]`\n7. That's it. ObjectiveFlickr will add the `auth_token` argument to all \n  your subsequent API calls, and you know have the access to all the APIs\n  to which the user has grant you permission.\n\nNow you have done the most difficult part of using the Flickr API.\n\n   \nHow Flickr's XML Responses Are Mapped Back\n==========================================\n\nFlickr's default response format is XML. You can opt for JSON. Whichever\nformat you choose, the gist is that *they are already structured data*.\nWhen I first started designing ObjectiveFlickr, I found it unnecessary to\ncreate another layer of code that maps those data to and from \"native\"\nobjects. So we don't have things like `OFFlickrPhoto` or `OFFlickrGroup`.\nIn essence, when an request object receives a response, it maps the XML\ninto a data structure consisting of NSDictionary's, NSArray's and \nNSString's. In Apple speak, this is known as \"property list\". And we'll\nuse that term to describe the mapped result. You then read out in the property\nlist the key-value pairs you're interested in.\n\nObjectiveFlickr uses the XML format to minimize dependency. It parses the\nXML with NSXMLParser, which is available on all Apple platforms. It maps\nXML to property list following the three simple rules:\n\n1. All XML tag properties are mapped to NSDictionary key-value pairs\n2. Text node (e.g. `\u003cphotoid\u003e12345\u003c/photoid\u003e`) is mapped as a dictionary\n   containing the key `OFXMLTextContentKey` (a string const) with its value\n   being the text content.\n3. ObjectiveFlickr knows when to translate arrays. We'll see how this is \n   done now.\n   \nSo, for example, this is a sample response from flickr.auth.checkToken   \n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"utf-8\" ?\u003e\n\u003crsp stat=\"ok\"\u003e\n\u003cauth\u003e\n\t\u003ctoken\u003eaaaabbbb123456789-1234567812345678\u003c/token\u003e\n\t\u003cperms\u003ewrite\u003c/perms\u003e\n\t\u003cuser nsid=\"00000000@N00\" username=\"foobar\" fullname=\"blah\" /\u003e\n\u003c/auth\u003e\n\u003c/rsp\u003e\n```\n \nThen in your `flickrAPIRequest:didCompleteWithResponse:` delegate method,\nif you dump the received response (an NSDictionary object) with NSLog,\nyou'll see something like (extraneous parts omitted):\n\n```js\n{\n    auth ={\n        perms = { \"_text\" = write };\n        token = { \"_text\" = \"aaaabbbb123456789-1234567812345678\"; };\n        user = {\n            fullname = \"blah\";\n            nsid = \"00000000@N00\";\n            username = foobar;\n        };\n    };\n    stat = ok;\n}\n```\n \nSo, say, if we are interested in the retrieved auth token, we can do this:\n\n```obj-c\nNSString *authToken = [[inResponseDictionary valueForKeyPath:@\"auth.token\"] textContent];\n```\n    \nHere, our own `-[NSDictionary textContent]` is simply a convenient method\nthat is equivalent to calling `[authToken objectForKey:OFXMLTextContentKey]`\nin our example.\n\nHere is another example returned by `flickr.photos.getRecent`:\n\n```xml\n\u003c?xml version=\"1.0\" encoding=\"utf-8\" ?\u003e\n\u003crsp stat=\"ok\"\u003e\n\u003cphotos page=\"1\" pages=\"334\" perpage=\"3\" total=\"1000\"\u003e\n\t\u003cphoto id=\"3444583634\" owner=\"37096380@N08\" secret=\"7bbc902132\" server=\"3306\" farm=\"4\" title=\"studio_53_1\" ispublic=\"1\" isfriend=\"0\" isfamily=\"0\" /\u003e\n\t\u003cphoto id=\"3444583618\" owner=\"27122598@N06\" secret=\"cc76db8cf8\" server=\"3327\" farm=\"4\" title=\"IMG_6830\" ispublic=\"1\" isfriend=\"0\" isfamily=\"0\" /\u003e\n\t\u003cphoto id=\"3444583616\" owner=\"26073312@N08\" secret=\"e132988dc3\" server=\"3376\" farm=\"4\" title=\"Cidade Baixa\" ispublic=\"1\" isfriend=\"0\" isfamily=\"0\" /\u003e\n\u003c/photos\u003e\n\u003c/rsp\u003e\n```\n    \nAnd the mapped property list looks like:\n\n```js\n{\n    photos = {\n        page = 1;\n        pages = 334;\n        perpage = 3;\n        photo = (\n            {\n                farm = 4;\n                id = 3444583634;\n                isfamily = 0;\n                isfriend = 0;\n                ispublic = 1;\n                owner = \"37096380@N08\";\n                secret = 7bbc902132;\n                server = 3306;\n                title = \"studio_53_1\";\n            },\n            {\n                farm = 4;\n                id = 3444583618;\n                /* ... */\n            },\n            {\n                farm = 4;\n                id = 3444583616;\n                /* ... */\n            }\n        );\n        total = 1000;\n    };\n    stat = ok;\n}\n```\n\nObjectiveFlickr knows to translate the enclosed \u003cphoto\u003e tags in the plural\n\u003cphotos\u003e tag into an NSArray. So if you want to retrieve the second photo\nin the array, you can do this:\n\n```obj-c\nNSDictionary *photoDict = [[inResponseDictionary valueForKeyPath:@\"photos.photo\"] objectAtIndex:1];\n```\n\nThen, with two helper methods from `OFFlickrAPIContext`, you can get the\nstatic photo source URL and the photo's original web page URL:\n\n```obj-c\nNSURL *staticPhotoURL = [flickrContext photoSourceURLFromDictionary:photoDict size:OFFlickrSmallSize];\nNSURL *photoSourcePage = [flickrContext photoWebPageURLFromDictionary:photoDict];\n```\n\nDo remember that Flickr requires you present a link to the photo's web page\nwherever you show the photo in your app. So design your UI accordingly.\n\n\nWacky XML Mappings\n==================\n\nUnfortunately, there are some Flickr responses that don't rigorously follow\nthe \"plural tag == array\" rule. Consider the following snippet (tag\nattributes removed to highlight the issue at hand), from the API method\n[flickr.activity.userPhotos](\nhttp://www.flickr.com/services/api/flickr.activity.userPhotos.html):\n\n```xml\n\u003crsp stat=\"ok\"\u003e\n\u003citems page=\"1\" pages=\"1\" perpage=\"50\" total=\"3\"\u003e\n\t\u003citem type=\"photo\"\u003e\n\t\t\u003ctitle\u003eSnap and Run Demo\u003c/title\u003e\n\t\t\u003cactivity\u003e\n\t\t\t\u003cevent type=\"comment\"\u003edouble comment 1\u003c/event\u003e\n\t\t\t\u003cevent type=\"comment\"\u003edouble comment 2\u003c/event\u003e\n\t\t\u003c/activity\u003e\n\t\u003c/item\u003e\n\t\u003citem type=\"photo\"\u003e\n\t\t\u003ctitle\u003eSnap and Run Demo\u003c/title\u003e\n\t\t\u003cactivity\u003e\n\t\t\t\u003cevent type=\"comment\"\u003etest comment 1\u003c/event\u003e\n\t\t\u003c/activity\u003e\n\t\u003c/item\u003e\n\u003c/items\u003e\n\u003c/rsp\u003e\n```\n    \nNote how the `\u003cactivity\u003e` tag can enclose *either* one *or* more \n`\u003cevent\u003e` tags. This is actually a gray area of Flickr API and I'm not \nentirely sure if I should write that exception into the book (*i.e.* the\nlogic of `OFXMLMapper`, which handles the job). The list of exceptions\ncould never be comprehensive.\n\nWe can make good use of Objective-C's dynamic nature to work around the\nproblem. We can tell if it's an array:\n\n```obj-c\n// get the first element in the items\nNSArray *itemArray = [responseDict valueForKeyPath:@\"items.item\"];\nNSDictionary *firstItem = [itemArray objectAtIndex:0];\n\n// get the \"event\" element and see if it's an array\nid event = [firstItem valueForKeyPath:@\"activity.event\"];\n    \nif ([event isKindOfClass:[NSArray class]]) {\n    // it has more than one elements\n    NSDictionary *someEvent = [event objectAtIndex:0];\n}\nelse {\n    // that's the only element\n    NSDictionary *someEvent = event;\n}\n```\n    \nOn the other hand, the reason why we build the plural tag rule in \n`OFXMLMapper` is that writing the boilerplate above for frequently-used\ntags again and again is very tedious. Since `OFXMLMapper` already handles\nthe plural tags, the borderline cases are easier to tackle.\n    \n\nDesign Patterns and Tidbits\n===========================\n\nDesign Your Own Trampolines\n---------------------------\n\n`OFFlickrAPIRequest` has a `sessionInfo` property that you can use to provide\nstate information of your app. However, it will soon become tedious to write\ntons of `if`-`else`s in the delegate methods. My experience is that I design\na customized \"session\" object with three properties: delegate (that doesn't\nhave to be the originator of the request), selector to call on completion,\nselector to call on error. Then the delegate methods for `OFFlickrAPIRequest`\nsimply dispatches the callbacks according to the session object.\n\nIf your controller calls a number of Flickr methods or involves multiple\nstages/states, this design pattern will be helpful.\n\nThread-Safety\n-------------\n\nEach OFFlickrAPIRequest object can be used in the thread on which it is created. Do not pass them across threads. Delegate methods are also called in the thread in which the request object is running.\n\nCFNetwork-Based\n---------------\n\nObjectiveFlickr uses LFHTTPRequest, which uses only the CFNetwork stack.\nNSURLConnection is reported to have its own headaches. On the other hand,\nLFHTTPRequest does not handle non-HTTP URLs (it does handle HTTPS with\na catch: on iPhone you cannot use untrusted root certs) and does not do\nHTTP authentication. It also does not manage caching. For web API\nintegration, however, LFHTTPRequest provides a lean way of making and\nmanaging requests.\n\nOne side note: LFHTTPRequest will use your system's shared proxy settings\non your Mac or iPhone. This is how it requires `SystemConfiguration.framework`\non Mac when being built alone.\n\n\nPossible Migration Path from ObjectiveFlickr 0.9.x\n--------------------------------------------------\n\nI didn't really seriously investigate this, but here are some thoughts:\n\n* In theory 0.9.x and 2.0 should co-exist as there is no class name clashes.\n* OFFlickrContext becomes OFFlickrAPIContext\n* OFFlickrInvocation becomes OFFlickrAPIRequest\n* OFFlickrUploader is now merged into OFFlickrAPIRequest\n* Delegate methods are greatly simplified and redesigned\n\n\n\n\nHistory\n=======\n\nObjectiveFlickr was first released in late 2006. The previous version, 0.9.x,\nhas undergone one rewrite and is hosted on [Google \nCode](https://code.google.com/p/objectiveflickr/). It also has a Ruby version\navailable as a [Ruby gem](http://rubyforge.org/frs/?group_id=2698).\n\nThe present rewrite derives from the experiences that I have had in\ndeveloping Mac and iPhone products (I run my own company, [Lithoglyph](lithoglyph.com)). It's a great learning process.\n\n\nAcknowledgements\n================\n\nMany people have given kind suggestions and directions to the development\nof ObjectiveFlickr. And there are a number of Mac apps that use it. I'd like\nto thank Mathieu Tozer, Tristan O'Tierney, Christoph Priebe, Yung-Lun Lan, \nand Pierre Bernard for the feedbacks that eventually lead to the framework's\npresent design and shape.\n\n\nCopyright and Software License\n==============================\n\nObjectiveFlickr Copyright (c) 2006-2009 Lukhnos D. Liu.\n\nLFWebAPIKit Copyright (c) 2007-2009 Lukhnos D. Liu and Lithoglyph Inc.\n\nOne test in LFWebAPIKit (`Tests/StreamedBodySendingTest`) makes\nuse of [Google Toolbox for Mac](\nhttps://github.com/google/google-toolbox-for-mac), Copyright (c) 2008 Google Inc. Refer to `COPYING.txt` in the directory for the full text of the Apache License, Version 2.0, under which the said software is licensed.\n\nBoth ObjectiveFlickr and LFWebAPIKit are released under the MIT license,\nthe full text of which is printed here as follows. You can also \nfind the text at: \u003chttps://opensource.org/licenses/mit-license.php\u003e\n\nPermission is hereby granted, free of charge, to any person\nobtaining a copy of this software and associated documentation\nfiles (the \"Software\"), to deal in the Software without\nrestriction, including without limitation the rights to use,\ncopy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following\nconditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES\nOF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\nNONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT\nHOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,\nWHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR\nOTHER DEALINGS IN THE SOFTWARE.\n\nContact\n=======\n\n* lukhnos {at} lukhnos {dot} org\n\n\nLinks\n=====\n\n* Project host: \u003chttps://github.com/lukhnos/objectiveflickr\u003e\n* Discussion group: \u003chttp://groups.google.com/group/objectiveflickr\u003e\n* Issue tracking: \u003chttp://code.google.com/p/objectiveflickr/issues/list\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukhnos%2Fobjectiveflickr","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flukhnos%2Fobjectiveflickr","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flukhnos%2Fobjectiveflickr/lists"}