Saving NSAttributedString with NSTextAttachment into file. How to? - objective-c

I have a NSTextView, which may contains rich text or rich text with image as NSTextAttachment. There is how I adds attachment:
NSImage *image = [NSImage imageNamed:#"image"];
NSTextAttachmentCell *attachmentCell =[[NSTextAttachmentCell alloc] initImageCell:image];
NSTextAttachment *attachment =[[NSTextAttachment alloc] init];
[attachment setAttachmentCell: attachmentCell ];
NSAttributedString *attributedString =[NSAttributedString attributedStringWithAttachment: attachment];
[[aTextView textStorage] beginEditing];
if ([aTextView shouldChangeTextInRange:NSMakeRange([aTextView selectedRange].location, 0) replacementString:#""]) {
[[aTextView textStorage] insertAttributedString:attributedString atIndex:[aTextView selectedRange].location];
[aTextView didChangeText];
}
[[aTextView textStorage] endEditing];
My -fileWrapperOfType:error: method:
- (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError *__autoreleasing *)outError
{
NSRange documentRange = NSMakeRange(0, [[[WindowController aTextView] textStorage] length]);
NSTextStorage *text = [[WindowController aTextView] textStorage];
NSFileWrapper *resultWrapper = nil;
if ([typeName compare:#"public.rtf"] == NSOrderedSame) {
resultWrapper = [[NSFileWrapper alloc] initRegularFileWithContents:[text RTFFromRange:documentRange documentAttributes:[NSDictionary dictionaryWithObjectsAndKeys:NSRTFTextDocumentType, NSDocumentTypeDocumentAttribute, nil]]];
}
else if ([typeName compare:#"com.apple.rtfd"] == NSOrderedSame) {
resultWrapper = [text RTFDFileWrapperFromRange:documentRange documentAttributes:[NSDictionary dictionaryWithObjectsAndKeys:NSRTFDTextDocumentType, NSDocumentTypeDocumentAttribute, nil]];
}
return resultWrapper;
}
But when I'm saving RTFD, all attachments looses. Please, help. What I'm missing?

I have found an acceptable solution, it's described here: Cocoa: custom attachment in a text view

Related

How can I search any volume in macOS?

- (void)readFolder:(NSString *)str :(NSMutableDictionary *)dict {
NSArray *appFolderContents = [[NSArray alloc] init];
appFolderContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:str error:nil];
for (NSString *app in appFolderContents) {
if ([app containsString:#".app"])
{
NSString *appName = [[app lastPathComponent] stringByDeletingPathExtension];
NSString *appPath = [NSString stringWithFormat:#"%#/%#", str, app];
NSString *appBundle = [[NSBundle bundleWithPath:appPath] bundleIdentifier];
// NSLog(#"%# -- %#", appPath, appBundle);
NSArray *jumboTron = [NSArray arrayWithObjects:appName, appPath, appBundle, nil];
[dict setObject:jumboTron forKey:appName];
}
}
}
//This searches for apps
- (void)getAPPList {
NSMutableDictionary *myDict = [[NSMutableDictionary alloc] init];
[self readFolder:#"/Applications" :myDict];
[self readFolder:#"/Applications/Utilities" :myDict];
[self readFolder:#"/System/Library/CoreServices" :myDict];
[self readFolder:#"/Volumes/Macintosh HD/Applications" :myDict ];
// Volumes not named 'Macintosh HD' doesn't work, I'm trying to make it work
[self readFolder:#"/Volumes/*/Applications" :myDict ];
//Some apps are stored in the user's Application folder instead of the main one
[self readFolder:[NSString stringWithFormat:#"%#/Applications", NSHomeDirectory()] :myDict];
//Sometimes people keep apps in Downloads
[self readFolder:[NSString stringWithFormat:#"%#/Downloads", NSHomeDirectory()] :myDict];
//Some apps are stored in the user's Library/Application Support sometimes
[self readFolder:[NSString stringWithFormat:#"%#/Library/Application Support", NSHomeDirectory()] :myDict];
I'm trying to make line 26 ([self readFolder:#"/Volumes/*/Applications" :myDict ]) search all volumes, instead of only searching a volume with a matching/specific name. How can I do this?
I'm using Xcode 9.2
something like this should do the trick (untested)
NSArray *keys = [NSArray arrayWithObjects:NSURLVolumeURLKey, NSURLIsVolumeKey, nil];
NSArray *volumeUrls = [[NSFileManager defaultManager] mountedVolumeURLsIncludingResourceValuesForKeys:keys options:NSVolumeEnumerationSkipHiddenVolumes];
for (NSURL *volumeUrl in volumeUrls)
{
BOOL mayBeBootVolume = NO;
NSString* pathToVolume = [volumeUrl path];
[self readFolder: [pathToVolume stringByAppendingString: #"/Applications"];
}

NSRTFPboardType & paste into gmail browser window?

I have a NSTextView which contains some text with attributes (syntax highlighting). I'm trying to have a copy option which keeps the syntax highlighting so that I can paste it into a gmail text window. Currently the highlighting does not appear when I copy paste it, however if I were to copy the following section directly from this stackoverflow page:
- (void) copyAsRTF
{
NSPasteboard *pateboard = [NSPasteboard generalPasteboard];
NSData * rtfData = [[self textStorage] RTFFromRange: [self selectedRange]
documentAttributes: nil];
if (rtfData)
{
NSString * test = [[NSString alloc] initWithData: rtfData
encoding: NSUTF8StringEncoding];
[pateboard declareTypes: #[NSRTFPboardType]
owner: self];
[pateboard setData: rtfData
forType: NSRTFPboardType];
} // End of we had data
} // End of copyAsRTF
And paste it into gmail, it will paste with full syntax highlight no problem. The above code is what I use for generating my RTF code and I can confirm that it does generate proper RTF as I have a test variable being generated.
Any ideas what I am doing wrong here? To my understanding this SHOULD work.
(I should note that I have tried in multiple browsers - Chrome, Safari and Firefox).
As discovered in comments, in order to be working in chrome, you need to copy your text as html (public.html pasteboard type) or probably both html an rtf types.
Based on the comments with #Sega-Zero, I came up with the following (a bit sloppy, but it does the trick). For my specific needs, the html color & font should match the attributed string, so I enumerate that and create an html variable. This works in Safari, Chrome and Firefox.
#define PasteBoardTypeHTML #"public.html"
- (void) copyAsRTF
{
NSPasteboard *pasteboard = [NSPasteboard generalPasteboard];
// Get our RTF data
NSData * rtfData = [[self textStorage] RTFFromRange: [self selectedRange]
documentAttributes: nil];
// Get the HTML for our current data
NSData *htmlData = [[self htmlForRange: self.selectedRange] dataUsingEncoding: NSUTF8StringEncoding];
NSMutableArray * clipboardTypes = [NSMutableArray array];
if (nil != rtfData)
{
[clipboardTypes addObject: NSPasteboardTypeRTF];
} // End of we have rtf
if(nil != htmlData)
{
[clipboardTypes addObject: PasteBoardTypeHTML];
} // End of we have html
// Set our pasteboard types (types need to be declared before we call setData).
[pasteboard declareTypes: clipboardTypes.copy
owner: self];
if (rtfData)
{
[pasteboard setData: rtfData
forType: NSPasteboardTypeRTF];
} // End of we have rtf
if(htmlData)
{
[pasteboard setData: htmlData
forType: PasteBoardTypeHTML];
} // End of we have html
} // End of copyAsRTF
- (NSString *) htmlForRange: (NSRange) range
{
NSMutableString * htmlOutput = [NSMutableString stringWithString: #"<meta charset='utf-8'><pre>"];
[[self textStorage] enumerateAttributesInRange: range
options: 0
usingBlock:
^(NSDictionary * attributes, NSRange range, BOOL * stop)
{
NSString * actualCode = [[self textStorage].string substringWithRange: range];
actualCode = [self textToHtml: actualCode];
NSMutableString * currentHtml = [NSMutableString stringWithString: #"<span"];
NSColor * color = attributes[NSForegroundColorAttributeName];
NSFont * font = attributes[NSFontAttributeName];
NSMutableArray * fontStyles = [NSMutableArray array];
if(nil != color)
{
NSString * fontColorStyle =
[NSString stringWithFormat: #"color: %#;", [color hexadecimalValue]];
[fontStyles addObject: fontColorStyle];
} // End of we have a color
if(nil != font)
{
NSString * fontDetailsStyle =
[NSString stringWithFormat: #"font-family: %#;", font.familyName];
[fontStyles addObject: fontDetailsStyle];
} // End of we have a font
if(nil != fontStyles && fontStyles.count > 0)
{
[currentHtml appendFormat: #" style=\"%#\"", [fontStyles componentsJoinedByString: #" "]];
} // End of we have font styles
[currentHtml appendString: #">"];
[currentHtml appendString: actualCode];
[currentHtml appendString: #"</span>"];
// Add our section
[htmlOutput appendString: currentHtml];
}]; // End of attribute enumerations
// End of html output
[htmlOutput appendString: #"</pre></meta>"];
return htmlOutput.copy;
} // End of htmlForRange:
- (NSString*)textToHtml:(NSString*)htmlString
{
htmlString = [htmlString stringByReplacingOccurrencesOfString:#"&" withString:#"&"];
htmlString = [htmlString stringByReplacingOccurrencesOfString:#"<" withString:#"<"];
htmlString = [htmlString stringByReplacingOccurrencesOfString:#">" withString:#">"];
htmlString = [htmlString stringByReplacingOccurrencesOfString:#"""" withString:#"""];
htmlString = [htmlString stringByReplacingOccurrencesOfString:#"'" withString:#"'"];
htmlString = [htmlString stringByReplacingOccurrencesOfString:#"\n" withString:#"<br>"];
return htmlString;
} // End of textToHtml:

Image not displayed on UICollectionViewCell

I am trying to get images on contacts,here i used UICollectionViewCell but in the collection view i didn't get image for the contact,i get only name and number.Here my code is
- (IBAction)ContactDisplay:(id)sender {
_addressBookController = [[ABPeoplePickerNavigationController alloc] init];
[_addressBookController setPeoplePickerDelegate:self];
[self presentViewController:_addressBookController animated:YES completion:nil];
}
- (void)peoplePickerNavigationController:(ABPeoplePickerNavigationController*)peoplePicker didSelectPerson:(ABRecordRef)person
{
[self displayPerson:person];
}
- (void)displayPerson:(ABRecordRef)person
{
NSString* name = (__bridge_transfer NSString*)ABRecordCopyValue(person,
kABPersonFirstNameProperty);
NSLog(#"%#",name);
NSString* phone = nil;
ABMultiValueRef phoneNumbers = ABRecordCopyValue(person,
kABPersonPhoneProperty);
if (ABMultiValueGetCount(phoneNumbers) > 0) {
phone = (__bridge_transfer NSString*)
ABMultiValueCopyValueAtIndex(phoneNumbers, 0);
} else {
phone = #"[None]";
}
NSLog(#"%#",phone);
UIImage *img ;
if (person != nil && ABPersonHasImageData(person)) {
if ((&ABPersonCopyImageDataWithFormat) != nil ) {
img= [UIImage imageWithData:(__bridge NSData *)ABPersonCopyImageDataWithFormat(person, kABPersonImageFormatThumbnail)];
}
} else {
NSString *imageUrlString = #"http://www.google.co.in/intl/en_com/images/srpr/logo1w.png";
NSURL *url = [NSURL URLWithString:imageUrlString];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
img= [UIImage imageWithData:data];
}
NSString *string ;//
string =[NSString stringWithFormat:#"%#",img];
NSLog(#"%#",img);
self.name.text=name;
self.number.text=phone;
[self.nameArray addObject:name];
[self.imageArray addObject:string];
NSLog(#"%#",self.nameArray);
NSLog(#"%#",self.imageArray);
[self.collectionView reloadData];
[self.collectionView performBatchUpdates:^{
[self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
} completion:nil];
}
finally an image array i got like this
(
"add-button.png",
"<UIImage: 0x17e56c80>, {148, 148}"
)
On image array every image like display .PNG format it will display fine ,then how can modify it.
Can you please suggest me how can you solve this,thank you.
I don't fully agree with everything you're doing there but I think you're getting your data wrong. Try using this instead when you're fetching the ABPerson image data.
if (person != nil) {
CFDataRef imageData = ABPersonCopyImageData(person);
NSData *data = CFBridgingRelease(imageData);
if (data != nil && data.length > 10){ //arbitrary length to make sure our data object isnt' really empty
img = [UIImage imageWithData:data];
} else {
NSString *imageUrlString = #"http://www.google.co.in/intl/en_com/images/srpr/logo1w.png";
NSURL *url = [NSURL URLWithString:imageUrlString];
NSData *data = [[NSData alloc] initWithContentsOfURL:url];
img= [UIImage imageWithData:data];
}
Then don't store your images as Strings in your array. Store them either as NSData or UIImage, but NOT STRINGS.
so
[myArray addObject:img]; //not the string.
And when you fetch it later, make sure you treat is as an image and not as a string
on your storyboard, select the image and look at the properties panel.
there are "Installed" options at the bottom. check the topmost "Installed" box.
I think there might be issue with conversion of image to string
NSString *string ;//
string =[NSString stringWithFormat:#"%#",img];
Add image to image array without converting to string
[self.imageArray addObject:img];
I do it like this in my app. Assuming 'person' is an ABRecordRef.
NSMutableDictionary *contactInfoDict = [[NSMutableDictionary alloc]
initWithObjects:#[#"", #"", #"", #""]
forKeys:#[#"firstName", #"lastName", #"birthday", #"picture"]];
CFTypeRef generalCFObject;
// Firtname
generalCFObject = ABRecordCopyValue(person, kABPersonFirstNameProperty);
if (generalCFObject) {
[contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:#"firstName"];
CFRelease(generalCFObject);
}
// Lastname
generalCFObject = ABRecordCopyValue(person, kABPersonLastNameProperty);
if (generalCFObject) {
[contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:#"lastName"];
CFRelease(generalCFObject);
}
// Birthday
generalCFObject = ABRecordCopyValue(person, kABPersonBirthdayProperty);
if (generalCFObject) {
[contactInfoDict setObject:(__bridge NSString *)generalCFObject forKey:#"birthday"];
NSLog(#"Date : %#", [contactInfoDict objectForKey:#"birthday"]);
CFRelease(generalCFObject);
}
// User image
CFDataRef photo = ABPersonCopyImageData(person);
if (photo) {
CFRelease(photo);
UIImage *image = [UIImage imageWithData:(__bridge NSData*)photo];
[contactInfoDict setObject:image forKey:#"picture"];
}

-[__NSCFConstantString allKeys]: unrecognized selector sent to instance 0xf9ac8

My app when I run it on my phone I get this error:
I just tried to parse a json and trying to use images in two column of custom cell, but my images on scroll are mis-placed.
int index=indexPath.row*2;
int newindex=index+1;
NSDictionary *u = [[results objectAtIndex:index]mutableCopy ];
NSLog(#"NSDictionary *u = [results objectAtIndex:index] %#",u);
NSDictionary *u1 = [[results objectAtIndex:newindex]mutableCopy];
NSLog(#"NSDictionary *u1 = [results objectAtIndex:newindex] %#",u1);
But if i use both index and newindex same value it works.
:-
:-
Code :
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil suffix:(NSString *)_suffix{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
self.suffix = _suffix;
}
return self;
}
#pragma mark Table view methods
- (NSInteger)numberOfSectionsInTableView:(UITableView *)_tableView{
return 1;
}
//my new
- (NSInteger)tableView:(UITableView *)_tableView numberOfRowsInSection:(NSInteger)section{
int resultCount = [results count];
labelResultsCount.text = [NSString stringWithFormat:#"%d",resultCount];
return resultCount/2;
}
- (UITableViewCell *)tableView:(UITableView *)_tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath{
// NSString* CellIdentifier = [NSString stringWithFormat:#"ident_%d",indexPath.row];
static NSString *CellIdentifier = #"ResultCell";
ResultCell *cell = (ResultCell *)[_tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil){
NSArray *a = [[NSBundle mainBundle] loadNibNamed:#"ResultCell" owner:self options:nil];
cell = (ResultCell *)[a objectAtIndex:0];
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
}
int index=[(indexPath.row*2) copy];
int newindex=[(index+1) copy];
// save badge in dictionaory and get here and show in lable
NSDictionary *u = [[results objectAtIndex:index]mutableCopy ];
NSLog(#"NSDictionary *u = [results objectAtIndex:newindex] %#",u);
NSDictionary *u1 = [[results objectAtIndex:newindex]mutableCopy];
NSLog(#"NSDictionary *u1 = [results objectAtIndex:indexPath.row*2+1 newindex] %#",u1);
#try {
/* fullName */
NSString *nickName = [u objectForKey:#"nickName"];
cell.labelName.text = nickName;
NSString *nickName1 = [u1 objectForKey:#"nickName"];
cell.labelName1.text = nickName1;
/* chat notification*/
cell.imageViewNotification.hidden=0;
cell.imageViewNotification1.hidden=0;
NSString *badge = [u objectForKey:#"badge"];
NSString *badge1 = [u1 objectForKey:#"badge"];
if([badge intValue]>0)
{
cell.imageViewNotification.hidden=0;
cell.labelNotification.text = badge;
NSLog(#"inside > 0 %#",badge);
}
else if([badge intValue]<=0)
{
cell.imageViewNotification.hidden=1;
cell.labelNotification.text=#"";
NSLog(#"%#",badge);
}
if([badge1 intValue]>0)
{
cell.imageViewNotification1.hidden=0;
cell.labelNotification1.text = badge1;
NSLog(#"inside > 0 %#",badge1);
}
else if([badge1 intValue]<=0)
{
cell.imageViewNotification1.hidden=1;
cell.labelNotification1.text=#"";
NSLog(#"%#",badge1);
}
/*..................*/
/* distance */
id distance = [u objectForKey:#"distance"];
if([distance isKindOfClass:[NSString class]]){
cell.labelDistance.text = distance;
cell.imageViewDistance.hidden = 0;
}else{
cell.imageViewDistance.hidden = 1;
cell.labelDistance.text = #"";
}
id distance1 = [u1 objectForKey:#"distance"];
if([distance1 isKindOfClass:[NSString class]]){
cell.labelDistance1.text = distance1;
cell.imageViewDistance1.hidden = 0;
}else{
cell.imageViewDistance1.hidden = 1;
cell.labelDistance1.text = #"";
}
/* online */
NSNumber *online = [u objectForKey:#"online"];
cell.imageViewOnline.image = [online intValue] ? [UIImage imageNamed:#"circle_online.png"] : [UIImage imageNamed:#"circle_offline_red.png"];
NSNumber *online1 = [u1 objectForKey:#"online"];
cell.imageViewOnline1.image = [online1 intValue] ? [UIImage imageNamed:#"circle_online.png"] : [UIImage imageNamed:#"circle_offline_red.png"];
/* buttonProfile */
id d = [u objectForKey:#"thumbnails"];
id d1 = [u1 objectForKey:#"thumbnails"];
if([d isKindOfClass:[NSDictionary class]] ||[d1 isKindOfClass:[NSDictionary class]]){
if([[d allKeys] count]>0 ||[[d1 allKeys] count]>0){
NSString *imageSuffix = [d objectForKey:#"icon"];
NSString *imageSuffix1 = [d1 objectForKey:#"icon"];
NSLog(#"[d allKeys] count]%#", d);
NSLog(#"[d1 allKeys] count]%#", d1);
UIImage *image = [[SharingCenter sharedManager] imageFromCache:imageSuffix];
UIImage *image1 = [[SharingCenter sharedManager] imageFromCache:imageSuffix1];
if(image||image1)
{
[cell.buttonUserProfile setBackgroundImage:image forState:UIControlStateNormal];
[cell.buttonUserProfile1 setBackgroundImage:image1 forState:UIControlStateNormal];
}
else{
NSString *gender = [u objectForKey:#"gender"];
NSString *gender1 = [u1 objectForKey:#"gender"];
UIImage *profileDefualtImage = [gender isEqualToString:#"M"] ? [UIImage imageNamed:#"no_photo_male.png"] : [UIImage imageNamed:#"no_photo_female.png"];
UIImage *profileDefualtImage1 = [gender1 isEqualToString:#"M"] ? [UIImage imageNamed:#"no_photo_male.png"] : [UIImage imageNamed:#"no_photo_female.png"];
[cell.buttonUserProfile setBackgroundImage:profileDefualtImage forState:UIControlStateNormal];
[cell.buttonUserProfile1 setBackgroundImage:profileDefualtImage1 forState:UIControlStateNormal];
/* downlowd Image */
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#",WebServicePrefix,imageSuffix]];
__block
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
request.delegate = self;
[request setPostValue:[NSString stringWithFormat:#"%f",[[SharingCenter sharedManager] currentCoordinate].latitude] forKey:#"lat"];
[request setPostValue:[NSString stringWithFormat:#"%f",[[SharingCenter sharedManager] currentCoordinate].longitude] forKey:#"lon"];
// [[[SharingCenter sharedManager] imagesCache] removeAllObjects];
[request setCompletionBlock:^{
NSData *imageData = [request responseData];
if(imageData){
UIImage *image = [UIImage imageWithData:imageData];
if(image){
[[[SharingCenter sharedManager] imagesCache] setObject:image forKey:imageSuffix];
if([[self.tableView indexPathsForVisibleRows] containsObject:indexPath]){
ResultCell *cell = (ResultCell *)[self.tableView cellForRowAtIndexPath:indexPath];
[cell.buttonUserProfile setBackgroundImage:image forState:UIControlStateNormal];
}
}
}
}];
[request setFailedBlock:^{
NSError *error = request.error;
NSLog(#"%#",error);
}];
/* downlowd Image */
NSURL *url1 = [NSURL URLWithString:[NSString stringWithFormat:#"%#%#",WebServicePrefix,imageSuffix1]];
__block
ASIFormDataRequest *request1 = [ASIFormDataRequest requestWithURL:url1];
request1.delegate = self;
[request1 setPostValue:[NSString stringWithFormat:#"%f",[[SharingCenter sharedManager] currentCoordinate].latitude] forKey:#"lat"];
[request1 setPostValue:[NSString stringWithFormat:#"%f",[[SharingCenter sharedManager] currentCoordinate].longitude] forKey:#"lon"];
// [[[SharingCenter sharedManager] imagesCache] removeAllObjects];
[request1 setCompletionBlock:^{
NSData *imageData1 = [request1 responseData];
if(imageData1){
UIImage *image1 = [UIImage imageWithData:imageData1];
if(image1){
[[[SharingCenter sharedManager] imagesCache] setObject:image1 forKey:imageSuffix1];
if([[self.tableView indexPathsForVisibleRows] containsObject:indexPath]){
ResultCell *cell = (ResultCell *)[self.tableView cellForRowAtIndexPath:indexPath];
[cell.buttonUserProfile1 setBackgroundImage:image1 forState:UIControlStateNormal];
}
}
}
}];
[request1 setFailedBlock:^{
NSError *error = request1.error;
NSLog(#"%#",error);
}];
[[self networkQueue] addOperation:request];
[[self networkQueue] addOperation:request1];
}
}
}
else{
NSString *gender = [u objectForKey:#"gender"];
NSString *gender1 = [u1 objectForKey:#"gender"];
UIImage *profileDefualtImage = [gender isEqualToString:#"M"] ? [UIImage imageNamed:#"no_photo_male.png"] : [UIImage imageNamed:#"no_photo_female.png"];
[cell.buttonUserProfile setBackgroundImage:profileDefualtImage forState:UIControlStateNormal];
UIImage *profileDefualtImage1 = [gender1 isEqualToString:#"M"] ? [UIImage imageNamed:#"no_photo_male.png"] : [UIImage imageNamed:#"no_photo_female.png"];
[cell.buttonUserProfile1 setBackgroundImage:profileDefualtImage1 forState:UIControlStateNormal];
}
/* pickStatus */
NSNumber *pickStatus = [u objectForKey:#"pick_status"];
NSNumber *pickStatus1 = [u1 objectForKey:#"pick_status"];
switch ([pickStatus intValue]) {
case 0:
cell.imageViewBorder.image = [UIImage imageNamed:#"border_yellow_transperent.png"];
cell.buttonUserPick.enabled = 1;
[cell.buttonUserPick setBackgroundImage:[UIImage imageNamed:#"button_circle_pick.png"] forState:UIControlStateNormal];
break;
case 1:
cell.imageViewBorder.image = [UIImage imageNamed:#"border_red_transperent.png"];
cell.buttonUserPick.enabled = 0;
[cell.buttonUserPick setBackgroundImage:[UIImage imageNamed:#"button_circle_wait.png"] forState:UIControlStateDisabled];
break;
case 2:
cell.imageViewBorder.image = [UIImage imageNamed:#"border_red_transperent.png"];
cell.buttonUserPick.enabled = 1;
[cell.buttonUserPick setBackgroundImage:[UIImage imageNamed:#"button_circle_pick.png"] forState:UIControlStateNormal];
break;
case 3:
cell.imageViewBorder.image = [UIImage imageNamed:#"border_red_transperent.png"];
cell.buttonUserPick.enabled = 0;
[cell.buttonUserPick setBackgroundImage:[UIImage imageNamed:#"button_circle_date.png"] forState:UIControlStateDisabled];
break;
default:
break;
}
switch ([pickStatus1 intValue]) {
case 0:
cell.imageViewBorder1.image = [UIImage imageNamed:#"border_yellow_transperent.png"];
cell.buttonUserPick1.enabled = 1;
[cell.buttonUserPick1 setBackgroundImage:[UIImage imageNamed:#"button_circle_pick.png"] forState:UIControlStateNormal];
break;
case 1:
cell.imageViewBorder1.image = [UIImage imageNamed:#"border_red_transperent.png"];
cell.buttonUserPick1.enabled = 0;
[cell.buttonUserPick1 setBackgroundImage:[UIImage imageNamed:#"button_circle_wait.png"] forState:UIControlStateDisabled];
break;
case 2:
cell.imageViewBorder1.image = [UIImage imageNamed:#"border_red_transperent.png"];
cell.buttonUserPick1.enabled = 1;
[cell.buttonUserPick1 setBackgroundImage:[UIImage imageNamed:#"button_circle_pick.png"] forState:UIControlStateNormal];
break;
case 3:
cell.imageViewBorder1.image = [UIImage imageNamed:#"border_red_transperent.png"];
cell.buttonUserPick1.enabled = 0;
[cell.buttonUserPick1 setBackgroundImage:[UIImage imageNamed:#"button_circle_date.png"] forState:UIControlStateDisabled];
break;
default:
break;
}
}
#catch (NSException * e) {
NSLog(#"%#",e);
}
#finally {
return cell;
}
}
Educated guess:
This line causes your problem:
if([d isKindOfClass:[NSDictionary class]] ||[d1 isKindOfClass:[NSDictionary class]]){
if([[d allKeys] count]>0 ||[[d1 allKeys] count]>0){
There are 4 different possibilities how the first if will come out:
d and d1 are both NSStrings. Line 2 will not be called
d is NSDictionary, d1 is a NSString. Line 2 will be called
d is NSString, d1 is a NSDictionary. Line 2 will be called
d and d1 are both NSDictionaries. Line 2 will be called.
First case is no problem at all. Last case neither. In case 2 and 3 allKeys will be called on a object that is not a NSDictionary.
You should probably replace it with an "if" that needs both tests to be true.
if([d isKindOfClass:[NSDictionary class]] && [d1 isKindOfClass:[NSDictionary class]]){
^^
Another option would be to check individually.
if([d isKindOfClass:[NSDictionary class]]) {
x = [d allKeys];
}
if([d1 isKindOfClass:[NSDictionary class]]) {
x = [d1 allKeys];
}
You are probably doing something to those NSDictionary objects somewhere, reading their allKeys. But my guess is that the objects you try to fetch from that results array aren't NSDictionary objects but NSString objects.
Try logging their class property to see what you are dealing with (you can also find this out by just looking at the JSON of course).
NSDictionary *u = [[results objectAtIndex:index]mutableCopy ];
NSLog(#"u Class: %#", [u class]);
Also, why are you making a mutableCopy of the object right to a non-mutable NSDictionary object.
Using the following should do the trick normally:
NSDictionary* u = [results objectAtIndex:index];
NSLog(#"u Class: %#", [u class]);
That's a lot of code to look through, but I think this could be the problem:
if([d isKindOfClass:[NSDictionary class]] ||[d1 isKindOfClass:[NSDictionary class]]){
if([[d allKeys] count]>0 ||[[d1 allKeys] count]>0){
This if statement will pass if either d or d1 is a dictionary. If one isn't, it would cause that error you see on the second line. Log the class of d and d1 to see if they're both dictionaries.

How Can I Save This Array of Images?

I'm very new to programming, and I jumped right into a project (I know thats not the smartest thing to do, but I'm learning as I go). The app that I'm writing has 10 UIImageViews that display a picture from the users camera roll. The code I'm using needs each of the UIImageViews to have tags. I'm currently using NSData to save the array images, and it works great, but I can't use this method anymore because NSData doesn't support the use of tags. I also can't use NSUserDefaults, because I can't save images to a plist. Here is how I'm attempting to do this (using the NSData method, which works but I have to edit this so that my tags work.)
This is my current code:
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingImage:(UIImage *)img editingInfo:(NSDictionary *)editInfo {
if (imageView.image == nil) {
imageView.image = img;
[self.array addObject:imageView.image];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
if (imageView2.image == nil) {
imageView2.image = img;
NSLog(#"The image is a %#", imageView);
[self.array addObject:imageView2.image];
[picker dismissModalViewControllerAnimated:YES];
[self.popover dismissPopoverAnimated:YES];
return;
}
...
- (void)applicationDidEnterBackground:(UIApplication*)application {
NSLog(#"Image on didenterbackground: %#", imageView);
[self.array addObject:imageView.image];
[self.array addObject:imageView2.image];
[self.user setObject:self.array forKey:#"images"];
[user synchronize];
}
- (void)viewDidLoad
{
self.user = [NSUserDefaults standardUserDefaults];
NSLog(#"It is %#", self.user);
self.array = [[self.user objectForKey:#"images"]mutableCopy];
imageView.image = [[self.array objectAtIndex:0] copy];
imageView2.image = [[self.array objectAtIndex:1] copy];
UIApplication *app = [UIApplication sharedApplication];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:app];
[super viewDidLoad];
}
Any help or suggestions on how to edit this code so that I can save the images, while using tags is much appreciated, thanks!
EDIT: Here is my updated code:
-(IBAction)saveButtonPressed:(id)sender {
NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES) objectAtIndex:0];
for (UIImageView *imageView in self.array) {
NSInteger tag = self.imageView.tag;
UIImage *image = self.imageView.image;
NSString *imageName = [NSString stringWithFormat:#"Image%i.png",tag];
NSString *imagePath = [docsDir stringByAppendingPathComponent:imageName];
[UIImagePNGRepresentation(image) writeToFile:imagePath atomically:YES];
}
NSLog(#"Saved Button Pressed");
}
- (void)applicationDidEnterBackground:(UIApplication*)application {
}
-(void)viewDidLoad {
NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask,YES) objectAtIndex:0];
NSArray *docFiles = [[NSFileManager defaultManager]contentsOfDirectoryAtPath:docsDir error:NULL];
for (NSString *fileName in docFiles) {
if ([fileName hasSuffix:#".png"]) {
NSString *fullPath = [docsDir stringByAppendingPathComponent:fileName];
UIImage *loadedImage = [UIImage imageWithContentsOfFile:fullPath];
if (!imageView.image) {
imageView.image = loadedImage;
} else {
imageView2.image = loadedImage;
}
}
}
}
You need to use "Fast Enumeration" to parse the array's objects, and write each object to disk sequentially. First, you're going to need to add the UIImageView objects to the array instead of the UIImage property of the UIImageView, so you can recover the tag. So instead of writing
[self.array addObject:imageView.image];
It will be
[self.array addObject:imageView];
Try to follow along with my code. I inserted comments on each line to help.
-(void)applicationDidEnterBackground:(UIApplication *)application {
//Obtain the documents directory
NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainmask,YES) objectAtIndex:0];
//begin fast enumeration
//this is special to ObjC: it will iterate over any array one object at a time
//it's easier than using for (i=0;i<array.count;i++)
for (UIImageView *imageView in self.array) {
//get the imageView's tag to append to the filename
NSInteger tag = imageView.tag;
//get the image from the imageView;
UIImage *image = imageView.image;
//create a filename, in this case "ImageTAGNUM.png"
NSString *imageName = [NSString stringWithFormat:#"Image%i.png",tag];
//concatenate the docsDirectory and the filename
NSString *imagePath = [docsDir stringByAppendingPathComponent:imageName];
[UIImagePNGRepresentation(image) writeToFile:imagePath atomically:YES];
}
}
To load the images from disk, you'll have to look at your viewDidLoad method
-(void)viewDidLoad {
//get the contents of the docs directory
NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainmask,YES) objectAtIndex:0];
//Get the list of files from the file manager
NSArray *docFiles = [[NSFileManager defaultManager]contentsOfDirectoryAtPath:docsDir error:NULL]);
//use fast enumeration to iterate the list of files searching for .png extensions and load those
for (NSString *fileName in docFiles) {
//check to see if the file is a .png file
if ([fileName hasSuffix:#".png"]) {
NSString *fullPath = [docsDir stringByAppendingPathComponent:fileName];
UIImage *loadedImage = [UIImage imageWithContentsOfFile:fullPath];
//you'll have to sort out how to put these images in their proper place
if (!imageView1.image) {
imageView1.image = loadedImage;
} else {
imageView2.image = loadedImage;
}
}
}
}
Hope this helps
One thing you need to be aware of is that when an app enters the background it has about 5 seconds to clean up its act before it's suspended. The UIPNGRepresentation() function takes a significant amount of time and is not instantaneous. You should be aware of this. It would probably be better to write some of this code in other places and do it earlier than at app backgrounding. FWIW
You can use the [NSbundle Mainbundel] to store that images.
To get path
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
First, there's still a problem in your for loop.
for (UIImageView *imageView in self.array) {
NSInteger tag = self.imageView.tag;
UIImage *image = self.imageView.image;
// ...
}
Before you make any other changes, you must understand why. imageView is your for loop control variable, which changes on each iteration through the loop. self.imageView is a different thing. It is the first of the 10 imageViews attached to your viewController. Every time this loop cycles, it looks at the first imageView, and only the first.
As for why saving doesn't work, it's probably because the arrays elsewhere aren't working. Add some logging to make sure there's something in the array, and that it has as many elements as you expect.
-(IBAction)saveButtonPressed:(id)sender {
NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask,YES) objectAtIndex:0];
// Log to make sure the views expected have previously been stored.
// If the array is empty, or shorter than expected, the problem is elsewhere.
NSLog(#"Image view array before saving = %#", self.array);
for (UIImageView *imageViewToSave in self.array) {
NSInteger tag = imageViewToSave.tag;
UIImage *image = imageViewToSave.image;
NSString *imageName = [NSString stringWithFormat:#"Image%i.png",tag];
NSString *imagePath = [docsDir stringByAppendingPathComponent:imageName];
// Log the image and path being saved. If either of these are nil, nothing will be written.
NSLog(#"Saving %# to %#", image, imagePath);
[UIImagePNGRepresentation(image) writeToFile:imagePath atomically:NO];
}
NSLog(#"Save Button Pressed");
}