<commit_before># CocoaLibSpotify #

CocoaLibSpotify is an Objective-C wrapper around our libspotify library. It provides easy access to libspotify's features in a friendly, KVC/O compliant Objective-C wrapper.

CocoaLibSpotify requires libspotify.framework, which isn't 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.

## Release Notes ##

You can find the latest release notes in the [CHANGELOG.markdown](https://github.com/spotify/cocoalibspotify/blob/master/CHANGELOG.markdown) file.

## Threading ##

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.

However, libSpotify is **not** 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 use libDispatch to call the relevant API on the correct queue, which `SPSession` provides an accessor for.

Bad:

```
sp_artist *artist = …; // An artist.
SPArtist *artistObj = [SPArtist artistWithArtistStruct:artist inSession:session];
// ^ The above line will throw an assertion for being called on the wrong queue.
```

Instead, you should create the object on the correct thread and safely pass it back to the target queue (the main queue if you're doing UI work) for further use:

```
SPDispatchAsync(^{
	sp_artist *artist = …; // An artist.
	SPArtist *artistObj = [SPArtist artistWithArtistStruct:artist inSession:session];
	dispatch_async(dispatch_get_main_queue(), ^{ self.artist = artistObj; });
});
```

CocoaLibSpotify provides three macros to assist with threading:

- `SPDispatchAsync()` takes a block and executes it asynchronously on the libSpotify thread. It works very much like libdispatch's `dispatch_async`.

- `SPDispatchSyncIfNeeded()` 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 `SPDispatchAsync()` is always recommended.

- `SPAssertOnLibSpotifyThread()` will throw an assertion when called from anything but the libSpotify thread. This can be useful for debugging code using the libSpotify thread.

## A Note On "Loading" ##

CocoaLibSpotify does a lot of asynchronous loading — 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.
<commit_msg>Fix mistake in README<commit_after># CocoaLibSpotify #

CocoaLibSpotify is an Objective-C wrapper around our libspotify library. It provides easy access to libspotify's features in a friendly, KVC/O compliant Objective-C wrapper.

CocoaLibSpotify requires libspotify.framework, which isn't 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.

## Release Notes ##

You can find the latest release notes in the [CHANGELOG.markdown](https://github.com/spotify/cocoalibspotify/blob/master/CHANGELOG.markdown) file.

## Threading ##

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.

However, libSpotify is **not** 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 `SPSession` provides various helper macros for.

Bad:

```
sp_artist *artist = …; // An artist.
SPArtist *artistObj = [SPArtist artistWithArtistStruct:artist inSession:session];
// ^ The above line will throw an assertion for being called on the wrong queue.
```

Instead, you should create the object on the correct thread and safely pass it back to the target queue (the main queue if you're doing UI work) for further use:

```
SPDispatchAsync(^{
	sp_artist *artist = …; // An artist.
	SPArtist *artistObj = [SPArtist artistWithArtistStruct:artist inSession:session];
	dispatch_async(dispatch_get_main_queue(), ^{ self.artist = artistObj; });
});
```

CocoaLibSpotify provides three macros to assist with threading:

- `SPDispatchAsync()` takes a block and executes it asynchronously on the libSpotify thread. It works very much like libdispatch's `dispatch_async`.

- `SPDispatchSyncIfNeeded()` 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 `SPDispatchAsync()` is always recommended.

- `SPAssertOnLibSpotifyThread()` will throw an assertion when called from anything but the libSpotify thread. This can be useful for debugging code using the libSpotify thread.

## A Note On "Loading" ##

CocoaLibSpotify does a lot of asynchronous loading — 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.

{'fraction_non_alphanumeric': 0.0605759682224429, 'fraction_numerical': 0.0006620324395895399, 'mean_word_length': 5.0551102204408815, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4176608', 'n_tokens_mistral': 1648, 'n_tokens_neox': 1542, 'n_words': 797}