Skip to content

Instantly share code, notes, and snippets.

@theoknock
Last active April 19, 2022 21:09
Show Gist options
  • Save theoknock/cf6d8fbb1483128de0532a322cacdaaa to your computer and use it in GitHub Desktop.
Save theoknock/cf6d8fbb1483128de0532a322cacdaaa to your computer and use it in GitHub Desktop.
Thread-safe NSObject array iteration/enumeration
#import <objc/runtime.h>
static __strong id _Nonnull buttons[5];
static __strong const id * _Nonnull (*buttons_t)[5] = &buttons;
static void (^(^map)(id * _Nonnull, const unsigned long))(const void *(^__strong)(const unsigned long)) = ^ (id * _Nonnull obj_collection, const unsigned long index_count) {
__block unsigned long (^recursive_block)(unsigned long);
return ^ (const void * (^enumeration)(const unsigned long)) {
(recursive_block = ^ unsigned long (unsigned long counter) {
obj_collection[counter] = (__bridge id)((__bridge const void * _Nonnull)CFBridgingRelease(enumeration(counter)));
return (unsigned long)((counter += 1) ^ index_count) && (unsigned long)(recursive_block)(counter);
})(0ul);
};
};
/*
Older versions (non-recursive) below
*/
static __strong UIButton * _Nonnull buttons[5];
static void (^(^populate_collection)(__strong UIButton * _Nonnull [_Nonnull 5]))(UIButton * (^__strong)(unsigned int)) = ^ (__strong UIButton * _Nonnull button_collection[5]) {
dispatch_queue_t enumerator_queue = dispatch_queue_create("enumerator_queue", DISPATCH_QUEUE_SERIAL);
return ^ (UIButton *(^enumeration)(unsigned int)) {
dispatch_apply(5, enumerator_queue, ^(size_t index) {
dispatch_barrier_async(dispatch_get_main_queue(), ^{
button_collection[index] = enumeration((unsigned int)index);
});
});
};
};
static void (^(^enumerate_collection)(__strong UIButton * _Nonnull [_Nonnull 5]))(void (^__strong)(UIButton * _Nonnull, unsigned int)) = ^ (__strong UIButton * _Nonnull button_collection[5]) {
dispatch_queue_t enumerator_queue = dispatch_queue_create("enumerator_queue", DISPATCH_QUEUE_SERIAL);
return ^ (void(^enumeration)(UIButton * _Nonnull, unsigned int)) {
dispatch_barrier_async(dispatch_get_main_queue(), ^{
dispatch_apply(5, enumerator_queue, ^(size_t index) {
for (int index = 0; index < 5; index++)
dispatch_barrier_async(dispatch_get_main_queue(), ^{
enumeration(button_collection[index], (unsigned int)index); // no return value
});
});
});
};
};
map(&buttons, 5)(^ const void * (const unsigned long index) {
printf("map button %lu\n", index);
__block UIButton * button;
[button = [UIButton new] setTag:index];
[button setImage:[UIImage systemImageNamed:CaptureDeviceConfigurationControlPropertyImageValues[0][index] withConfiguration:CaptureDeviceConfigurationControlPropertySymbolImageConfiguration(CaptureDeviceConfigurationControlStateDeselected)] forState:UIControlStateNormal];
[button setImage:[UIImage systemImageNamed:CaptureDeviceConfigurationControlPropertyImageValues[1][index] withConfiguration:CaptureDeviceConfigurationControlPropertySymbolImageConfiguration(CaptureDeviceConfigurationControlStateSelected)] forState:UIControlStateSelected];
[button setImage:[UIImage systemImageNamed:CaptureDeviceConfigurationControlPropertyImageValues[1][index] withConfiguration:CaptureDeviceConfigurationControlPropertySymbolImageConfiguration(CaptureDeviceConfigurationControlStateHighlighted)] forState:UIControlStateHighlighted];
NSMutableParagraphStyle *centerAlignedParagraphStyle = [[NSMutableParagraphStyle alloc] init];
centerAlignedParagraphStyle.alignment = NSTextAlignmentCenter;
NSDictionary *centerAlignedTextAttributes = @{NSForegroundColorAttributeName:[UIColor systemYellowColor],
NSFontAttributeName:[UIFont systemFontOfSize:14.0],
NSParagraphStyleAttributeName:centerAlignedParagraphStyle};
NSString *valueString = [NSString stringWithFormat:@"%.2f", 0.00];
NSAttributedString *attributedString = [[NSAttributedString alloc] initWithString:valueString attributes:centerAlignedTextAttributes];
[button setAttributedTitle:attributedString forState:UIControlStateNormal];
[button.titleLabel setFrame:UIScreen.mainScreen.bounds];
[button sizeToFit];
float angle = rescale(index, 0.0, 4.0, 180.0, 270.0);
NSNumber * button_angle = [NSNumber numberWithFloat:angle];
objc_setAssociatedObject (button,
(void *)index,
button_angle,
OBJC_ASSOCIATION_RETAIN);
[button setUserInteractionEnabled:FALSE];
void (^eventHandlerBlockTouchUpInside)(void) = ^{
NSNumber * associatedObject = (NSNumber *)objc_getAssociatedObject (button, (void *)index);
// printf("%s\n", [[associatedObject stringValue] UTF8String]);
};
objc_setAssociatedObject(button, @selector(invoke), eventHandlerBlockTouchUpInside, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[button addTarget:eventHandlerBlockTouchUpInside action:@selector(invoke) forControlEvents:UIControlEventTouchUpInside];
CGPoint target_center = point_from_angle(angle);
[button setCenter:target_center];
[self addSubview:button];
return (const id *)CFBridgingRetain(button);
});
/*
Older versions (non-recursive) below
*/
populate_collection(buttons)(^ UIButton * (unsigned int index) {
UIButton * button;
[button = [UIButton new] setTag:index];
[button setImage:[UIImage systemImageNamed:@"questionmark.circle" withConfiguration:[[UIImageSymbolConfiguration configurationWithPointSize:42] configurationByApplyingConfiguration:[UIImageSymbolConfiguration configurationPreferringMulticolor]]] forState:UIControlStateNormal];
[button sizeToFit];
void (^eventHandlerBlock)(void) = ^{ };
objc_setAssociatedObject(button, @selector(invoke), eventHandlerBlock, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[button addTarget:eventHandlerBlock action:@selector(invoke) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:button];
float angle = 270.0 - ((90.0 / 4.0) * button.tag);
[button setCenter:[[UIBezierPath bezierPathWithArcCenter:CGPointMake(CGRectGetMaxX(self.view.bounds), CGRectGetMaxY(self.view.bounds)) radius:CGRectGetMidX(self.view.bounds) startAngle:degreesToRadians(angle) endAngle:degreesToRadians(angle) clockwise:FALSE] currentPoint]];
return button;
});
enumerate_collection(buttons)(^ (UIButton * _Nonnull button, unsigned int property) {
float angle = 270.0 - ((90.0 / 4.0) * button.tag);
[button setCenter:[[UIBezierPath bezierPathWithArcCenter:CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds)) radius:CGRectGetMidX(self.view.bounds) startAngle:degreesToRadians(angle) endAngle:degreesToRadians(angle) clockwise:FALSE] currentPoint]];
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment