I have an IOS app that is using RestKit to pull json formatted data from a server into a CoreData Entity. One of the attributes in the data is a URL for the image associated with the particular article. I'm trying to load that image to my collectionViewController. This is what I've been trying with no success.
From within
- (UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
I am trying this
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSURL *photoURL = [object valueForKey:#"imageUrl"];
NSData *photoData = [NSData dataWithContentsOfURL:photoURL];
cell.cellimg = [[UIImage alloc] initWithData:photoData];
[cell.title setText:[object valueForKey:#"title"]];
If I comment out the attempt to grab and load the image the view loads great with a default image and the titles of the articles received from the json data. Based on that I know everything is coming in correctly.
I have also determined that *photoData is being assigned the correct URL. But each time I encounter the NSData line the console prints out "-[__NSCFString isFileURL]: unrecognized selector sent to instance...."
I honestly don't know if this is even the correct way to do this or if it will even work. I am pretty new at this so any help would be great. Given that I am new some small code examples would really help as well as explaining the proper way to approach this.
Just in case here is the header file where I define *cellimg and *title
#import <UIKit/UIKit.h>
#interface GlobismNewsCollectionViewCell : UICollectionViewCell
#property (strong, nonatomic) IBOutlet UIImage *cellimg;
#property (weak, nonatomic) IBOutlet UILabel *title;
#property (weak, nonatomic) NSURL *imageUrl;
#end
I think you are using NSString as NSURL. So try to use this one...
NSURL *photoURL = [NSURL URLWithString:(NSString *) [object valueForKey:#"imageUrl"]];
Thanks to Dharmbir I had this issue wrapped up within 25 minutes of asking the question!
To clarify for any new guys like me I changed the line Dharmbir suggested so the block looks like this now
NSManagedObject *object = [self.fetchedResultsController objectAtIndexPath:indexPath];
NSURL *photoURL = [NSURL URLWithString:(NSString *) [object valueForKey:#"imageUrl"]];
NSData *photoData = [NSData dataWithContentsOfURL:photoURL];
[cell.cellimg setImage:[[UIImage alloc] initWithData:photoData]];
[cell.title setText:[object valueForKey:#"title"]];
Notice the 4th line in the block also changed from this
cell.cellimg = [[UIImage alloc] initWithData:photoData];
to this
[cell.cellimg setImage:[[UIImage alloc] initWithData:photoData]];
I also had to change my *cellimg property to this
#property (strong, nonatomic) IBOutlet UIImageView *cellimg;
from this
#property (strong, nonatomic) IBOutlet UIImage *cellimg;
I had to change to the UIImageView class because the cell in my storyboard is based on the UIImageView Class. Hope this helps a guy in need thanks again Dharmbir!
edit 2
I found out it depends on the method used. I somehow lose the appdelegate pointer when I access it via scrollViewDidEndDecelerating instead of awakeFromNib. But I do need to use scrollViewDidEndDecelerating.
Can someone of you please fix this?
Works fine
- (void)awakeFromNib
{
AppDelegate *mainDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog(#"%#", [NSString stringWithFormat:#"%#", mainDelegate.content1]);
}
Crashes bad_access to mainDelegate.content1
- (void)scrollViewDidEndDecelerating:(UIScrollView *)scrollView
{
AppDelegate *mainDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSLog(#"%#", [NSString stringWithFormat:#"%#", mainDelegate.content1]);
}
ORIGINAL QUESTION (I keep this for past-reference. Just read the above functions)
This problem regards stringWithContentsOfURL
The code below works, downloads HTMLstring to mainDelegate.content1 and shows it appropriately in UIWebView controller.myWebView. If I modify the function, so that I conduct the downloading process beforehand, let it be somewhere in AppDelegate.m, the program crashes upon processing mainDelegate.content1 in this very function.
Here goes the good code
- (void)ReloadView:(int)page{
MyViewController *controller = [viewControllers objectAtIndex:pageControl.currentPage];
mainDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
NSError * error;
NSURL * Tmpurl;
NSString *tmpContent;
NSString *urlAddress;
urlAddress = mainDelegate.TitleStrP1;
Tmpurl = [NSURL URLWithString:urlAddress];
tmpContent = [NSString stringWithContentsOfURL:Tmpurl encoding:NSUTF8StringEncoding error:&error];
maindelegate.content1 = [NSString stringWithString:tmpContent];
[controller.myWebView loadHTMLString:mainDelegate.content1 baseURL:nil];
}
And here what I am trying to do and what doesn't work. SomeFunction executes upon startup of the app. I checked the loaded value after downloading HTMLstring into content1 from the Internet site and html code indeed is there.
- (void)ReloadView:(int)page{
MyViewController *controller = [viewControllers objectAtIndex:pageControl.currentPage];
mainDelegate = (AppDelegate *)[[UIApplication sharedApplication] delegate];
//code had been removed here
[controller.myWebView loadHTMLString:mainDelegate.content1 baseURL:nil];
}
-(void)SomeFunction{
NSError * error;
NSURL * Tmpurl;
NSString *tmpContent;
NSString *urlAddress;
urlAddress = mainDelegate.TitleStrP1;
Tmpurl = [NSURL URLWithString:urlAddress];
tmpContent = [NSString stringWithContentsOfURL:Tmpurl encoding:NSUTF8StringEncoding error:&error];
maindelegate.content1 = [NSString stringWithString:tmpContent];
}
Your help is appreciated.
Thanks
EDIT:
AppDelegate.h
#import <UIKit/UIKit.h>
#class ContentController,MyViewController;
#interface AppDelegate : NSObject <UIApplicationDelegate>
{
...
NSString *content1;
NSString *content2;
}
...
#property (nonatomic, strong) NSString * content1;
#property (nonatomic, strong) NSString * content2;
AppDelegate.m
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
content1 = [NSString stringWithString:#""];
content2 = [NSString stringWithString:#""];
NSError * error;
NSURL * Tmpurl;
NSString *tmpContent;
NSString *urlAddress;
urlAddress = TitleStrP1;
Tmpurl = [NSURL URLWithString:urlAddress];
tmpContent = [NSString stringWithContentsOfURL:Tmpurl encoding:NSUTF8StringEncoding error:&error];
content1 = [NSString stringWithString:tmpContent];
urlAddress = TitleStrP2;
Tmpurl = [NSURL URLWithString:urlAddress];
tmpContent = [NSString stringWithContentsOfURL:Tmpurl encoding:NSUTF8StringEncoding error:&error];
content2 = [NSString stringWithString:tmpContent];
...
}
Is your "Content1" property in the appDelegate using "strong"? Also, to use properties, you should be using lower class as the setter needs to capitalize the variable name (setContent1). That is
#property (nonatomic, strong) NSString *content1;
EDIT:
[[UIApplication sharedApplication] delegate] will always work. By bad, you did not say if there is a value there or not (that is, is it nil). So one of these is happening.
1) your AppDelegate object is getting released and dealloced. I'm not sure how you would do this but its possible.
2) You have told UIApplication to create a delegate in main.m, in the fourth parameter of "UIApplicationMain()", but have also specified a NIB in your .plist file and that nib ALSO has a AppDelegate object in it and is wired to the UIApplication as a delegate. If you are using a NIB the property attribute for AppDelegate better be STRONG as its not retained by the UIApplication (it says this in the delegate property of UIApplication).
3) If the "delegate" property is nil, then someone has set it to nil.
Think about it - the UIApplication delegate gets set very early, otherwise you would never get the launched message.
So you need to add a "dealloc" method to your app delegate and log if that happens. You can also add a simple "init" method that also logs when AppDelegate is created - then see if my suspicion is correct.
I have used the following code.
MainView.h:
NSString *sCopySource;
NSString *sFileSource;
// retain and copy used both for test proposes
#property (nonatomic, retain) NSString *sCopySource;
#property (nonatomic, copy) NSString *sFileSource;
MainView.m:
// Inside the first method:
sCopySource = [NSString stringWithFormat:#"%#%#", path1, filename];
sFileSource = [NSString stringWithFormat:#"%#%#", path2, filename];
// Inside the second method:
[[NSFileManager defaultManager] copyItemAtPath:sCopySource toPath:sFileSource error:&err];
And take error in the last line of the code by zombie-enabled objects sCopySource and sFileSource:
message sent to deallocated instance
Why? The properties marked as retain and copy. How to fix this?
Thanks a lot for the help!
P.S. Please don't answer to use ratain and release methods. They're extremely inconvenient.
You have defined the property, but you are writing directly to the instance variable.
If you want to use the retain/release logic in the property, you need to use:
self.sCopySource = [NSString stringWithFormat:#"%#%#", path1, filename];
self.sFileSource = [NSString stringWithFormat:#"%#%#", path2, filename];
That way, the methods that do the copy and retain are used.
Hey guys, I'm receiving a SIGABRT when trying to use an instance variable for anything but an NSLOG :
//Class_X.H
#interface MeldingController : UIViewController
{
NSString *refURLAsString;
}
#property (nonatomic, retain) NSString *refURLAsString;
//Class_X.M
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info
{
self.refURLAsString = [info objectForKey:UIImagePickerControllerReferenceURL];
NSLog(#"%#",self.refURLAsString);//Successfully outputs the ReferenceURL string
}
-(void)function_abc
{
NSLog(#"%#",self.refURLAsString);//Successfully outputs the ReferenceURL string
NSURL *URL = [NSURL URLWithString:self.refURLAsString]; //SIGABRT
//Or even trying to make another string using refUrlAsString
NSString *string = [[NSString alloc]init];
string = self.refURLAsString;//SIGABRT
}
iPhone Simulator iOS version 4.3, Xcode 4.
Any ideas anyone? cheers.
Your refURLAsString is of type NSString *, but [info objectForKey:UIImagePickerControllerReferenceURL] should return a NSURL * instance according to the docs. You want:
self.refURLAsString = [[info objectForKey:UIImagePickerControllerReferenceURL] absoluteString];
The reason why the NSLog works is because it calls the description method on each object that is to be printed via the %# sequence, and that does return a string. But refURLAsString is pointing to a NSURL instead of a NSString, and that makes [NSURL URLWithString:self.refURLAsString]; crash.
try this
string =[refURLAsString copy];
Your code is screwing up refURLAsString. I can't tell you how from the posted code. Activate NSZombieEnabled for details.
Not sure exactly whats the issue is, but try string = [NSString stringWithFormat:#"%#",self.refURLAsString]; and see if it crashes here too
NSString *string = [NSString stringWithFormat:#"%#",self.refURLAsString];
no need to alloc here
Wondering if there is an easy way to do a simple HTML escape/unescape in Objective C. What I want is something like this psuedo code:
NSString *string = #"<span>Foo</span>";
[string stringByUnescapingHTML];
Which returns
<span>Foo</span>
Hopefully unescaping all other HTML entities as well and even ASCII codes like Ӓ and the like.
Is there any methods in Cocoa Touch/UIKit to do this?
Check out my NSString category for XMLEntities. There's methods to decode XML entities (including all HTML character references), encode XML entities, stripping tags and removing newlines and whitespace from a string:
- (NSString *)stringByStrippingTags;
- (NSString *)stringByDecodingXMLEntities; // Including all HTML character references
- (NSString *)stringByEncodingXMLEntities;
- (NSString *)stringWithNewLinesAsBRs;
- (NSString *)stringByRemovingNewLinesAndWhitespace;
Another HTML NSString category from Google Toolbox for Mac
Despite the name, this works on iOS too.
http://google-toolbox-for-mac.googlecode.com/svn/trunk/Foundation/GTMNSString+HTML.h
/// Get a string where internal characters that are escaped for HTML are unescaped
//
/// For example, '&' becomes '&'
/// Handles and 2 cases as well
///
// Returns:
// Autoreleased NSString
//
- (NSString *)gtm_stringByUnescapingFromHTML;
And I had to include only three files in the project: header, implementation and GTMDefines.h.
This link contains the solution below. Cocoa CF has the CFXMLCreateStringByUnescapingEntities function but that's not available on the iPhone.
#interface MREntitiesConverter : NSObject <NSXMLParserDelegate>{
NSMutableString* resultString;
}
#property (nonatomic, retain) NSMutableString* resultString;
- (NSString*)convertEntitiesInString:(NSString*)s;
#end
#implementation MREntitiesConverter
#synthesize resultString;
- (id)init
{
if([super init]) {
resultString = [[NSMutableString alloc] init];
}
return self;
}
- (void)parser:(NSXMLParser *)parser foundCharacters:(NSString *)s {
[self.resultString appendString:s];
}
- (NSString*)convertEntitiesInString:(NSString*)s {
if (!s) {
NSLog(#"ERROR : Parameter string is nil");
}
NSString* xmlStr = [NSString stringWithFormat:#"<d>%#</d>", s];
NSData *data = [xmlStr dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
NSXMLParser* xmlParse = [[[NSXMLParser alloc] initWithData:data] autorelease];
[xmlParse setDelegate:self];
[xmlParse parse];
return [NSString stringWithFormat:#"%#",resultString];
}
- (void)dealloc {
[resultString release];
[super dealloc];
}
#end
This is an incredibly hacked together solution I did, but if you want to simply escape a string without worrying about parsing, do this:
-(NSString *)htmlEntityDecode:(NSString *)string
{
string = [string stringByReplacingOccurrencesOfString:#""" withString:#"\""];
string = [string stringByReplacingOccurrencesOfString:#"'" withString:#"'"];
string = [string stringByReplacingOccurrencesOfString:#"<" withString:#"<"];
string = [string stringByReplacingOccurrencesOfString:#">" withString:#">"];
string = [string stringByReplacingOccurrencesOfString:#"&" withString:#"&"]; // Do this last so that, e.g. #"<" goes to #"<" not #"<"
return string;
}
I know it's by no means elegant, but it gets the job done. You can then decode an element by calling:
string = [self htmlEntityDecode:string];
Like I said, it's hacky but it works. IF you want to encode a string, just reverse the stringByReplacingOccurencesOfString parameters.
In iOS 7 you can use NSAttributedString's ability to import HTML to convert HTML entities to an NSString.
Eg:
#interface NSAttributedString (HTML)
+ (instancetype)attributedStringWithHTMLString:(NSString *)htmlString;
#end
#implementation NSAttributedString (HTML)
+ (instancetype)attributedStringWithHTMLString:(NSString *)htmlString
{
NSDictionary *options = #{ NSDocumentTypeDocumentAttribute : NSHTMLTextDocumentType,
NSCharacterEncodingDocumentAttribute :#(NSUTF8StringEncoding) };
NSData *data = [htmlString dataUsingEncoding:NSUTF8StringEncoding];
return [[NSAttributedString alloc] initWithData:data options:options documentAttributes:nil error:nil];
}
#end
Then in your code when you want to clean up the entities:
NSString *cleanString = [[NSAttributedString attributedStringWithHTMLString:question.title] string];
This is probably the simplest way, but I don't know how performant it is. You should probably be pretty damn sure the content your "cleaning" doesn't contain any <img> tags or stuff like that because this method will download those images during the HTML to NSAttributedString conversion. :)
Here's a solution that neutralizes all characters (by making them all HTML encoded entities for their unicode value)... Used this for my need (making sure a string that came from the user but was placed inside of a webview couldn't have any XSS attacks):
Interface:
#interface NSString (escape)
- (NSString*)stringByEncodingHTMLEntities;
#end
Implementation:
#implementation NSString (escape)
- (NSString*)stringByEncodingHTMLEntities {
// Rather then mapping each individual entity and checking if it needs to be replaced, we simply replace every character with the hex entity
NSMutableString *resultString = [NSMutableString string];
for(int pos = 0; pos<[self length]; pos++)
[resultString appendFormat:#"&#x%x;",[self characterAtIndex:pos]];
return [NSString stringWithString:resultString];
}
#end
Usage Example:
UIWebView *webView = [[UIWebView alloc] init];
NSString *userInput = #"<script>alert('This is an XSS ATTACK!');</script>";
NSString *safeInput = [userInput stringByEncodingHTMLEntities];
[webView loadHTMLString:safeInput baseURL:nil];
Your mileage will vary.
The least invasive and most lightweight way to encode and decode HTML or XML strings is to use the GTMNSStringHTMLAdditions CocoaPod.
It is simply the Google Toolbox for Mac NSString category GTMNSString+HTML, stripped of the dependency on GTMDefines.h. So all you need to add is one .h and one .m, and you're good to go.
Example:
#import "GTMNSString+HTML.h"
// Encoding a string with XML / HTML elements
NSString *stringToEncode = #"<TheBeat>Goes On</TheBeat>";
NSString *encodedString = [stringToEncode gtm_stringByEscapingForHTML];
// encodedString looks like this now:
// <TheBeat>Goes On</TheBeat>
// Decoding a string with XML / HTML encoded elements
NSString *stringToDecode = #"<TheBeat>Goes On</TheBeat>";
NSString *decodedString = [stringToDecode gtm_stringByUnescapingFromHTML];
// decodedString looks like this now:
// <TheBeat>Goes On</TheBeat>
This is an easy to use NSString category implementation:
http://code.google.com/p/qrcode-scanner-live/source/browse/trunk/iphone/Classes/NSString%2BHTML.h
http://code.google.com/p/qrcode-scanner-live/source/browse/trunk/iphone/Classes/NSString%2BHTML.m
It is far from complete but you can add some missing entities from here: http://code.google.com/p/statz/source/browse/trunk/NSString%2BHTML.m
Usage:
#import "NSString+HTML.h"
NSString *raw = [NSString stringWithFormat:#"<div></div>"];
NSString *escaped = [raw htmlEscapedString];
The MREntitiesConverter above is an HTML stripper, not encoder.
If you need an encoder, go here: Encode NSString for XML/HTML
MREntitiesConverter doesn't work for escaping malformed xml. It will fail on a simple URL:
http://www.google.com/search?client=safari&rls=en&q=fail&ie=UTF-8&oe=UTF-8
If you need to generate a literal you might consider using a tool like this:
http://www.freeformatter.com/java-dotnet-escape.html#ad-output
to accomplish the work for you.
See also this answer.
This easiest solution is to create a category as below:
Here’s the category’s header file:
#import <Foundation/Foundation.h>
#interface NSString (URLEncoding)
-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding;
#end
And here’s the implementation:
#import "NSString+URLEncoding.h"
#implementation NSString (URLEncoding)
-(NSString *)urlEncodeUsingEncoding:(NSStringEncoding)encoding {
return (NSString *)CFURLCreateStringByAddingPercentEscapes(NULL,
(CFStringRef)self,
NULL,
(CFStringRef)#"!*'\"();:#&=+$,/?%#[]% ",
CFStringConvertNSStringEncodingToEncoding(encoding));
}
#end
And now we can simply do this:
NSString *raw = #"hell & brimstone + earthly/delight";
NSString *url = [NSString stringWithFormat:#"http://example.com/example?param=%#",
[raw urlEncodeUsingEncoding:NSUTF8Encoding]];
NSLog(url);
The credits for this answer goes to the website below:-
http://madebymany.com/blog/url-encoding-an-nsstring-on-ios
Why not just using ?
NSData *data = [s dataUsingEncoding:NSUTF8StringEncoding allowLossyConversion:YES];
NSString *result = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease];
return result;
Noob question but in my case it works...
This is an old answer that I posted some years ago. My intention was
not to provide a "good" and "respectable" solution, but a "hacky" one
that might be useful under some circunstances. Please, don't use this solution unless nothing else works.
Actually, it works perfectly fine in many situations that other
answers don't because the UIWebView is doing all the work. And you can
even inject some javascript (which can be dangerous and/or useful). The performance should be horrible, but actually is not that bad.
There is another solution that has to be mentioned. Just create a UIWebView, load the encoded string and get the text back. It escapes tags "<>", and also decodes all html entities (e.g. ">") and it might work where other's don't (e.g. using cyrillics). I don't think it's the best solution, but it can be useful if the above solutions doesn't work.
Here is a small example using ARC:
#interface YourClass() <UIWebViewDelegate>
#property UIWebView *webView;
#end
#implementation YourClass
- (void)someMethodWhereYouGetTheHtmlString:(NSString *)htmlString {
self.webView = [[UIWebView alloc] init];
NSString *htmlString = [NSString stringWithFormat:#"<html><body>%#</body></html>", self.description];
[self.webView loadHTMLString:htmlString baseURL:nil];
self.webView.delegate = self;
}
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
self.webView = nil;
}
- (void)webViewDidFinishLoad:(UIWebView *)webView {
self.webView = nil;
NSString *escapedString = [self.webView stringByEvaluatingJavaScriptFromString:#"document.body.textContent;"];
}
- (void)webViewDidStartLoad:(UIWebView *)webView {
// Do Nothing
}
#end