{"id":7950,"date":"2015-11-12T03:12:33","date_gmt":"2015-11-12T03:12:33","guid":{"rendered":"https:\/\/unknownerror.org\/index.php\/2015\/11\/12\/spotify-cocoalibspotify\/"},"modified":"2015-11-12T03:12:33","modified_gmt":"2015-11-12T03:12:33","slug":"spotify-cocoalibspotify","status":"publish","type":"post","link":"https:\/\/unknownerror.org\/index.php\/2015\/11\/12\/spotify-cocoalibspotify\/","title":{"rendered":"spotify\/cocoalibspotify"},"content":{"rendered":"<p>CocoaLibSpotify is an Objective-C wrapper around our libspotify library. It provides easy access to libspotify\u2019s features in a friendly, KVC\/O compliant Objective-C wrapper.<\/p>\n<p>CocoaLibSpotify requires libspotify.framework, which isn\u2019t included in the repository. The Mac Framework and iOS Library Xcode projects include a build step to download and unpack it from developer.spotify.com automatically. If this fails for some reason, download it manually from developer.spotify.com and unpack it into the project folder.<\/p>\n<h2>Release Notes<\/h2>\n<p>You can find the latest release notes in the CHANGELOG.markdown file.<\/p>\n<h2>Threading<\/h2>\n<p>As of CocoaLibSpotify 2.0, the framework uses an internal threading model to run the libSpotify library on a background thread, allowing your application to remain responsive when libSpotify is experiencing heavy load.<\/p>\n<p>However, libSpotify is <strong>not<\/strong> thread-safe, and all methods in CocoaLibSpotify that provide access to libSpotify types are guarded to prevent access from the wrong thread. If you must access libSpotify types directly, first file an issue so we can make a thread-aware API in CocoaLibSpotify for your use case, then make sure you call the relevant API on the correct thread, which <code>SPSession<\/code> provides various helper macros for.<\/p>\n<p>Bad:<\/p>\n<pre><code>sp_artist *artist = \u2026; \/\/ An artist.\nSPArtist *artistObj = [SPArtist artistWithArtistStruct:artist inSession:session];\n\/\/ ^ The above line will throw an assertion for being called on the wrong queue.\n<\/code><\/pre>\n<p>Instead, you should create the object on the correct thread and safely pass it back to the target queue (the main queue if you\u2019re doing UI work) for further use:<\/p>\n<pre><code>SPDispatchAsync(^{\n    sp_artist *artist = \u2026; \/\/ An artist.\n    SPArtist *artistObj = [SPArtist artistWithArtistStruct:artist inSession:session];\n    dispatch_async(dispatch_get_main_queue(), ^{ self.artist = artistObj; });\n});\n<\/code><\/pre>\n<p>CocoaLibSpotify provides three macros to assist with threading:<\/p>\n<ul>\n<li>\n<p><code>SPDispatchAsync()<\/code> takes a block and executes it asynchronously on the libSpotify thread. It works very much like libdispatch\u2019s <code>dispatch_async<\/code>.<\/p>\n<\/li>\n<li>\n<p><code>SPDispatchSyncIfNeeded()<\/code> takes a block and executes it synchronously on the libSpotify thread, blocking the current code path until completion. Since the libSpotify thread executes blocks on a first-come, first-served basis, internal work may delay execution for a significant amount of time, so using <code>SPDispatchAsync()<\/code> is always recommended.<\/p>\n<\/li>\n<li>\n<p><code>SPAssertOnLibSpotifyThread()<\/code> will throw an assertion when called from anything but the libSpotify thread. This can be useful for debugging code using the libSpotify thread.<\/p>\n<\/li>\n<\/ul>\n<h2>A Note On \u201cLoading\u201d<\/h2>\n<p>CocoaLibSpotify does a lot of asynchronous loading \u2014 tracks, playlists, artists, albums, etc can all finish loading their metadata after you get an object. In the case of user playlists and searching, this can be a number of seconds.<\/p>\n<p>Do <em>not<\/em> poll these properties &#8211; when you do a polling loop you can, in many cases, stop CocoaLibSpotify\u2019s ability to do any work, causing the metadata to never load.<\/p>\n<p>Instead, most objects in the CocoaLibSpotify object model (including metadata classes like <code>SPArtist<\/code>, <code>SPTrack<\/code>, <code>SPAlbum<\/code>, etc and \u201caction\u201d classes like <code>SPSearch<\/code> etc) conform to the <code>SPAsyncLoading<\/code> protocol, and you can use the <code>SPAsyncLoading<\/code> helper class to get a block callback when the given item(s) are loaded. For example:<\/p>\n<pre><code>    NSArray *someTracks = \u2026; \/\/ Some tracks.\n\n    [SPAsyncLoading waitUntilLoaded:someTracks timeout:10.0 then:^(NSArray *loadedTracks, NSArray *notLoadedTracks) {\n\n        NSLog(@\"The following tracks are loaded: %@\", loadedTracks);\n    }];\n<\/code><\/pre>\n<p>Additionally, CocoaLibSpotify\u2019s properties are Key-Value Observing compliant, and the best practice is to add an observer to the properties you\u2019re interested in to receive a notification callback when the metadata is loaded.<\/p>\n<p>For example, if you want to know when search results come back, add an observer like this:<\/p>\n<pre><code>[self addObserver:self forKeyPath:@\"search.tracks\" options:0 context:nil];\nself.search = [SPSearch searchWithSearchQuery:@\"Hello\" inSession:[SPSession sharedSession]];\n<\/code><\/pre>\n<p>When the tracks in the search are updated, you\u2019ll get a callback:<\/p>\n<pre><code>- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {\n\n    if ([keyPath isEqualToString:@\"search.tracks\"])\n        NSLog(@\"Search found tracks: %@\", self.search.tracks);\n}\n<\/code><\/pre>\n<p>Key-Value Observing is a core technology in the Mac and iOS SDKs, and extensive documentation and examples can be found in Apple\u2019s developer documentation.<\/p>\n<h2>Building &#8211; Mac OS X<\/h2>\n<p>The Xcode project requires Xcode 4.5 and Mac OS X 10.7 to build since it uses ARC. However, the built binary can be deployed on 64-bit systems running Mac OS X 10.6 or higher.<\/p>\n<p>The built CocoaLibSpotify.framework contains libspotify.framework as a child framework. Sometimes, Xcode gives build errors complaining it can\u2019t find . If you get this, manually add the directory libspotify.framework is in to your project\u2019s \u201cFramework Search Paths\u201d build setting. For example, if you\u2019re building the CocoaLibSpotify project alongside your application as an embedded Xcode project then copying it into your bundle, you\u2019d have this:<\/p>\n<p><code>$CONFIGURATION_BUILD_DIR\/CocoaLibSpotify.framework\/Versions\/Frameworks<\/code><\/p>\n<p>Otherwise, you\u2019d point to the downloaded libspotify.framework manually, something like this:<\/p>\n<p><code>..\/..\/libspotify-12.1.45-Darwin-universal<\/code><\/p>\n<h2>Building &#8211; iOS<\/h2>\n<p>The Xcode project requires Xcode 4.5 and iOS SDK version 6.0+ to build since it uses ARC. However, the built binary can be deployed on any iOS version from version 4.0.<\/p>\n<p>The built libCocoaLibSpotify contains libspotify internally as a static library, as well as all of the required header files in a directory called \u201cinclude\u201d.<\/p>\n<p>In addition, you MUST include SPLoginResources.bundle as a resource of your application.<\/p>\n<p>When including libCocoaLibSpotify in your application, you must also link to the following frameworks:<\/p>\n<ul>\n<li>SystemConfiguration.framework<\/li>\n<li>CFNetwork.framework<\/li>\n<li>libstdc++<\/li>\n<li>CoreAudio.framework<\/li>\n<li>AudioToolbox.framework<\/li>\n<li>AVFoundation.framework<\/li>\n<li>Security.framework<\/li>\n<\/ul>\n<p>In addition, you must add the following two items to the \u201cOther Linker Flags\u201d build setting:<\/p>\n<p>If you\u2019re building the CocoaLibSpotify project alongside your application as an embedded Xcode project then linking it with your application in a build step, you can tell Xcode where the header files are by adding the following setting to the \u201cFramework Search Paths\u201d build setting of your project:<\/p>\n<p><code>$CONFIGURATION_BUILD_DIR\/include<\/code><\/p>\n<p>Otherwise, you can simply add all of the header files to your project manually.<\/p>\n<p>Once everything is set up, simply import the following header to get started with CocoaLibSpotify!<\/p>\n<p><code>#import \"CocoaLibSpotify.h\"<\/code><\/p>\n<h2>Documentation<\/h2>\n<p>The headers of CocoaLibSpotify are well documented, and we\u2019ve provided an Xcode DocSet to provide documentation right in Xcode. With these and the sample projects, you should have everything you need to dive right in!<\/p>\n<p>Additionally, there\u2019s an FAQ right here in the repo that covers common usage questions.<\/p>\n<h2>Branching<\/h2>\n<p>All development work is done on the <code>dev<\/code> branch. When it\u2019s considered stable, it\u2019s merged to <code>master<\/code> with a new version tag.<\/p>\n<h2>Unit Tests<\/h2>\n<p>CocoaLibSpotify now ships with a number of unit tests, which run inside a standalone application built by the project. If you find a bug in CocoaLibSpotify, please fork the project, add or modify a unit test <em>on the dev branch<\/em> so it fails (demonstrating the bug), then issue a pull request. We can then fix the underlying bug and keep your test so it stays that way.<\/p>\n<p>To run the tests, open the \u201cCocoaLibSpotify Mac Framework\u201d or \u201cCocoaLibSpotify iOS Library\u201d project as needed, then switch to the \u201cCocoaLSTests\u201d scheme in Xcode. Then:<\/p>\n<ul>\n<li>Generate a Base64 representation of your appkey by downloading the binary version (not the C file) from <code>developer.spotify.com<\/code> and running the following command on it: <code>openssl base64 -in spotify_appkey.key | tr -d '\\n'<\/code>.<\/li>\n<li>Edit the scheme to pass the following arguments on launch: <code>-TestUserName -TestPassword -AppKey<\/code><\/li>\n<li>Run the \u201cCocoaLSTests\u201d target.<\/li>\n<\/ul>\n<p>You\u2019ll find examples on how to make a good test in the tests themselves.<\/p>\n<h2>Contact<\/h2>\n<p>If you have any problems or find any bugs, see our GitHub page for known issues and discussion. For usage questions, please open a question on Stack Overflow with the <code>spotify<\/code> tag. Otherwise, we may be available in irc:\/\/irc.freenode.net\/spotify.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>CocoaLibSpotify is an Objective-C wrapper around our libspotify library. It provides easy access to libspotify\u2019s features in a friendly, KVC\/O compliant Objective-C wrapper. CocoaLibSpotify requires libspotify.framework, which isn\u2019t included in the repository. The Mac Framework and iOS Library Xcode projects include a build step to download and unpack it from developer.spotify.com automatically. If this fails [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[1],"tags":[],"class_list":["post-7950","post","type-post","status-publish","format-standard","hentry","category-uncategorized"],"_links":{"self":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/7950","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/comments?post=7950"}],"version-history":[{"count":0,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/posts\/7950\/revisions"}],"wp:attachment":[{"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/media?parent=7950"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/categories?post=7950"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/unknownerror.org\/index.php\/wp-json\/wp\/v2\/tags?post=7950"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}