What I want to do:
I want to implement ability for user to use CIFilters on image. So I need somehow to fix it's sequence. For example if user opens image, then applies CIGaussianBlur, and then CIColorControls and then CISepia, I need to get result like that:
On user opened image apply CIGaussianBlur -> on CIGaussianBlur output image apply CIColorControls - > on CIColorControls output image apply CISepia.
Thats OK. But what if then user turns off CIGaussianBlur? I need then to repeat this effect's sequence just without blur. It would look like this:
On user opened image apply CIColorControls -> on CIColorControls output image apply CISepia.
The question
Is it possible to do something like this:
After applying any effect, add some string in NSMutableArray or NSMutableDictionary. Then when applying another effect, check NSMutableArray or NSMutableDictionary contents like that:
if object at index 0 is equal to "blur", apply blur on source image, then take blur's output image like current effect's input image
And so on? So that effects would be re-applied every time in their sequence made by user.
If it is possible maybe someone could suggest me any solution?
I think that this is a great instance for the factory idea to be used.
You should store your array of filters to process the image as an array - that maintains sort order, and is fairly straightforward to deal with (other than something like a NSCountedSet).
The next logical question to ask, then, is how do we apply the factory pattern here? The most important thing to consider is what type should the context object be? Here are a few thoughts:
Using NSString as a constant identifier.
Probably the simplest to start, its , and easy to understand - the downside is that it's slower than other options, and can get to be quite the complex if-else block, as you cannot use a switch statement on a NSString.
NSNumber, wrapping an enum value.
This is probably one of the better options. You can convert right down to an int variable, which compares quite fast on almost any processor I can imagine, and, if you use ObjC 2.5's fancy literals, you could do something like this:
[filters addObject:#(filterType_gaussianBlur)];
Where filterType_gaussianBlur is an enum constant or something.
Another advantage to using an enum is the support for switch statements out of the box. It cleans up your code if done properly, it's faster than a large if-else block, the only thing to look out for is ensuring that you break properly!
Storing Class objects
This one may require some explaining. In objective-c, you can actually store a reference to the type of an object, CIGaussianBlur, NSString, NSData, etc.
This class "object" allows you to dynamically create an object based just on it's type, for example:
Class cls = nil;
if (stringMutable)
cls = [NSMutableString class];
else
cls = [NSString class];
NSString *mutableOrNot = [[cls alloc] initWithString:#"Hello World!"];
However, the disadvantage to this approach would be the inability to configure the objects after they are initialized, and you must use the same selector (method) to initialize each one. If that is not an issue (I do not use CoreImage), then using the Class approach should be fine.
All in all, use whatever makes sense in the situation. If these filters need no additional configuration after they have been initialized, then approach 3 makes a lot of sense. I personally wouldn't recommend approach 1, unless it really is necessary to use a string. Whenever you can, always try to control the values that an object can have. It makes your life much easier, trust me.
Related
We are using a web service to fetch data. As project progressed, number of params being passed between functions also increased. To make it more readable and easier to add/remove parameters in future thought of using a dictionary instead. So every function calls will have only one parameter , a dictionary with all required parameters in it.
So to set a parameter I need to do [aDictionary setObject:foo forkey:#"bar"] and to get a parameter, it would be [aDictionary objectForKey:#"bar"].
To access the variables easily I thought of using a Model class with all common parameters used as properties. So for one function call say 3 out of 10 properties would be used and rest will be not be set. So it would be like paramModel.foo = #"bar".
If I would do it like this, will I be wasting memory for unused properties which are not initialised. And is this right in doing so ?
Continuing Amin Negm-Awad's points: If you are finding yourself passing along a lot of parameters to many methods, you almost certainly have incorrectly defined your model classes. Rather than creating a generic dictionary, create a simple value object that holds the related properties.
As an example, consider NSURL. You would never do this:
[self handleScheme:scheme host:host path:path];
Instead you do this:
NSURL *URL = [[NSURL alloc] initWithScheme:scheme host:host path:path];
[self handleURL:URL];
This is the correct way to consolidate parameters, and to improve your design.
Also, if you're taking a large number of boolean parameters or other kinds of "options," first consider whether you have a method that is doing too many things. Perhaps it should just be broken up into multiple methods that each works a specific way. If you really do need to pass multiple boolean options, in ObjC, this is often done with bit fields rather than with many parameters. Look at [NSString rangeOfString:options:] for an example.
No, it is strange. (Of course this is a subjective opinion.)
A. "As project progressed, number of params being passed between functions also increased."
There is only a connection between size of a software and numbers of parameters to a method (in your example there is no function): if you do something wrong in your design.
Split your code into modules, into classes, define good relationships between them and so on.
Define classes that can hold connected data.
B. I cannot see, what becomes more readable using dictionaries:
[receiver doSomethingWithA:#"a"
B:#"b"
C:#"c"];
NSMutableDictionary *aDictionary = [NSMutableDictionary new];
[aDictionary setObject:#"a" forKey:#"A"];
[aDictionary setObject:#"b" forKey:#"B"];
[aDictionary setObject:#"c" forKey:#"C"];
[receiver doSomethingWithABC:aDictionary];
It is more code, it is more complex code (because it needs an additional instance object), arguments and its "parameter destination" are wrested apart.
Inside the method you have to read out the arguments from the dictionary. This is additional boiler plate code.
I'm trying to understand the concept of NSCache, and one thing that strikes me is that a NSCache instance does not guarantee to give back the value to a key you stored before. It might not even store the key value pair when you try to add it, if it deems that the performance is more important at the moment.
What that implies, for me, is that:
Each key must 'hold' enough information to generate the value if necessary
Each query for the NSCache, which essentially is just in the form of a key, should thus wrap up all the information needed to generate the corresponding value.
From the above two points one can say that NSCache serves no purpose of establishing any kind of association between a key and a value - the user must be able to generate the value independent of the cache, and the sole purpose of using a NSCache is not to 'look up' some value, but rather just to trade memory for some performance boost
So my problem is about storing transparency masks for images. Initially I thought I just need to use the names of the images as the keys, but from my deductions above it seems that's not sufficient - I also have to include all other parameters used in generating a mask e.g. the transparency threshold, for example. It also means that every time I ask the cache for a mask I have to provide ALL the parameters. And the only way that I can think of about doing that is to use something like NSInvocation as the key; but that seems a rather clunky solution.
It is the very nature of a cache to be volatile, so caches should only ever be used to speed up access to information that could also be acquired some other way.
Your idea to create keys that hold all this information should work - just remember to store all your keys somewhere other than the cache as well.
As for the key, you can create a very simple class that has nothing but a couple of properties (the ones that make up a key), an isEqual: and hash method and maybe an initializer that takes parameters for each of your properties.
This requires extremely little code, since accessors and iVars for properties are autogenerated, so the only thing you really need to write is the isEqual: method (and hash).
This class is so small and taylor-made for the particular case you need it for, it makes sense to declare and implement it at the top of the .m file you're going to use it in. This way, you don't pollute the rest of the system. Just add #interface and #implementation sections for your class at the top of your .m file.
After more thought about this I think I've got one thing wrong - the keys in a NSCache do not necessarily need to hold all the information for generating the values. A key in a NSCache can serve the same purpose as that in a NSDictionary - a unique identifier to look up the value. The only difference, though, is that you'd always need to have a backup plan B for a NSCache in case the key-value pair added before is destroyed.
In simplier terms, operations on the two different classes look like this:
NSDictionary
generate each value V for each key K and add the pairs to the dictionary
look up V using K
NSCache
look up V using K
if V == nil, generate the value V and add the pair to the cache
Therefore it's possible to convert almost any NSDictionary to a NSCache, only that after the conversion you can't pass the NSCache around - you have to know how to generate the values at all times and thus the NSCache instance would most probably be a private property used exclusively in a certain class.
For my problem I've resolved to use a method like this (self is supposedly pointing to a subclass of NSCache, but I haven't tested it yet)
- (Mask *) maskForImageName:(NSString *)name maskGenerator:(Mask *(^)(NSString *))generator {
Mask *mask = [self objectForKey:name];
if (!mask) {
mask = generator(name);
[self setObject:mask forKey:name];
}
return mask;
}
It would be further simplified if objective-c is a functional, lazy-style language, in which case I don't even need to wrap the generator in a block; but I'm satisfied with this solution for now. In fact I feel that this pattern is almost always used with NSCache so I'd just add it as a category to NSCache.
I would like to know if there is any difference in performance between these:
- create an object with the value of an existing object, then assign itself = a modified version of it
AND
- create and object with the value = the modified value of an existing object
Code sample in Objective-C:
UIImage* img= img2;
img = [img apply:filter];
VS
UIImage* img=[img2 apply:filter];
Thanks
This:
UIImage* img= img2;
does not "create a new object", it simply makes "img" refer to the same object as "img2".
In either case, all you're doing is assigning a pointer, so there's no significant performance difference.
If the apply method always returns a new image, then no, there is not the slightest difference between those two things. The main difference is that in the first one, the first line is wasted: you assign img2 to img but then you throw away that assignment, replacing img's value a different image (the result of apply). But even that waste makes no performance difference, because object assignment is pointer assignment, which is trivial (no data copying takes place or anything like that).
At this level, you're dealing with something the compiler will optimize away anyway. There may be an additional assignment that occurs in the first that doesn't happen in the second (that would have a negligible impact on performance because you're simply dealing with pointers), but I imagine any compiler worth its salt would turn these two statements into the same assembly.
Newbie question here. I'd like to be able to specify through data (i.e. an XML file), the appropriate Objective-C message to send. Any advice on if this is possible or how I can do this?
The next best thing, if I can't do this, would be some way to create a map object that would correlate a key (an int) with a function (I guess also a selector). Is that possible if the above isn't?
If someone could point me to some tutorial or example code as reference, that'd be great. Right now I'm doing things with a big switch statement, and I don't like it. (I'm switching on the id and in each case, explicitly calling the method relevant to the particular id.)
I love that you asked this question; too often, I see Satan's Swollen Switch Statement. It's nice to see someone wanting to using a function-table instead.
If you're OK with using a property list file (which is usually encoded in XML), this is really easy.
Just make a property list where the root element is a dictionary, which maps from some keys to some selectors.
Key Type Value
----------------------------------------------
Root Dictionary
firstKey String someSelector
secondKey String anotherSelector
Load the contents of your property list into an NSDictionary:
id path = [[NSBundle mainBundle] pathForResource:#"filename" ofType:#"plist"];
id dict = [NSDictionary dictionaryWithContentsOfFile:path];
SEL selector = NSSelectorFromString([dict objectForKey:#"firstKey"]);
if ([someObject respondsToSelector:selector]) {
[someObject performSelector:selector];
}
Of course, you'll want to refactor this logic into an appropriate method, and probably cache the property list as an instance variable.
Note: I personally think it's better to just put this function table inline; property lists are cool, but I'm not sure that it is very helpful in this case. Also, if you are cool with using Objective-C++, std::map will allow you to get away with not wrapping and unwrapping the selectors in NSString objects, etc.
I have used sortUsingSelector to sort an NSMutableArray of custom objects.
Now I'm trying to sort an NSMutableArray containing NSMutableArrays of custom objects.
Can you use sortUsingSelector on an NSMutableArray, or does it only work for custom classes?
If you can use blocks, the most straightforward way using sortUsingComparator:. Otherwise, you'll need to use sortUsingFunction:.
In either case, you are going to need to write a custom block or function that takes two arrays as arguments and returns a sort order based on their contents (I'm not sure what logic you are using to determine if array A or array B is "before" or "after" the other).
You'd do something like:
static NSInteger MySorterFunc(id leftArray, id rightArray, void *context) {
... return ascending/descending/same based on leftArray vs. rightArray ...
}
Then:
[myArrayOfArrays sortUsingFunction: MySorterFunc context: NULL];
It sends the selector to the objects, so you'll need to use one of the other sorters. Probably sortUsingFunction:context:.
Of course you can also use sortUsingSelector:, it really doesn’t matter whats the object in your array as long as it responds to the selector you want to use. But NSMutableArray and NSArray don’t have any comparison methods themselves, so you’d have to extend them using a category to implement your compare method.
So you probably want to use the other sorting methods pointed out in the other answers here. It’s not impossible to use sortUsingSelector: but it is rather inconvenient and most people (including me) would argue that it’s bad style to write a category for that.