Skip to content

Commit

Permalink
Added AEWeakRetainingProxy
Browse files Browse the repository at this point in the history
This also fixes an issue with a few classes being prematurely released when their references are set to nil from a timer callback
  • Loading branch information
michaeltyson committed Jun 8, 2016
1 parent b5c26bd commit 1024ff0
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 68 deletions.
16 changes: 16 additions & 0 deletions TheAmazingAudioEngine.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,12 @@
4CDCADAD1CAB89CF008AAEF1 /* AEArray.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CDCADAB1CAB89CF008AAEF1 /* AEArray.m */; };
4CDCADB51CABDE68008AAEF1 /* AEAudioUnitOutput.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CDCADB31CABDE62008AAEF1 /* AEAudioUnitOutput.h */; settings = {ATTRIBUTES = (Public, ); }; };
4CDCADBB1CAC95A8008AAEF1 /* AEAudioUnitOutput.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CDCADB41CABDE62008AAEF1 /* AEAudioUnitOutput.m */; };
4CE10C2D1D07E507004AA02C /* AEWeakRetainingProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE10C291D07E507004AA02C /* AEWeakRetainingProxy.m */; };
4CE10C2E1D07E507004AA02C /* AEWeakRetainingProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE10C291D07E507004AA02C /* AEWeakRetainingProxy.m */; };
4CE10C2F1D07E507004AA02C /* AEWeakRetainingProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 4CE10C291D07E507004AA02C /* AEWeakRetainingProxy.m */; };
4CE10C301D07E510004AA02C /* AEWeakRetainingProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CE10C281D07E507004AA02C /* AEWeakRetainingProxy.h */; settings = {ATTRIBUTES = (Public, ); }; };
4CE10C311D07E510004AA02C /* AEWeakRetainingProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CE10C281D07E507004AA02C /* AEWeakRetainingProxy.h */; settings = {ATTRIBUTES = (Public, ); }; };
4CE10C321D07E510004AA02C /* AEWeakRetainingProxy.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CE10C281D07E507004AA02C /* AEWeakRetainingProxy.h */; settings = {ATTRIBUTES = (Public, ); }; };
4CE5F4BC1CD2F2CE00322F03 /* TPCircularBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CDCAD1F1CA3A67A008AAEF1 /* TPCircularBuffer.h */; settings = {ATTRIBUTES = (Public, ); }; };
4CE5F4BD1CD2F2CF00322F03 /* TPCircularBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CDCAD1F1CA3A67A008AAEF1 /* TPCircularBuffer.h */; settings = {ATTRIBUTES = (Public, ); }; };
4CE5F4BE1CD2F2CF00322F03 /* TPCircularBuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CDCAD1F1CA3A67A008AAEF1 /* TPCircularBuffer.h */; settings = {ATTRIBUTES = (Public, ); }; };
Expand Down Expand Up @@ -407,6 +413,8 @@
4CDCADAB1CAB89CF008AAEF1 /* AEArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AEArray.m; sourceTree = "<group>"; };
4CDCADB31CABDE62008AAEF1 /* AEAudioUnitOutput.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AEAudioUnitOutput.h; sourceTree = "<group>"; };
4CDCADB41CABDE62008AAEF1 /* AEAudioUnitOutput.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AEAudioUnitOutput.m; sourceTree = "<group>"; };
4CE10C281D07E507004AA02C /* AEWeakRetainingProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AEWeakRetainingProxy.h; sourceTree = "<group>"; };
4CE10C291D07E507004AA02C /* AEWeakRetainingProxy.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AEWeakRetainingProxy.m; sourceTree = "<group>"; };
4CE5F4C21CD30A1900322F03 /* AEMainThreadEndpoint.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AEMainThreadEndpoint.h; sourceTree = "<group>"; };
4CE5F4C31CD30A1900322F03 /* AEMainThreadEndpoint.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AEMainThreadEndpoint.m; sourceTree = "<group>"; };
4CE5F4CA1CD3135800322F03 /* AECrossThreadMessagingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AECrossThreadMessagingTests.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -582,6 +590,8 @@
4CDCAD321CA3C31C008AAEF1 /* AEMessageQueue.m */,
4C43E5A71CF131290000DB62 /* AEAudioFileReader.h */,
4C43E5A81CF131290000DB62 /* AEAudioFileReader.m */,
4CE10C281D07E507004AA02C /* AEWeakRetainingProxy.h */,
4CE10C291D07E507004AA02C /* AEWeakRetainingProxy.m */,
);
path = Utilities;
sourceTree = "<group>";
Expand Down Expand Up @@ -658,6 +668,7 @@
4C9F0F531CB265F90032903E /* AEUtilities.h in Headers */,
4C43E5A21CF066B20000DB62 /* AETime.h in Headers */,
4CE5F4BD1CD2F2CF00322F03 /* TPCircularBuffer.h in Headers */,
4CE10C311D07E510004AA02C /* AEWeakRetainingProxy.h in Headers */,
4C9F0F541CB265F90032903E /* AENewTimePitchModule.h in Headers */,
4C9F0F551CB265F90032903E /* AEAudioFilePlayerModule.h in Headers */,
4CE5F4C51CD30A1900322F03 /* AEMainThreadEndpoint.h in Headers */,
Expand Down Expand Up @@ -707,6 +718,7 @@
4C9F0F9C1CB269C30032903E /* AEUtilities.h in Headers */,
4C43E5A31CF066B20000DB62 /* AETime.h in Headers */,
4CE5F4BE1CD2F2CF00322F03 /* TPCircularBuffer.h in Headers */,
4CE10C301D07E510004AA02C /* AEWeakRetainingProxy.h in Headers */,
4C9F0F9D1CB269C30032903E /* AENewTimePitchModule.h in Headers */,
4C9F0F9E1CB269C30032903E /* AEAudioFilePlayerModule.h in Headers */,
4CE5F4C61CD30A1900322F03 /* AEMainThreadEndpoint.h in Headers */,
Expand Down Expand Up @@ -781,6 +793,7 @@
4CDCACEB1CA25B6F008AAEF1 /* TheAmazingAudioEngine.h in Headers */,
4CE5F4CE1CD3169C00322F03 /* AEAudioThreadEndpoint.h in Headers */,
4C9F0F251CB224D70032903E /* AEIOAudioUnit.h in Headers */,
4CE10C321D07E510004AA02C /* AEWeakRetainingProxy.h in Headers */,
4C94E2C91CAF95BD006EB497 /* AEManagedValue.h in Headers */,
4CE5F4C41CD30A1900322F03 /* AEMainThreadEndpoint.h in Headers */,
4C43E5A91CF131290000DB62 /* AEAudioFileReader.h in Headers */,
Expand Down Expand Up @@ -941,6 +954,7 @@
4CBCF2A21CFBC3D200CA2EA0 /* AESplitterModule.m in Sources */,
4C9F0F381CB265F90032903E /* AELowShelfModule.m in Sources */,
4C9F0F391CB265F90032903E /* AEAudioUnitInputModule.m in Sources */,
4CE10C2E1D07E507004AA02C /* AEWeakRetainingProxy.m in Sources */,
4C9F0F3A1CB265F90032903E /* AEBufferStack.m in Sources */,
4C9F0F3B1CB265F90032903E /* AEModule.m in Sources */,
4C9F0F3C1CB265F90032903E /* AEDistortionModule.m in Sources */,
Expand Down Expand Up @@ -989,6 +1003,7 @@
4CBCF2A31CFBC3D200CA2EA0 /* AESplitterModule.m in Sources */,
4C9F0F821CB269C30032903E /* AELowShelfModule.m in Sources */,
4C9F0F831CB269C30032903E /* AEAudioUnitInputModule.m in Sources */,
4CE10C2F1D07E507004AA02C /* AEWeakRetainingProxy.m in Sources */,
4C9F0F841CB269C30032903E /* AEBufferStack.m in Sources */,
4C9F0F851CB269C30032903E /* AEModule.m in Sources */,
4C9F0F861CB269C30032903E /* AEDistortionModule.m in Sources */,
Expand Down Expand Up @@ -1063,6 +1078,7 @@
4CDCAD9D1CA90F98008AAEF1 /* AEAudioUnitModule.m in Sources */,
4CBCF2A11CFBC3D200CA2EA0 /* AESplitterModule.m in Sources */,
4CDCAD8F1CA5484D008AAEF1 /* AEReverbModule.m in Sources */,
4CE10C2D1D07E507004AA02C /* AEWeakRetainingProxy.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Expand Down
19 changes: 2 additions & 17 deletions TheAmazingAudioEngine/Core Types/AEManagedValue.m
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#import <libkern/OSAtomic.h>
#import <pthread.h>
#import "AEUtilities.h"
#import "AEWeakRetainingProxy.h"

typedef struct __linkedlistitem_t {
void * data;
Expand All @@ -52,10 +53,6 @@ @interface AEManagedValue () {
@property (nonatomic, strong) NSTimer * pollTimer;
@end

@interface AEManagedValueProxy : NSProxy
@property (nonatomic, weak) AEManagedValue * target;
@end

@implementation AEManagedValue
@dynamic objectValue, pointerValue;

Expand Down Expand Up @@ -196,9 +193,7 @@ - (void)setValue:(void *)value {

if ( !self.pollTimer ) {
// Start polling for pending releases
AEManagedValueProxy * proxy = [AEManagedValueProxy alloc];
proxy.target = self;
self.pollTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:proxy
self.pollTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:[AEWeakRetainingProxy proxyWithTarget:self]
selector:@selector(pollReleaseList) userInfo:nil repeats:YES];
}
}
Expand Down Expand Up @@ -268,13 +263,3 @@ - (void)releaseOldValue:(void *)value {
}

@end

@implementation AEManagedValueProxy
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [_target methodSignatureForSelector:selector];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation setTarget:_target];
[invocation invoke];
}
@end
14 changes: 0 additions & 14 deletions TheAmazingAudioEngine/Modules/Generation/AEAudioFilePlayerModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,6 @@ @interface AEAudioFilePlayerModule () {
@property (nonatomic, copy) void(^beginBlock)();
@end

@interface AEAudioFilePlayerModuleWeakProxy : NSProxy
@property (nonatomic, weak) id target;
@end

@implementation AEAudioFilePlayerModule

- (instancetype)initWithRenderer:(AERenderer *)renderer URL:(NSURL *)url error:(NSError *__autoreleasing *)error {
Expand Down Expand Up @@ -597,13 +593,3 @@ static void AEAudioFilePlayerModuleProcess(__unsafe_unretained AEAudioFilePlayer
}

@end

@implementation AEAudioFilePlayerModuleWeakProxy
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [_target methodSignatureForSelector:selector];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation setTarget:_target];
[invocation invoke];
}
@end
22 changes: 3 additions & 19 deletions TheAmazingAudioEngine/Modules/Taps/AEAudioFileRecorderModule.m
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#import "AEUtilities.h"
#import "AETypes.h"
#import "AEAudioBufferListUtilities.h"

#import "AEWeakRetainingProxy.h"
#import <AudioToolbox/AudioToolbox.h>

@interface AEAudioFileRecorderModule () {
Expand All @@ -25,10 +25,6 @@ @interface AEAudioFileRecorderModule () {
@property (nonatomic, strong) NSTimer * pollTimer;
@end

@interface AEAudioFileRecorderModuleWeakProxy : NSProxy
@property (nonatomic, weak) id target;
@end

@implementation AEAudioFileRecorderModule

- (instancetype)initWithRenderer:(AERenderer *)renderer URL:(NSURL *)url
Expand Down Expand Up @@ -64,10 +60,8 @@ - (void)beginRecordingAtTime:(AEHostTicks)time {
- (void)stopRecordingAtTime:(AEHostTicks)time completionBlock:(AEAudioFileRecorderModuleCompletionBlock)block {
self.completionBlock = block;
_stopTime = time ? time : AECurrentTimeInHostTicks();
AEAudioFileRecorderModuleWeakProxy * proxy = [AEAudioFileRecorderModuleWeakProxy alloc];
proxy.target = self;
self.pollTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:proxy selector:@selector(pollForCompletion)
userInfo:nil repeats:YES];
self.pollTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:[AEWeakRetainingProxy proxyWithTarget:self]
selector:@selector(pollForCompletion) userInfo:nil repeats:YES];
}

static void AEAudioFileRecorderModuleProcess(__unsafe_unretained AEAudioFileRecorderModule * THIS,
Expand Down Expand Up @@ -145,13 +139,3 @@ - (void)finishWriting {
}

@end

@implementation AEAudioFileRecorderModuleWeakProxy
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [_target methodSignatureForSelector:selector];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation setTarget:_target];
[invocation invoke];
}
@end
1 change: 1 addition & 0 deletions TheAmazingAudioEngine/TheAmazingAudioEngine.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ extern "C" {
#import <TheAmazingAudioEngine/AEManagedValue.h>
#import <TheAmazingAudioEngine/AEIOAudioUnit.h>
#import <TheAmazingAudioEngine/AEAudioFileReader.h>
#import <TheAmazingAudioEngine/AEWeakRetainingProxy.h>


/*!
Expand Down
21 changes: 3 additions & 18 deletions TheAmazingAudioEngine/Utilities/AEMainThreadEndpoint.m
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#import "AEMainThreadEndpoint.h"
#import "TPCircularBuffer.h"
#import "AEWeakRetainingProxy.h"

@interface AEMainThreadEndpoint () {
TPCircularBuffer _buffer;
Expand All @@ -34,10 +35,6 @@ @interface AEMainThreadEndpoint () {
@property (nonatomic, strong) NSTimer * timer;
@end

@interface AEMainThreadEndpointProxy : NSProxy
@property (nonatomic, weak) AEMainThreadEndpoint * target;
@end

@implementation AEMainThreadEndpoint

- (instancetype)initWithHandler:(AEMainThreadEndpointHandler)handler {
Expand Down Expand Up @@ -120,10 +117,8 @@ void AEMainThreadEndpointDispatchMessage(__unsafe_unretained AEMainThreadEndpoin
}

- (void)startTimer {
AEMainThreadEndpointProxy * proxy = [AEMainThreadEndpointProxy alloc];
proxy.target = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:self.pollInterval target:proxy selector:@selector(poll)
userInfo:nil repeats:YES];
self.timer = [NSTimer scheduledTimerWithTimeInterval:self.pollInterval target:[AEWeakRetainingProxy proxyWithTarget:self]
selector:@selector(poll) userInfo:nil repeats:YES];
}

- (void)poll {
Expand All @@ -146,13 +141,3 @@ - (void)poll {
}

@end

@implementation AEMainThreadEndpointProxy
- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [_target methodSignatureForSelector:selector];
}
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation setTarget:_target];
[invocation invoke];
}
@end
50 changes: 50 additions & 0 deletions TheAmazingAudioEngine/Utilities/AEWeakRetainingProxy.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
//
// AEWeakRetainingProxy.h
// TheAmazingAudioEngine
//
// Created by Michael Tyson on 8/06/2016.
// Copyright © 2016 A Tasty Pixel. All rights reserved.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//

#ifdef __cplusplus
extern "C" {
#endif

#import <Foundation/Foundation.h>

/*!
* Weak Retaining Proxy
*
* This proxy class is useful to avoid a retain cycle when using an NSTimer
* retained by the instance that is the timer's target. It's used in a number
* of places throughout TAAE.
*/
@interface AEWeakRetainingProxy : NSProxy

