Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
//
// FunctionPointer.h
// AudioServicesTest
//
// Created by Julius Parishy on 11/9/14.
// Copyright (c) 2014 Julius Parishy. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <AudioToolbox/AudioToolbox.h>
typedef void(^AudioServicesCompletionBlock)(SystemSoundID soundID, void *userData);
@interface AudioServicesCompletionFunctionPointer : NSObject
/*
* Pass the same SystemSoundID & userData you pass to `AudioServicesAddSystemSoundCompletion`.
* `block` is the block you'd like to be called for the completion handler.
*
* A weak reference is held to the instance returned so you must keep it alive by
* holding a strong reference or it will be deallocated prematurely.
*/
- (instancetype)initWithSystemSoundID:(SystemSoundID)systemSoundID block:(AudioServicesCompletionBlock)block userData:(void *)userData;
/*
* Pass this as the completion handler to `AudioServicesAddSystemSoundCompletion`
*/
+ (AudioServicesSystemSoundCompletionProc)completionHandler;
@end
//
// FunctionPointer.m
// AudioServicesTest
//
// Created by Julius Parishy on 11/9/14.
// Copyright (c) 2014 Julius Parishy. All rights reserved.
//
#import "FunctionPointer.h"
void AudioServicesSystemSoundDidComplete(SystemSoundID soundID, void *userData);
@interface AudioServicesCompletionFunctionPointer ()
@property (nonatomic, assign) SystemSoundID systemSoundID;
@property (nonatomic, unsafe_unretained) void *userData;
@property (nonatomic, copy) AudioServicesCompletionBlock completionBlock;
@end
@implementation AudioServicesCompletionFunctionPointer
+ (NSMapTable *)sharedMapTable
{
static NSMapTable *mapTable = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
mapTable = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsStrongMemory valueOptions:NSPointerFunctionsWeakMemory];
});
return mapTable;
}
- (instancetype)initWithSystemSoundID:(SystemSoundID)systemSoundID block:(AudioServicesCompletionBlock)block userData:(void *)userData
{
if((self = [super init]))
{
self.systemSoundID = systemSoundID;
self.userData = userData;
self.completionBlock = block;
NSMapTable *mapTable = self.class.sharedMapTable;
NSValue *key = [NSValue valueWithPointer:self.userData];
[mapTable setObject:self forKey:key];
}
return self;
}
- (void)dealloc
{
NSMapTable *mapTable = self.class.sharedMapTable;
NSValue *key = [NSValue valueWithPointer:_userData];
[mapTable removeObjectForKey:key];
}
+ (AudioServicesSystemSoundCompletionProc)completionHandler
{
return &AudioServicesSystemSoundDidComplete;
}
@end
void AudioServicesSystemSoundDidComplete(SystemSoundID soundID, void *userData)
{
NSMapTable *mapTable = [AudioServicesCompletionFunctionPointer sharedMapTable];
NSValue *key = [NSValue valueWithPointer:userData];
AudioServicesCompletionFunctionPointer *functionPointer = (AudioServicesCompletionFunctionPointer *)[mapTable objectForKey:key];
NSCAssert(functionPointer != nil, @"No block for this userData found.");
if(functionPointer.systemSoundID != soundID)
return;
AudioServicesCompletionBlock block = functionPointer.completionBlock;
block(soundID, userData);
}
//
// ViewController.swift
// AudioServicesTest
//
// Created by Julius Parishy on 11/9/14.
// Copyright (c) 2014 Julius Parishy. All rights reserved.
//
import UIKit
import AudioToolbox
class ViewController: UIViewController {
var functionPointer: AudioServicesCompletionFunctionPointer?
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let inSystemSoundID = SystemSoundID(kSystemSoundID_Vibrate)
let block = {
(systemSoundID: SystemSoundID, userData: UnsafeMutablePointer<Void>) in
println("Completed!")
}
var vself = self
let userData = withUnsafePointer(&vself, {
(ptr: UnsafePointer<ViewController>) -> UnsafeMutablePointer<Void> in
return unsafeBitCast(ptr, UnsafeMutablePointer<Void>.self)
})
self.functionPointer = AudioServicesCompletionFunctionPointer(systemSoundID: inSystemSoundID, block: block, userData: userData)
AudioServicesAddSystemSoundCompletion(inSystemSoundID, CFRunLoopGetMain(), kCFRunLoopCommonModes, AudioServicesCompletionFunctionPointer.completionHandler(), userData)
}
@IBAction func vibrateButtonPressed(button: UIButton) {
let systemSoundID = SystemSoundID(kSystemSoundID_Vibrate)
AudioServicesPlaySystemSound(systemSoundID)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment