I'm using dataWithContentsOfFile on a PNG image and the iOS Simulator returns a value that differs from an iOS Device. My device is a 64-bit iPad Air (iOS 8.3) and my simulator is set to iPad Retina iOS 8.3. Here's the code that I'm using:
NSString *sourcePath = [[NSBundle mainBundle] pathForResource:#"image" ofType:#"png"];
NSData *data = [NSData dataWithContentsOfFile:sourcePath];
NSString *hash = [self md5Hash:data]
// Results on device: 2D25F346396FB00BEB27754ED1B56310
// Results on simulator: 55016FD1AB3DA0F882FEA85D5ABCA2ED
I tested my hash function with a string, and it works fine regardless of device. I'm not going to display the results of the dataWithContentsOfFile method, but I can assure you that they're different.
Update: Testing dataWithContentsOfURL works fine, example:
NSURL *fileURL = [NSURL URLWithString:#"https://www.google.com/images/srpr/logo11w.png"];
NSData *data = [NSData dataWithContentsOfURL:fileURL];
NSString *hash = [self md5Hash:data]
// Results on device: 57E396BAEDFE1A034590339082B9ABCE
// Results on simulator: 57E396BAEDFE1A034590339082B9ABCE
I'm going to guess that it's Xcode applying PNGCrush to your image... so it is actually not the same file.
Related
I was trying to load image using method:
[UIImage imageNamed:imageName]
[UIImage imageWithContentsOfFile:imagePath]
In IOS 8.x, the images are loaded. However in IOS 7.x simulators, the above methods always return nil. This situation happened in both simulators and devices.
NSBundle *myBundle = [NSBundle findMyBundle];
[myBundle load];
NSString *imagePath = [NSString stringWithFormat:#"%#/%#", [myBundle bundlePath], imageName];
UIImage *targetImage = [UIImage imageWithContentsOfFile:imagePath];
NSLog(#"FrameworkBundle: %#", myBundle);
// Bundle does exist For IOS 7.x
NSLog(#"Image: %#", targetImage);
// targetImage = nil for IOS 7.x; while it does return image for IOS 8.x
Is there any method need to notice for loading UIImage about IOS 7.x devices / simulators.?
Edit:
Here is what worked out for me:
// I have to specify imageType to be #"png"
// If one compose the path without the fileType ending, it does not load the image properly.
NSString *imagePath = [myBundle pathForResource:imageName ofType:#"png"];
UIImage *myImage = [UIImage imageWithContentsOfFile:imagePath];
I think there was a change when iOS 8 launched in how and where the bundles exist, I just search on Stackoverflow and probably this question (and its answer can help you), you probably have to use a different loading method for locating bundle or resource
ios 8: Bundle path changes
PS:should have been a comment in your answer but dont have enought reputation at the moment :)
I'm trying to preload the image tags from an html string in order to load them when the device is offline. Basically, I strip the source url from all the <img>tags, clean the url to have a clean filename, then download the image.
__block NSString *imageName = [[NSString alloc]init];
//Get the string after HTTP://
NSArray *nohttp = [actualUrl componentsSeparatedByString:#"//"];
imageName = [nohttp objectAtIndex:1];
//Clean any /.:
imageName = [imageName stringByReplacingOccurrencesOfString:#"/" withString:#""];
imageName = [imageName stringByReplacingOccurrencesOfString:#"." withString:#""];
imageName = [imageName stringByReplacingOccurrencesOfString:#":" withString:#""];
//Add .png at the end as we will be saving it as a PNG
imageName = [NSString stringWithFormat:#"%#.png", imageName];
//change the source url to the new filename of the image so the WebView will load it from the main bundle
html = [html stringByReplacingOccurrencesOfString:actualUrl withString:imageName];
//save the image to the main bundle
NSString *pathString = [NSString stringWithFormat:#"%#/%#",[[NSBundle mainBundle]bundlePath], imageName];
//this just checks if the image already exists
BOOL test = [[NSFileManager defaultManager] fileExistsAtPath:pathString];
if (!test){
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0ul); dispatch_async(queue, ^(void) {
NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:actualUrl]];
UIImage* image = [[UIImage alloc] initWithData:imageData];
NSData *imageData2 = UIImagePNGRepresentation(image);
[imageData2 writeToFile:pathString atomically:YES];
});
}
Then after I load the html string into the UIWebView, it works perfectly on the simulator, but on the device the images just aren't loaded. Why?
NSURL *baseUrl = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#",[[NSBundle mainBundle]bundlePath]]];
[self.webView loadHTMLString:self.htmlPage baseURL:baseUrl];
Any suggestions, thoughts? The images download fine on the iOS device/simulator but aren't loaded in the WebView of the real device. It works perfectly for the simulator.
That is correct.
On iOS an App's bundle is read-only. Any attempts to save changes into your bundle will fail on an iOS device.
On Mac OS the bundle is not read-only, but you should still treat it as read-only. Modifying your app's bundle is a bad idea. If the user updates their app from the app store, restores from a backup, etc, then changes you save to the bundle will be lost, even on Mac OS.
The simulator runs under Mac OS, and is built against Mac OS frameworks and the Mac file system.
There are a fair number of differences between the sim and running on a device. This is one.
Another example: The iOS file system is always case-senstive. The simulator, which runs on Mac OS, is not case-sensitive by default. (Mac OS can read from volumes running different file systems. The default file system is not case sensitive, but you can set it up to be case-sensitive.)
The file "Foo.txt" is a different file than the file "foo.txt". They can both exist in the same directory. If your file is called "Foo.txt" and you try to load it with the string "foo.txt" it will fail on an iOS device, but work on Mac OS.
As a result, you should always test your apps on an actual device. Don't assume that if something works correctly on the sim that it's correct for an iOS device. It may not be.
I have a plist (NSDictionary) which I intended can be changed by user data input. Here is what I have done.
NSString *path = (the path for the plist)
NSMutableDictionary *plistFile = [[NSDictionary dictionaryWithContentOfFile:path] mutableCopy];
[plistFile setObject:(an NSString object) forKey:(an NSString key)];
[plistFile writeToFile:path atomically:YES];
So this is what I have coded. It works well on iPad 3 (new iPad) (iOS 6.1.2) and my XCode (4.6) simulator (iOS 6). However, it does not work on my iPad mini (iOS 6.1.3). I have found the problem which is in the last step. When I wrote
BOOL success = [plistFile writeToFile:path atomically:YES];
NSLog(#"%#",#(success));
The console always prints 0 which means it does not succeed. But on my iPad 3 and simulator it prints 1, which means success.
That is all I can describe because there is no exception being thrown out or other output. By the way, my iPad 3 (on which it works) is jailbroken but the iPad mini is not. Nevertheless, I use my developer account to codesign on both devices. Can anyone help me? Or else can anyone point to me a new solution?
Try to use
NSError * error = nil;
BOOL success = [plistFile writeToFile:path options:NSDataWritingAtomic error:&error];
NSLog(#"Success = %d, error = %#", success, error);
And then check what error occures. Maybe it can helps you.
And you can write only to the document directory. You may have some troubles with your path.
I can't see from your code if you have done this, but your path needs to be the sandboxed app directory.
NSArray* pathList = NSSearchPathForDirectoriesInDomains(NSApplicationSupportDirectory, NSUserDomainMask, YES);
NSString* path = [[NSString alloc] initWithFormat:#"%#", [pathList objectAtIndex:0]];
I had a lot of trouble trying to force the loading of the low-resolution version of some resources on iOS, when the high-res version (#2x) is also present.
The reason I wanted to do this is simple: My app shows a bunch of full-screen images to the user (320x480 on older devices, 640x960 on Retina devices), and the user can upload some of these to TwitPic. I wanted to unify the uploaded images to 320x480, regardless of the device (for consistency, because that size is fine in a web browser).
I found out that no matter what UIImage method I used, when the high-resolution version of a resource file is present it is loaded (even if you pass the full file path): UIImage will out-smart you. But I found a way to out-smart UIImage:
- (UIImage*) lowResImage{
NSString* path = [[NSBundle mainBundle] pathForResource:_fileName
ofType:#"png"
inDirectory:_resourceSubdirectory];
path = [path stringByReplacingOccurrencesOfString:#"##2x" withString:#""];
NSData* imageData = [[NSData alloc] initWithContentsOfFile:path];
UIImage* image = [[UIImage alloc] initWithData:imageData];
[imageData release];
return [image autorelease];
}
The above code works fine on a 4th generation iPod touch.
Anybody came up with a better approach?
Build your path, open data, and then init the image using data as in the example below.
NSString *dataPath = [[[NSBundle mainBundle] bundlePath] stringByAppendingPathComponent:_fileName];
NSData *data = [[NSData alloc] initWithContentsOfFile:dataPath];
UIImage *image3 = [UIImage imageWithData:data];
I'm try to create some images and store it inside the Documents folder. When I run it on the simulator it is fine. However when I run it through the ipad device, the gdb just pauses at a certain point and doesn't give me much information to work with. I used the analyser to check what items to release to check memory leaks. Im running 4.3 SDK.
I'm not sure what the actual issue is. Sometimes looping through 100 images and storing them is ok but then after a while it just pauses. Where can I look further for debug or clues on how to fix this. I have provided some code.
for(int i = 0; i < totalpages; i++)
{
NSString *imagePath = [NSString stringWithFormat:#"%#/%d.jpg",
imageFullPathFolder, i+1];
if(![manager fileExistsAtPath:imagePath])
{
NSString *urlParams = [NSString stringWithFormat:#"SOMEURL",
fileSourceId, i+1];
NSURL *imageUrl = [NSURL URLWithString:urlParams];
UIImage *image = [UIImage imageWithData:[NSData
dataWithContentsOfURL:imageUrl]];
NSData *imageData = UIImageJPEGRepresentation(image, 1.0);
[manager createFileAtPath:imagePath contents:imageData
attributes:nil];
[imageData release];
}
}
You don't need to release the image data returned by UIImageJPEGRepresentation (you don't own it; you're over-releasing it).