Change UIImage in Objective-C Program - objective-c

I'm trying to change a UIImage in a xib file but it wouldn't change until I comment on this code. I changed image name in this code to but it's not helped me.
#property (strong, nonatomic) IBOutlet UIImageView *imgHeaderImage;
if([Util getStringData:kAppNameWhiteImage] !=nil){
[self.imgHeaderImage sd_setImageWithURL:[Util EncodedURL:[Util getStringData:kAppNameImage]] completed:^(UIImage * _Nullable image, NSError * _Nullable error, SDImageCacheType cacheType, NSURL * _Nullable imageURL) {
if (image == nil)
{
self.imgHeaderImage.image = [UIImage imageNamed:#"Logo Original"];
}
else
{
self.imgHeaderImage.image = image;
}
}];
} else {
self.imgHeaderImage.image = [UIImage imageNamed:#"Logo Original"];
}
I'm not familiar with Objective-C that why cannot solve this problem. please help me out with this.
Thanks in advance.

It looks like you need to track down the constant: kAppNameWhiteImage and change it’s value. Do a search in the project. In the code you shared “Logo Original” is only loaded if it cant get a valid image from kAppNameWhiteImage.

Since the context of the whole issue is not particularly sufficient, I can only speculate roughly.
Please forgive me if my answer is not accurate.
Since the code is executed only after the Xib file has been loaded, the code you presented is executed.
So no matter how you modify the Image in Xib, but the Code remains the same, the result will always be obtained after the Code is executed. The Logo of the Original. Because Code is executed after the Xib file is loaded.

Related

NSFilePresenter methods never get called

I'm trying to write a simple (toy) program that uses the NSFilePresenter and NSFileCoordinator methods to watch a file for changes.
The program consists of a text view that loads a (hardcoded) text file and a button that will save the file with any changes. The idea is that I have two instances running and saving in one instance will cause the other instance to reload the changed file.
Loading and saving the file works fine but the NSFilePresenter methods are never called. It is all based around a class called FileManager which implements the NSFilePresenter protocol. The code is as follows:
Interface:
#interface FileManager : NSObject <NSFilePresenter>
#property (unsafe_unretained) IBOutlet NSTextView *textView;
- (void) saveFile;
- (void) reloadFile;
#end
Implementation:
#implementation FileManager
{
NSOperationQueue* queue;
NSURL* fileURL;
}
- (id) init {
self = [super init];
if (self) {
self->queue = [NSOperationQueue new];
self->fileURL = [NSURL URLWithString:#"/Users/Jonathan/file.txt"];
[NSFileCoordinator addFilePresenter:self];
}
return self;
}
- (NSURL*) presentedItemURL {
NSLog(#"presentedItemURL");
return self->fileURL;
}
- (NSOperationQueue*) presentedItemOperationQueue {
NSLog(#"presentedItemOperationQueue");
return self->queue;
}
- (void) saveFile {
NSFileCoordinator* coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:self];
NSError* error;
[coordinator coordinateWritingItemAtURL:self->fileURL options:NSFileCoordinatorWritingForMerging error:&error byAccessor:^(NSURL* url) {
NSString* content = [self.textView string];
[content writeToFile:[url path] atomically:YES encoding:NSUTF8StringEncoding error:NULL];
}];
}
- (void) reloadFile {
NSFileManager* fileManager = [NSFileManager defaultManager];
NSFileCoordinator* coordinator = [[NSFileCoordinator alloc] initWithFilePresenter:self];
NSError* error;
__block NSData* content;
[coordinator coordinateReadingItemAtURL:self->fileURL options:0 error:&error byAccessor:^(NSURL* url) {
if ([fileManager fileExistsAtPath:[url path]]) {
content = [fileManager contentsAtPath:[url path]];
}
}];
dispatch_async(dispatch_get_main_queue(), ^{
[self.textView setString:[[NSString alloc] initWithData:content encoding:NSUTF8StringEncoding]];
});
}
// After this I implement *every* method in the NSFilePresenter protocol. Each one
// simply logs its method name (so I can see it has been called) and calls reloadFile
// (not the correct implementation for all of them I know, but good enough for now).
#end
Note, reloadFile is called in applicationDidFinishLaunching and saveFile gets called every time the save button is click (via the app delegate).
The only NSFilePresenter method that ever gets called (going by the logs) is presentedItemURL (which gets called four times when the program starts and loads the file and three times whenever save is clicked. Clicking save in a second instance has no noticeable effect on the first instance.
Can anyone tell me what I'm doing wrong here?
I was struggling with this exact issue for quite a while. For me, the only method that would be called was -presentedSubitemDidChangeAtURL: (I was monitoring a directory rather than a file). I opened a technical support issue with Apple, and their response was that this is a bug, and the only thing we can do right now is to do everything through -presentedSubitemDidChangeAtURL: if you're monitoring a directory. Not sure what can be done when monitoring a file.
I would encourage anyone encountering this issue to file a bug (https://bugreport.apple.com) to encourage Apple to get this problem fixed as soon as possible.
(I realize that this is an old question, but... :) )
First of all, I notice you don't have [NSFileCoordinator removeFilePresenter:self]; anywhere (it should be in dealloc).
Secondly, you wrote:
// After this I implement *every* method in the NSFilePresenter protocol. Each one
// simply logs its method name (so I can see it has been called) and calls reloadFile
// (not the correct implementation for all of them I know, but good enough for now).
You're right: it's the incorrect implementation! And you're wrong: it's not good enough, because it's essential for methods like accommodatePresentedItemDeletionWithCompletionHandler: which take a completion block as a parameter, that you actually call this completion block whenever you implement them, e.g.
- (void) savePresentedItemChangesWithCompletionHandler:(void (^)(NSError * _Nullable))completionHandler
{
// implement your save routine here, but only if you need to!
if ( dataHasChanged ) [self save]; // <-- meta code
//
NSError * err = nil; // <-- = no error, in this simple implementation
completionHandler(err); // <-- essential!
}
I don't know whether this is the reason your protocol methods are not being called, but it's certainly a place to start. Well, assuming you haven't already worked out what was wrong in the past three years! :-)

Caching images with NSMutableDictionary

I am attempting to create an application that goes through various images from the net and aim to cache them onto the iPhone for offline use. The code I am currently working with is:
NSMutableDictionary *Cache;
- (UIImage *)CachedImage: (NSString*)url {
UIImage *image = [Cache objectForKey:url];
if (image == nil) {
image = [UIImage imageWithData:[NSData dataWithContentsOfURL:[NSURL URLWithString:url]]];
[Cache setObject:image forKey:url];
//NSLog (#"Stored");
return image;
} else {
//NSLog (#"Taken");
return image;
} }
I call the function and place the image into an ImageView using the strip of code below.
[self.imageView setImage:[self CachedImage:url]]; // Change url to desired URL.
Using the NSLog, the problem I found is that the code doesn't actually store the value because the value is always reading nil. Why is that and are there other ways of storing images for offline use?
Thanks in advance.
-Gon
Use NSCache to cache UIImages. You can also save the image locally (if you reuse these images a lot and during multiple launch) so whenever your app closes or you flush your cache, you can get the images immediately from your local directory.
https://developer.apple.com/library/mac/#documentation/Cocoa/Reference/NSCache_Class/Reference/Reference.html
You are looking for
NSCache
Check it out here: http://nshipster.com/nscache/
Poor NSCache, always being overshadowed by NSMutableDictionary in the
most inappropriate circumstances. It’s like no one knows its there,
ready to provide all of that garbage collection behavior that
developers take great pains to re-implement themselves.

How to get image file path from UIImageview

I have a UIImageView that diaplays an image. Then I have a button titled 'save' . What I want to do is that when I click the button, it should save the image file name into a plist for further retrieval and stuff.
I know how to save into plist and all. The problem is only that I don't know how to get the file path of the image being displayed in the UIImageView.
I did homework and found few articles but im still confused. Any help will be appreciated.
I dont think it is possible to get the image path from a UIImage, if by path you mean the original location on disk, then i dont think that you can do it
The best way to do this is to Save the image in document folder with name image1, image2, etc or the exact name of the image if you know it. And you can save the image names in the plist. Using the names here you can do the further stuff easily.
Create UIImageview as CustomImageview class with NSString variable.Then while showing that image,store the image file path in that string variable.Then you can get it where ever you want with the use of that string.Use the following code
#import <UIKit/UIKit.h>
#interface Imager : UIImageView
{
NSString* imageFileName; #property(nonatomic,retain)NSString* imageFileName;
}
#end
#import "Imager.h"
#implementation
#synthesize imageFileName
and the assign the filepathname where you are assigning the image like your
Imageview.image = UIImage;
your Imageview.imageFileName=yourImageFilepath;
to get the yourImageFilepath add "AssetsLibrary.framework" to your framework folder.Then add #import "AssetsLibrary/AssetsLibrary.h"; to the header file of your class.
then add the following code in "didFinishPickingMediaWithInfo" method
UIImage *viewImage = yourImage;
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
[library writeImageToSavedPhotosAlbum:[viewImage CGImage] orientation: (ALAssetOrientation)[viewImage imageOrientation] completionBlock:^(NSURL *assetURL, NSError *error)
{
if (error)
{
NSLog(#"error");
}
else
{
NSLog(#"url %#", assetURL);
}
}];
[library release];
It will return a url.that is your yourImageFilepath.

Does the UIImage Cache image?

UIImage *img = [[UIImage alloc] initWithContentsOfFile:#"xx.jpg"]
UIImage *img = [UIImage imageNamed:#"xx.jpg"]
In the second type will the image get cached ?
Whereas the in the first type the images doesn't get cached?
The -initWithContentsOfFile: creates a new image without caching, it's an ordinary initialization method.
The +imageNamed: method uses cache. Here's a documentation from UIImage Reference:
This method looks in the system caches for an image object with the specified name and returns that object if it exists. If a matching image object is not already in the cache, this method loads the image data from the specified file, caches it, and then returns the resulting object.
UIImage will retain loaded image, keeping it alive until low memory condition will cause the cache to be purged.
Update for Swift:
In Swift the UIImage(named: "...") function is the one that caches the image.
Just wanted to leave this here to help deal with the pathnames issue. This is a method that you can put on a UIImage category.
+(UIImage *)imageNamed:(NSString *)name cache:(BOOL)cache {
if (cache)
return [UIImage imageNamed:name];
name = [[NSBundle mainBundle] pathForResource:[name stringByDeletingPathExtension] ofType:[name pathExtension]];
UIImage *retVal = [[UIImage alloc] initWithContentsOfFile:name];
return retVal;
}
If you don't have an easy way to switch to cached, you might end up just using `imageNamed. This is a big mistake in most cases. See this great answer for more details (and upvote both question and answer!).
#Dan Rosenstark answer in swift..
extension UIImage {
static func imageNamed(name: String, cache: Bool) -> UIImage? {
if (cache) {
return UIImage(named: name)
}
// Using NSString for stringByDeletingPathExtension
let fullName = NSString(string: name)
let fileName = fullName.stringByDeletingPathExtension
let ext = fullName.pathExtension
let resourcePath = NSBundle.mainBundle().pathForResource(fileName, ofType: ext)
if let path = resourcePath {
return UIImage(contentsOfFile: path)
}
return nil
}
}
Correct, the second item is cached.

How to get [UIImage imageWithContentsOfFile:] and High Res Images working

As many people are complaining it seems that in the Apple SDK for the Retina Display there's a bug and imageWithContentsOfFile actually does not automatically load the 2x images.
I've stumbled into a nice post how to make a function which detects UIScreen scale factor and properly loads low or high res images ( http://atastypixel.com/blog/uiimage-resolution-independence-and-the-iphone-4s-retina-display/ ), but the solution loads a 2x image and still has the scale factor of the image set to 1.0 and this results to a 2x images scaled 2 times (so, 4 times bigger than what it has to look like)
imageNamed seems to accurately load low and high res images, but is no option for me.
Does anybody have a solution for loading low/high res images not using the automatic loading of imageNamed or imageWithContentsOfFile ? (Or eventually solution how to make imageWithContentsOfFile work correct)
Ok, actual solution found by Michael here :
http://atastypixel.com/blog/uiimage-resolution-independence-and-the-iphone-4s-retina-display/
He figured out that UIImage has the method "initWithCGImage" which also takes a scale factor as input (I guess the only method where you can set yourself the scale factor)
[UIImage initWithCGImage:scale:orientation:]
And this seems to work great, you can custom load your high res images and just set that the scale factor is 2.0
The problem with imageWithContentsOfFile is that since it currently does not work properly, we can't trust it even when it's fixed (because some users will still have an older iOS on their devices)
We just ran into this here at work.
Here is my work-around that seems to hold water:
NSString *imgFile = ...path to your file;
NSData *imgData = [[NSData alloc] initWithContentsOfFile:imgFile];
UIImage *img = [[UIImage alloc] initWithData:imgData];
imageWithContentsOfFile works properly (considering #2x images with correct scale) starting iOS 4.1 and onwards.
Enhancing Lisa Rossellis's answer to keep retina images at desired size (not scaling them up):
NSString *imagePath = ...Path to your image
UIImage *image = [UIImage imageWithData:[NSData dataWithContentsOfFile:imagePath] scale:[UIScreen mainScreen].scale];
I've developed a drop-in workaround for this problem.
It uses method swizzling to replace the behavior of the "imageWithContentsOfFile:" method of UIImage.
It works fine on iPhones/iPods pre/post retina.
Not sure about the iPad.
Hope this is of help.
#import </usr/include/objc/objc-class.h>
#implementation NSString(LoadHighDef)
/** If self is the path to an image, returns the nominal path to the high-res variant of that image */
-(NSString*) stringByInsertingHighResPathModifier {
NSString *path = [self stringByDeletingPathExtension];
// We determine whether a device modifier is present, and in case it is, where is
// the "split position" at which the "#2x" token is to be added
NSArray *deviceModifiers = [NSArray arrayWithObjects:#"~iphone", #"~ipad", nil];
NSInteger splitIdx = [path length];
for (NSString *modifier in deviceModifiers) {
if ([path hasSuffix:modifier]) {
splitIdx -= [modifier length];
break;
}
}
// We insert the "#2x" token in the string at the proper position; if no
// device modifier is present the token is added at the end of the string
NSString *highDefPath = [NSString stringWithFormat:#"%##2x%#",[path substringToIndex:splitIdx], [path substringFromIndex:splitIdx]];
// We possibly add the extension, if there is any extension at all
NSString *ext = [self pathExtension];
return [ext length]>0? [highDefPath stringByAppendingPathExtension:ext] : highDefPath;
}
#end
#implementation UIImage (LoadHighDef)
/* Upon loading this category, the implementation of "imageWithContentsOfFile:" is exchanged with the implementation
* of our custom "imageWithContentsOfFile_custom:" method, whereby we replace and fix the behavior of the system selector. */
+(void)load {
Method originalMethod = class_getClassMethod([UIImage class], #selector(imageWithContentsOfFile:));
Method replacementMethod = class_getClassMethod([UIImage class], #selector(imageWithContentsOfFile_custom:));
method_exchangeImplementations(replacementMethod, originalMethod);
}
/** This method works just like the system "imageWithContentsOfFile:", but it loads the high-res version of the image
* instead of the default one in case the device's screen is high-res and the high-res variant of the image is present.
*
* We assume that the original "imageWithContentsOfFile:" implementation properly sets the "scale" factor upon
* loading a "#2x" image . (this is its behavior as of OS 4.0.1).
*
* Note: The "imageWithContentsOfFile_custom:" invocations in this code are not recursive calls by virtue of
* method swizzling. In fact, the original UIImage implementation of "imageWithContentsOfFile:" gets called.
*/
+ (UIImage*) imageWithContentsOfFile_custom:(NSString*)imgName {
// If high-res is supported by the device...
UIScreen *screen = [UIScreen mainScreen];
if ([screen respondsToSelector:#selector(scale)] && [screen scale]>=2.0) {
// then we look for the high-res version of the image first
UIImage *hiDefImg = [UIImage imageWithContentsOfFile_custom:[imgName stringByInsertingHighResPathModifier]];
// If such high-res version exists, we return it
// The scale factor will be correctly set because once you give imageWithContentsOfFile:
// the full hi-res path it properly takes it into account
if (hiDefImg!=nil)
return hiDefImg;
}
// If the device does not support high-res of it does but there is
// no high-res variant of imgName, we return the base version
return [UIImage imageWithContentsOfFile_custom:imgName];
}
#end
[UIImage imageWithContentsOfFile:] doesn't load #2x graphics if you specify an absolute path.
Here is a solution:
- (UIImage *)loadRetinaImageIfAvailable:(NSString *)path {
NSString *retinaPath = [[path stringByDeletingLastPathComponent] stringByAppendingPathComponent:[NSString stringWithFormat:#"%##2x.%#", [[path lastPathComponent] stringByDeletingPathExtension], [path pathExtension]]];
if( [UIScreen mainScreen].scale == 2.0 && [[NSFileManager defaultManager] fileExistsAtPath:retinaPath] == YES)
return [[[UIImage alloc] initWithCGImage:[[UIImage imageWithData:[NSData dataWithContentsOfFile:retinaPath]] CGImage] scale:2.0 orientation:UIImageOrientationUp] autorelease];
else
return [UIImage imageWithContentsOfFile:path];
}
Credit goes to Christof Dorner for his simple solution (which I modified and pasted here).