+ (instancetype _Nonnull)proxyWithTarget:(id _Nonnull)target;

@property (nonatomic, weak, readonly) id _Nullable target;

@end

#ifdef __cplusplus
}
#endif
51 changes: 51 additions & 0 deletions TheAmazingAudioEngine/Utilities/AEWeakRetainingProxy.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
//
// AEWeakRetainingProxy.m
// TheAmazingAudioEngine
//
// Created by Michael Tyson on 8/06/2016.
// Copyright © 2016 A Tasty Pixel. All rights reserved.
//
// This software is provided 'as-is', without any express or implied
// warranty. In no event will the authors be held liable for any damages
// arising from the use of this software.
//
// Permission is granted to anyone to use this software for any purpose,
// including commercial applications, and to alter it and redistribute it
// freely, subject to the following restrictions:
//
// 1. The origin of this software must not be misrepresented; you must not
// claim that you wrote the original software. If you use this software
// in a product, an acknowledgment in the product documentation would be
// appreciated but is not required.
//
// 2. Altered source versions must be plainly marked as such, and must not be
// misrepresented as being the original software.
//
// 3. This notice may not be removed or altered from any source distribution.
//

#import "AEWeakRetainingProxy.h"

@interface AEWeakRetainingProxy ()
@property (nonatomic, weak, readwrite) id target;
@end

@implementation AEWeakRetainingProxy

+ (instancetype)proxyWithTarget:(id)target {
AEWeakRetainingProxy * proxy = [AEWeakRetainingProxy alloc];
proxy.target = target;
return proxy;
}

- (NSMethodSignature *)methodSignatureForSelector:(SEL)selector {
return [_target methodSignatureForSelector:selector];
}

- (void)forwardInvocation:(NSInvocation *)invocation {
__strong id target = _target;
[invocation setTarget:target];
[invocation invoke];
}

@end

0 comments on commit 1024ff0

Please sign in to comment.