How can I change the value of an NSImage? - objective-c

I am a beginning Objective-C programming programmer, and I want to change the value of an NSImage. That means that if I have an NSImage that is a NSStatusUnavaliable, how could I make it a NSStatusAvaliable? Thanks!

So I believe what you're asking is: Somewhere you have an NSImage instance that was initialized like:
NSImage *image = [NSImage imageNamed: #"NSStatusUnavailable"];
And you would like to use the image that is mapped to #"NSStatusAvailable".
Without going into details, you really want to assign your image to [NSImage imageNamed: #"NSStatusAvailable"];
Take a look at the docs for NSImage. Specifically what you might find useful is the imageNamed: class method.
Discussion
This method searches for named images in several places, returning the first image it finds matching the given name. The order of the search is as follows:
Search for an object whose name was set explicitly using the setName: method and currently >resides in the image cache.
Search the app's main bundle for a file whose name matches the specified string. (For information on how the bundle is searched, see ““Accessing a Bundle's Contents”“ in >Bundle Programming Guide.)
Search the Application Kit framework for a shared image with the specified name.
But also since you're new, just reviewing Objective-C docs on object life cycle will be very useful to understand what's going on.

Swift:
let 🈯️ = NSImage(named: .statusAvailable)
let 🅿️ = NSImage(named: .statusPartiallyAvailable)
let 🔴 = NSImage(named: .statusUnavailable)
let 🔶 = NSImage(named: .statusNone)

Related

objective-c How to cache images from facebook using SDWebImage?

Im new in iOS programming so i need some help.
I have a TableViewController with a property NSArray, where is stored Facebook User's friends info: uid, square_pic and name. I use to load their profile photos using FBProfilePictureView, by uid.
My problem: When user scroll the table pictures from cells take a lot of time to reload. I want to cache this photos using SDWebImage.
Thank's a lot.
I am not familiar to SDWebImage. Their readme mentions ability to cache, so you might want to figure it out on your own.
However, there is a really nice class called NSCache that you can implement in some of your managers or view controllers. Also, this post by Mattt Thompson covers it in great details.
It functions as a regular NSDictionary in sense that you can set object for keys and retrieve them. e.g:
//setting
[cache setObject:image forKey:#"yourImageURL"]
//accessing
UIImage *image = [cache objectForKey:#"yourImageURL"];
if (image == nil) {
// request it
}
But it also contains some awesome staff for setting values for objects which will serve as a hint which objects have to be removed in case of low memory.
Hope this helps to answer your question.
Cheers!

How to convert (OS_dispatch_data *) 5018112 bytes into NSData to put into UIImage

I've been looking for an answer to this and some seem like they might be what I need but I'm not sure. I found this Question #9152851 and this Question #2617625 and poked around on a bunch of links but I need some direction here.
Essentially, I'm dispatching an async call to process an image using OpenCV. You can see by the code here that I'm turning it into NSData * before sending it back to my delegate.
NSData *proccessedData = [NSData dataWithBytes:processedImage.data length:(processedImage.rows * processedImage.cols)];
[self.delegate onProcessedBitmapReady:proccessedData withFocusQuality:focusQuality];
But when I get back to my delegate, my processedBitmap is of type (OS_dispatch_data *) and contains a value of bytes. So, when I try to set the UIImage, it gets set to null.
- (void)onProcessedBitmapReady:(NSData *)processedBitmap withFocusQuality:(double)focusQuality
{
//Use comverted image from self.captureCommand onComplete
UIImage *image = [[UIImage alloc] initWithData:processedBitmap];
[self saveImage:image];
}
Here is a screen capture of the values:
So, how do I convert those bytes (or whatever they are) into something that I can stuff into a UIImage?
Thank you in advance for your help.
------------------------------------------------------- Adding a new image -----------------------------------------
Does this new image help?
Thank you.
NSData is actually a class cluster which just provides the interface, and there are multiple special implementations for it around. It appears that OS_dispatch_data is such a special implementations made to pass data objects around blocks, especially since your UIImage creation doesn't crash (as it would if you would pass it a non NSData object, or just garbage memory). Instead, it looks like UIImage simply doesn't recognize the format the image is in!
By the way, Apple has a great guide about the concept of class clusters, which can be found here.

Why does nil-checking a table view cell property cause one of my cells to copy another?

My table view loads pictures through SDWebImage (async image downloading/cache category for UIImageView) in each tableView:cellForIndexPath:.
// 'spot' is a dictionary of this cell's attributes
NSURL* imageURL = [NSURL URLWithString:(NSString*)[spot objectForKey:#"Image"]];
UIImage* placeholderImage = [UIImage imageNamed:#"placeholder.png"];
^ Loads the images, but is constantly having to make requests or pull from the cache. So I wanted to see if the rendered cells were stored in memory, so I could only make requests for images when I need them. I went about this by adding a simple check for the image property of the image view.
if (!cell.pictureView.image)
{
NSURL* imageURL = [NSURL URLWithString:(NSString*)[spot objectForKey:#"Image"]];
UIImage* placeholderImage = [UIImage imageNamed:#"placeholder.png"];
[cell.pictureView setImageWithURL:imageURL placeholderImage:placeholderImage options:SDWebImageCacheMemoryOnly];
}
This works and keeps my images from having to reload after exiting and reentering the application. But in one of my cells that has a purposely bad image url (for debugging), the image- which used to remain as the imageNamed:#"placeholder"- is now the same image as my second cell.
I'm curious what kind of cell-reuse/cache magic is causing the cell to take the picture of a previous cell.
What is the best way to retain cell properties and only set them when needed?
It's very likely the issue is with the image package you are using. If you are making repeated URL requests to grab images, it is probably best practice to implement NSURLCache, which is a fairly simple and handles caching perfectly so it is not an issue. This is the NSHipster guide on how to use it. Other solutions tend towards these sorts of issues. Since it is a category on UIImageView, it could be any number of things causing issues with UIImageView's implementation when getting used in the cell.

How to get suitable CGImage from combined TIFF for display scale

I have two PNGs in a Mac project. Normal and #2x. Xcode combines these into a single TIFF with the #2x being at index 0 and the #1x at index 1.
What is the suggested approach to get the appropriate image as CGImageRef version (for use with Quartz) for the current display scale?
I can get the image manually via CGImageSource:
NSBundle *mainBundle = [NSBundle mainBundle];
NSURL *URL = [mainBundle URLForResource:#"Canvas-Bkgd-Tile" withExtension:#"tiff"];
CGImageSourceRef source = CGImageSourceCreateWithURL((__bridge CFURLRef)(URL), NULL);
_patternImage = CGImageSourceCreateImageAtIndex(source, 1, NULL); // index 1 is #1x, index 0 is #2x
CFRelease(source);
I also found this to be working, but I am not certain that this will return the Retina version on a Retina display:
NSImage *patternImage = [NSImage imageNamed:#"Canvas-Bkgd-Tile.tiff"];
_patternImage = [patternImage CGImageForProposedRect:NULL context:nil hints:nil];
CGImageRetain(_patternImage); // retain image, because NSImage goes away
An acceptable answer to this question either provides a solution how to get the CGImage suitable from a combined multi-resolution TIFF, or explains why the second approach here is working. Or what changes are required.
I am opting to answer on "why the second approach here is working".
In one of the WWDC videos published since 2010, they said that :
+[NSImage imageNamed:] chooses the best image representation object available for the current display.
So chances are that you are calling this class method from within a locked focus context (e.g. within a drawRect: method or similar), or maybe you actually called lockFocus yourself. Anyway, the result is that you get the most suitable image. But only when calling +[NSImage imageNamed:].
EDIT: Found it here:
http://adcdownload.apple.com//wwdc_2012/wwdc_2012_session_pdfs/session_213__introduction_to_high_resolution_on_os_x.pdf
Search for the keyword "best" in the slides: "NSImage automatically chooses best representation […]".
So, your second version will return the Retina version on a Retina display, you can be certain of it, it is advertised in the documentation[*].
[*] This will only work if you provide valid artwork.

How to create Multiple Themes/Skins for iphone apps? [closed]

It's difficult to tell what is being asked here. This question is ambiguous, vague, incomplete, overly broad, or rhetorical and cannot be reasonably answered in its current form. For help clarifying this question so that it can be reopened, visit the help center.
Closed 11 years ago.
I have an iphone app ready and approved by the app store. Now I want to create different themes for my app. Can someone please help me out, with info/links/steps on how to create themes for my app?
I want to create a Metal theme for the Boys and a Pink theme for the Girls. Again by theme I mean, the whole app(features and functionality) is gonna stay the same, but depending on who the user is(boy or girl), he/she can choose the theme they wish to see. And when the theme changes, only the images/Background/music will change according to the applied theme.
Thanks a lot!
This is quite difficult as apps don't have the equivalent of a css stylesheet.
First you need to work out what parts of the app you want to skin, and when you want to allow the user to swap skins.
I'm going to assume that you want to change images and font colours, and that it's okay if the user has to relaunch the app to change the skin (that will make things simpler for now).
Create a plist containing all your skinnable images and colours. The plist will be a dictionary with sensible, theme neutral key names for the images and colours (e.g. don't have a colour called "red", call it "primaryHeadingColor"). Images will be file names, and colours can be hex strings, e.g. FF0000 for red.
You'll have one plist for each theme.
Create a new class called ThemeManager and make it a singleton by adding the following method:
+ (ThemeManager *)sharedManager
{
static ThemeManager *sharedManager = nil;
if (sharedManager == nil)
{
sharedManager = [[ThemeManager alloc] init];
}
return sharedManager;
}
The ThemeManager class will have an NSDictionary property called "styles", and in the init method you will load the theme into your styles dictionary like this:
- (id)init
{
if ((self = [super init]))
{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSString *themeName = [defaults objectForKey:#"theme"] ?: #"default";
NSString *path = [[NSBundle mainBundle] pathForResource:themeName ofType:#"plist"];
self.styles = [NSDictionary dictionaryWithContentsOfFile:path];
}
return self;
}
(Note: some people don't like doing a lot of work inside an init method. I've never found it to be an issue, but if you prefer, create a separate method to load the themes dictionary and call it from your app's setup code).
Notice how I'm getting the name for the theme plist from user defaults. That means the user can select a theme in your preferences and save it and the app will load that theme next time it is launched. I've put in a default theme name of "default" if no theme is selected, so make sure you have a default.plist theme file (or change the #"default" in the code to whatever your default theme plist is actually called).
Now that you've loaded your theme you need to use it; I'm assuming your app has various images and text labels. If you're loading and laying those out in code then this part is easy. If you are doing it in nibs then it's a bit trickier but I'll explain how to handle that later.
Now normally you would load an image by saying:
UIImage *image = [UIImage imageNamed:#"myImage.png"];
But if you want that image to be themable, you'll now need to load it by saying
NSDictionary *styles = [ThemeManager sharedManager].styles;
NSString *imageName = [styles objectForKey:#"myImageKey"];
UIImage *image = [UIImage imageNamed:imageName];
That will look in your theme file for the themed image that matches the key "myImageKey" and will load it. Depending on which theme file you've loaded you'll get a different style.
You'll be using those three lines a lot so you may want to wrap them up in a function. A great idea would be to create a category on UIImage that declares a method called something like:
+ (UIImage *)themeImageNamed:(NSString *)key;
Then to use it you can just replace any calls to [UIImage imageNamed:#"foo.png"]; with [UIImage themeImageNamed:#"foo"]; where foo is now the theme key instead of the actual image name.
Okay, so that's it for theming your images. To theme your label colours, suppose you're currently setting your label colours by saying:
someLabel.color = [UIColor redColor];
You would now replace that with:
NSDictionary *styles = [ThemeManager sharedManager].styles;
NSString *labelColor = [styles objectForKey:#"myLabelColor"];
someLabel.color = [UIColor colorWithHexString:labelColor];
Now you may have noticed that UIColor doesn't have a method "colorWithHexString:" - you'll have to add that using a category. You can Google for "UIColor with hex string" solutions to find code to do that, or I've written a handy category that does that and a bit more here: https://github.com/nicklockwood/ColorUtils
If you've been paying attention you'll also be thinking that instead of writing those three lines over and over, why not add a method to UIColor called:
+ (UIColor *)themeColorNamed:(NSString *)key;
Just like we did with UIImage? Great idea!
So that's it. Now you can theme any image or label in your app. You could use the same trick to set the font name, or any number of other potentially themable visual properties.
There's just one tiny thing we've forgotten...
If you've built most of your views as nibs (and I see no reason why you wouldn't) then these techniques aren't going to work because your image names and font colours are buried inside impenetrable nib data and aren't being set in your source code.
There are a few approaches to solve this:
1) You could make duplicate themed copies of your nibs and then put the nib names in your theme plist and load them from your theme manager. That's not too bad, just implement the nibName method of your view controllers like this:
- (NSString *)nibName
{
NSDictionary *styles = [ThemeManager sharedManager].styles;
return [styles objectForKey:NSStringFromClass([self class])];
}
Notice my neat trick of using the class name of the view controller as the key - that will save you some typing because you can just make a base ThemeViewController with that method and have all your themable view controllers inherit from it.
This approach does mean maintaining multiple copies of each nib though, which is a maintenance nightmare if you need to change any screens later.
2) You could make IBOutlets for all of the imageViews and labels in your nibs, then set their images and colors in code in your viewDidLoad method. That's probably the most cumbersome approach, but at least you don't have duplicate nibs to maintain (this is essentially the same problem as localising nibs btw, and pretty much the same solution options).
3) You could create a custom subclass of UILabel called ThemeLabel that automatically sets the font color using the code above when the label is instantiated, then use those ThemeLabels in your nib files instead of regular UILabels by setting the class of the label to ThemeLabel in Interface Builder. Unfortunately if you have more than one font or font colour, you'll need to create a different UILabel subclass for each different style.
Or you could be devious and use something like the view tag or accessibilityLabel property as the style dictionary key so that you can have a single ThemeLabel class and set the accessibility label in Interface Builder to select the style.
The same trick could work for ImageViews - create a UIImageView subclass called ThemeImageView that, in the awakeFromNib method replaces the image with a theme image based on the tag or accessibilityLabel property.
Personally I like option 3 best because it saves on coding. Another advantage of option 3 is that if you wanted to be able to swap themes at runtime, you could implement a mechanism where your theme manager reloads the theme dictionary, then broadcasts an NSNotification to all the ThemeLabels and ThemeImageViews telling them to redraw themselves. That would probably only take about an extra 15 lines of code.
Anyway, there you have a complete iOS app theming solution. You're welcome!
UPDATE:
As of iOS 5, it's now possible to set custom attributes by keyPath in Interface Builder, meaning that it's no longer necessary to create a view subclass for each themable property, or abuse the tag or accessibilityLabel for selecting styles. Just give your UILabel or UIImageView subclass a string property to indicate which theme key it should use from the plist, and then set that value in IB.
UPDATE 2:
As of iOS 6, there is now a limited skinning system built into iOS that allows you to use a property called the UIAppearance proxy to skin all instances of a given control class at once (there's a good tutorial about the UIAppearance APIs here). It's worth checking if this is sufficient for your skinning needs, but if not, the solution I outlined above still works well, and can be used instead, or in combination with UIAppearance.