krzysztofzablocki/KZNodes

More notes or comments please.

bhartsb opened this issue · 0 comments

Not to sound critical as I appreciate this is open source, but the code is very difficult to decipher for someone who's never seen it. More comments or a document of the architecture would be of immense help. For example the following was really confusing so I added some comments and indenting:

[KZNNodeType registerType:name inputs:@{ @"Image" : CIImage.class } outputs:@{ @"Output" : CIImage.class } processingBlock:^(id node, NSDictionary *inputs, NSMutableDictionary *outputs)
        {
            //processing Block definition
            //processing block only is called from evaluateWithTick:(..)
            
            // WHY NOT CIImage *image = [CIImage new]; ???
            // probably because image already has data since it is from an input socket
            CIImage *image = inputs[@"Image"];
              if (!image) {
                return;
              }
            
            // create a filter object with the input image:
            //Note in the following the list of key value pairs is "kCIInputImageKey, image, nil" where nil is the end of the list
            CIFilter *filter = [CIFilter filterWithName:filterName
                                       keysAndValues:kCIInputImageKey, image, nil];
            //apply the filter and set the output image returned:
            CIImage *outputImage = [filter outputImage];
            outputs[@"Output"] = outputImage;
        }
         ];

The above has two sets of paramaters named "inputs" and "outputs" (one for the method and one for the block) so I easily confused that inputs and outputs used in the block was the same as that for the method. That made the code appear incorrect per the line:

CIImage *image = inputs[@"Image"];

Because I thought inputs was: @{ @"Image" : CIImage.class } which would make
CIImage *image = CIImage.class which would not work.

Next you have 3 versions of the method registerType:
The first version does nothing more than call the second version having the param:
withClass:KZNNode.class
But you are calling this second version many times within KZPlaygroundExample.m so why have this first version?

In the third version of the registerType method you have the line:
self.nodeTypes[typeName] = type;

where nodeTypes is not actually a dictionary as it would appear at a glance, but is a class method that returns a dictionary. This line is actually "registering" the type. The whole method is creating and registering the type. KZNNodeType it appears is not just a type of node but is also serving as a registry and factory of types and in addition a factory of nodes.

Here is the definition of the class method but where I'm at now is trying to understand what it is doing exactly? (update: I'm thinking that this was a work around for Objective-C not supporting class properties until Xcode 8, correct me if I'm wrong):

+ (NSMutableDictionary *)nodeTypes
{
  NSMutableDictionary *nodeTypes = objc_getAssociatedObject(self, kNodeTypesKey);
  if (!nodeTypes) {
    nodeTypes = [NSMutableDictionary new];
  }
  objc_setAssociatedObject(self, kNodeTypesKey, nodeTypes, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
  return nodeTypes;
}

In the project there are pod dependencies: KZPlayground, NHBalancedFlowLayout, RSSwizzle, and dyci. From their names I can guess what they are for, but some documentation of where, why and how much they are used in the project would be of help. When I looked at this project initially I had no idea that it used your own version of a Playground.

I'm still wondering why the project is seeming to use Class or why it needs it unless the plan were to do some runtime injection of classes.

I may add more comments to this as I proceed. The UI concept of nodes and sockets and connections seems too tightly coupled to the graph data model of same.