I found it:
#import <UniformTypeIdentifiers/UniformTypeIdentifiers.h>
Post
Replies
Boosts
Views
Activity
If what you need to do is add a white border around and image, here's some code
-(NSImage *)addBorderToImage: (NSImage *)oldImage
width: (CGFloat)w;
{
NSSize size;
NSRect iRect;
NSImage *newImage;
size = oldImage.size;
iRect.origin.x = w;
iRect.origin.y = w;
iRect.size = size;
size.width += 2 * w;
size.height += 2 * w;
newImage = [[NSImage alloc] initWithSize: size];
[newImage lockFocus];
[[NSColor whiteColor] drawSwatchInRect: NSMakeRect( 0 , 0 , size.width, size.height)];
[oldImage drawInRect: iRect];
[newImage unlockFocus];
return newImage;
}
code-block
I found a work around to the problem. In the example code below, in response to a color change the action message, newColor:, changes the color of the image and calls the button's setImage: message. This actually is the same NSImage object already in the Button. In this case the API ignores the setNeedsDisplay message.
If a new NSImage object is created, as in the line commented out, and sent to the Button, the Button is redrawn with the new image.
I still think it is a bug that the in the first instance the setNeedsDisplay message is ignored.
// AppDelegate.m
// TestUI
//
// Created by Bruce D MacKenzie on 11/20/22.
//
#import "AppDelegate.h"
@interface AppDelegate ()
{
}
@property (strong) IBOutlet NSWindow *window;
@property (assign) IBOutlet NSButton *theButton;
@end
@implementation AppDelegate
{
NSImage *image;
}
@synthesize theButton;
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
// Insert code here to initialize your application
}
- (void)applicationWillTerminate:(NSNotification *)aNotification {
// Insert code here to tear down your application
}
-(void)awakeFromNib
{
image = [[NSImage alloc] initWithSize: NSMakeSize( 32 , 32 )];
[image lockFocus];
[[NSColor redColor] drawSwatchInRect: NSMakeRect(0, 0, 32, 32)];
[image unlockFocus];
[[self theButton] setImage: image];
}
- (BOOL)applicationSupportsSecureRestorableState:(NSApplication *)app {
return YES;
}
-(IBAction)newColor: (NSColorWell *)sender
{
NSColor *newColor;
newColor = [sender color];
// image = [[NSImage alloc] initWithSize: NSMakeSize( 32 , 32 )];
[image lockFocus];
[newColor drawSwatchInRect: NSMakeRect( 0, 0, 32, 32)];
[image unlockFocus];
[[self theButton] setImage: image];
[[self theButton] setNeedsDisplay: YES];
}
code-block
6/18/22 Fixed a bug that caused the hit test to fail on Retina Displays.
I found the problem. Yesterday when entering an accent, á, I inadvertently turned on Mouse Keys which reassigns the numeric keyboard.
Included in the sample code project MigratingOpenGLCodeToMetal is the file AAPLMathUtilities. This file contains two functions for creating projection matrixes:
/// Constructs a symmetric perspective Projection Matrix
/// from left-handed Eye Coordinates to left-handed Clip Coordinates,
/// with a vertical viewing angle of fovyRadians, the specified aspect ratio,
/// and the provided absolute near and far Z distances from the eye.
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_perspective_left_hand(float fovyRadians, float aspect, float nearZ, float farZ);
/// Constructs a symmetric perspective Projection Matrix
/// from right-handed Eye Coordinates to left-handed Clip Coordinates,
/// with a vertical viewing angle of fovyRadians, the specified aspect ratio,
/// and the provided absolute near and far Z distances from the eye.
matrix_float4x4 AAPL_SIMD_OVERLOAD matrix_perspective_right_hand(float fovyRadians, float aspect, float nearZ, float farZ);
So, I guess one can define the geometry of one's objects using either a right hand or a left hand coordinate system and have it display properly depending on which of these two one uses to construct the projection matrix.
This is good. I think I understand things much better now.
I have placed a little Xcode project on github that renders to an off screen texture to do mouse picking.
Rather than have dispatch_apply() run the loop I have replaced the above with repeated calls to dispatch_async() to avoid the problem. The following code works like a hose.
- (void)searchTreeBranches
{
int n;
RBK_Turn turn;
// load up the processor cores
for ( n = 0 ; n < turnsMax; n++)
{
turn = turns[n];
dispatch_async( myDispatchQueue, ^( void )
{ ••• });
}
}
I think I have a clearer picture of what the problem is. The code block is an IDA (Iterative Deepening Algorithm) search in the Cayley graph of the Rubik's Cube group for a solution to a cube position. For the first few iterations the code block returns almost immediately. As the search goes deeper the times increase exponentially. The problem is that GCD profiles the block based on the early iterations and decides it would be more efficiently run serially. So, when the search reaches a deeper level where parallel processing gives a huge performance increase GCD continues to run the tasks one at a time. How can one preempt that profiling?
Using the more explicit method: unarchivedDictionaryWithKeysOfClasses:objectsOfClasses:fromData:error:
eliminates all the problems. The following code executes with no errors.
-(void)test: (NSString *)input
{
NSDictionary *source,
*destination;
NSSet *classes;
NSMutableData *mData1,
*mData2;
NSData *table1,
*table2,
*archive;
NSError *error;
@autoreleasepool
{
mData1 = [NSMutableData dataWithData: edgeTableC3v];
mData2 = [NSMutableData dataWithData: cornerTableC3v];
table1 = mData1;
table2 = mData2;
source = [NSDictionary dictionaryWithObjectsAndKeys:
input, @"input",
table1, @"edge table",
table2, @"corner table",
nil];
archive = [NSKeyedArchiver archivedDataWithRootObject: source
requiringSecureCoding: YES
error: &error];
if( error != nil )
{
[self report: [NSString stringWithFormat: @"\nError creating archive\n\t%@", [error localizedFailureReason]]];
}
else
{
classes = [NSSet setWithObjects:
[NSData class],
[NSString class],
nil];
destination = [NSKeyedUnarchiver unarchivedDictionaryWithKeysOfClasses: [NSSet setWithObject: [NSString class]]
objectsOfClasses: classes
fromData: archive
error: &error];
if( error != nil)
{
[self report: [NSString stringWithFormat: @"\nError reading archive\n\t%@", [error localizedFailureReason]]];
}
else
[self report: [NSString stringWithFormat: @"\nNo Error\n%@", [destination description]]];
}
[self reportDone];
}
}
OUTPUT
No Error
{
"corner table" = {length = 2449440, bytes = 0x88a40000 e0970000 98c40000 48b70000 ... f3b00000 85a40000 };
"edge table" = {length = 145152, bytes = 0x00000000 00000000 140b0000 250a0000 ... 99090000 bf080000 };
input = Parameters;
}
Note that I archived NSMutableData objects and they were unarchived with no error. The runtime doesn't send any warnings when unarchiving.
I found the docs I needed: [https://developer.apple.com/documentation/security/1399291-secrandomcopybytes?language=objc).
The core foundation security services api contains the appropriate system call. The modern implementation of the above would be:
-(uint64)random64
{
uint64_t value = 0;
uint8 randomByte;
int i, err;
for (i = 0 ; i < sizeof(value); i++)
{
value <<= 8;
err = SecRandomCopyBytes( kSecRandomDefault , 1 , &randomByte );
value |= randomByte;
}
return value;
}
pruneTableP2 is an NSData object holding a 200+mbyte table. The first time the user launches the program the table must be calculated and that routine uses an NSMutableData object for that. This is archived to the users home directory to be loaded from disk thereafter. So, although typed as NSData, pruneTableP2 actually is a pointer to an NSMutableData object when it is archived. Sometime after the app was written stricter type checking was added to NSKeyedUnarchiver and the code broke. The fix is to use a pure NSData object rather than its subclass to create the archive.
It is disturbing that even then the runtime sends out these warnings:
Multiline
2021-11-04 08:24:55.954653-0500 Cube Console[1366:19975] [general] *** -[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSData' (0x1dda3e558) [/System/Library/Frameworks/CoreFoundation.framework]' for key 'NS.objects', even though it was not explicitly included in the client allowed classes set: '{(
"'NSDictionary' (0x1dda3e5d0) [/System/Library/Frameworks/CoreFoundation.framework]"
)}'. This will be disallowed in the future
.
2021-11-04 08:24:55.955503-0500 Cube Console[1366:19975] [general] *** -[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSString' (0x1dda6c848) [/System/Library/Frameworks/Foundation.framework]' for key 'NS.keys', even though it was not explicitly included in the client allowed classes set: '{(
"'NSDictionary' (0x1dda3e5d0) [/System/Library/Frameworks/CoreFoundation.framework]"
)}'. This will be disallowed in the future.
BlockQuote
code-block
I copied the pruneTableP2 into an NSData object and now unarchivedObjectOfClass: will read in the archive. It doesn't like NSMutableData. But now it throws out a couple of warnings.
2021-11-03 22:31:46.749411-0500 Cube Console[8846:238300] [general] *** -[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSData' (0x1ed406558) [/System/Library/Frameworks/CoreFoundation.framework]' for key 'NS.objects', even though it was not explicitly included in the client allowed classes set: '{(
"'NSDictionary' (0x1ed4065d0) [/System/Library/Frameworks/CoreFoundation.framework]"
)}'. This will be disallowed in the future.
2021-11-03 22:31:46.749801-0500 Cube Console[8846:238300] [general] *** -[NSKeyedUnarchiver validateAllowedClass:forKey:] allowed unarchiving safe plist type ''NSString' (0x1ed434848) [/System/Library/Frameworks/Foundation.framework]' for key 'NS.keys', even though it was not explicitly included in the client allowed classes set: '{(
"'NSDictionary' (0x1ed4065d0) [/System/Library/Frameworks/CoreFoundation.framework]"
)}'. This will be disallowed in the future.
It's an NSMutableData object.
pruneTableP2 NSConcreteMutableData * 274337280 bytes 0x00006000002b8120
On reading my post I realized that the data in the C array is in row major order. The row index changes fastest and that is the right most index in a C array. I feel stupid.