Once more I come to the Internet, hat in hand. :)
I'm attempting to use a class method to return a populated array containing other arrays as elements:
.h:
#interface NetworkData : NSObject {
}
+(NSString*) getCachePath:(NSString*) filename;
+(void) writeToFile:(NSString*)text withFilename:(NSString*) filePath;
+(NSString*) readFromFile:(NSString*) filePath;
+(void) loadParkData:(NSString*) filename;
+(NSArray*) generateColumnArray:(int) column type:(NSString*) type filename:(NSString*) filename;
#end
.m:
#import "NetworkData.h"
#import "JSON.h"
#import "Utility.h"
#implementation NetworkData
+(NSString*) getCachePath:(NSString*) filename {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *cachePath = [NSString stringWithFormat:#"%#/%#", [paths objectAtIndex:0], filename];
[paths release];
return cachePath;
}
+(void) writeToFile:(NSString*)text withFilename:(NSString*) filename {
NSMutableArray *array = [[NSArray alloc] init];
[array addObject:text];
[array writeToFile:filename atomically:YES];
[array release];
}
+(NSString*) readFromFile:(NSString*) filename {
NSFileManager* filemgr = [[NSFileManager alloc] init];
NSData* buffer = [filemgr contentsAtPath:filename];
NSString* data = [[NSString alloc] initWithData:buffer encoding:NSUTF8StringEncoding];
[buffer release];
[filemgr release];
return data;
}
+(void) loadParkData:(NSString*) filename {
NSString *filePath = [self getCachePath:filename];
NSURL *url = [NSURL URLWithString:#"http://my.appserver.com"];
NSData *urlData = [NSData dataWithContentsOfURL:url];
[urlData writeToFile:filePath atomically:YES];
}
+(NSArray*) generateColumnArray:(int) column type:(NSString*) type filename:(NSString*) filename {
// NSLog(#"generateColumnArray called: %u %# %#", column, type, filename);
// productArray = [[NSMutableArray alloc] init];
// NSString *filePath = [self getCachePath:filename];
// NSString *fileContent = [self readFromFile:filePath];
// NSString *jsonString = [[NSString alloc] initWithString:fileContent];
// NSDictionary *results = [jsonString JSONValue];
// NSArray *eventsArray = [results objectForKey:type];
// NSInteger* eventsArrayCount = [eventsArray count];
// NSInteger* a;
// for (a = 0; a < eventsArrayCount; a++) {
// NSArray *eventsColSrc = [eventsArray objectAtIndex:a];
// NSArray *blockArray = [eventsColSrc objectAtIndex:column];
// [productArray addObject:blockArray];
// [blockArray release];
// }
// [eventsArray release];
// [results release];
// [jsonString release];
// [fileContent release];
// [filePath release];
// [a release];
// [eventsArrayCount release];
// return productArray;
}
-(void)dealloc {
[super dealloc];
}
#end
.. and the call:
NSArray* dataColumn = [NetworkData generateColumnArray:0 type:#"eventtype_a" filename:#"data.json"];
The code within the method works (isn't pretty, I know - noob at work). It's essentially moot because just calling it (with no active code, as shown) causes the app to quit before the splash screen reveals anything else.
I'm betting this is a headslapper - many thanks for any knowledge you can drop.
If your app crashes, there's very likely a message in the console that tells you why. It's always helpful to include that message when seeking help.
One obvious problem is that your +generateColumnArray... method is supposed to return a pointer to an NSArray, but with all the code in the method commented out, it's not returning anything, and who-knows-what is being assigned to dataColumn. Try just adding a return nil; to the end of the method and see if that fixes the crash. Again, though, look at the error message to see specifically why the code is crashing, and that will lead you to the solution.
Well, you're not returning a valid value from your commented out code. What do you use 'dataColumn' for next? Running under the debugger should point you right to the issue, no?
Related
I can't find anything online about threading loading an image from a device and scrolling smoothly through a tableview. There is one on ray wen about this, but it doesn't really help me for my situation.
Does anybody have any advice or code which would help to allow a tableview to scroll smoothly and load images from the device's temporary directory?
i did exactly as mentioned at tutorial, but with modification for nsoperation subclass
this is methods for fetch
-(void) updateData
{
[self.pendingOperations.downloadQueue addOperationWithBlock:^{
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSArray *filePathes = [self recursiveRecordsForResourcesOfType:#[#"png", #"jpeg", #"jpg",#"pdf"] inDirectory:documentsDirectory];
#synchronized (self) {
self.documents = filePathes;
NSLog(#"documents count %#", #([self.documents count]));
}
dispatch_async(dispatch_get_main_queue(), ^(void){
//Run UI Updates
[self.delegate modelDidUpdate:self];
});
}];
}
- (NSArray *)recursiveRecordsForResourcesOfType:(NSArray *)types inDirectory:(NSString *)directoryPath{
NSMutableArray *filePaths = [[NSMutableArray alloc] init];
NSMutableDictionary *typesDic = [NSMutableDictionary dictionary];
for (NSString *type in types)
[typesDic setObject:type forKey:type];
// Enumerators are recursive
NSDirectoryEnumerator *enumerator = [[NSFileManager defaultManager] enumeratorAtPath:directoryPath];
NSString *filePath;
while ((filePath = [enumerator nextObject]) != nil){
// If we have the right type of file, add it to the list
// Make sure to prepend the directory path
if([typesDic objectForKey:[filePath pathExtension]]){
//[filePaths addObject:[directoryPath stringByAppendingPathComponent:filePath]];
CURFileRecord *record = [CURFileRecord new];
record.filePath =[directoryPath stringByAppendingPathComponent:filePath];
record.fileName = filePath;
[filePaths addObject:record];
}
}
return filePaths;
}
this is .m for subclass
- (void)main {
// 4
#autoreleasepool {
if (self.isCancelled)
return;
NSData *fileData = [[NSFileManager defaultManager] contentsAtPath:self.fileRecord.filePath];
// self.fileRecord.fileData = fileData;
if (self.isCancelled) {
fileData = nil;
return;
}
if (fileData) {
UIImage *newImage;
if ([[self.fileRecord.filePath pathExtension] isEqualToString:#"pdf"])
{
CGPDFDocumentRef doc = [CURDocumentViewerUtilities MyGetPDFDocumentRef:fileData];
newImage = [CURDocumentViewerUtilities buildThumbnailImage:doc withSize:CGSizeMake(64, 96)];
}
else
{
newImage = [CURDocumentViewerUtilities makePreviewImageFromData:fileData];
}
self.fileRecord.previewImage = newImage;
}
else {
self.fileRecord.failed = YES;
}
fileData = nil;
if (self.isCancelled)
return;
// 5
[(NSObject *)self.delegate performSelectorOnMainThread:#selector(imageDownloaderDidFinish:) withObject:self waitUntilDone:NO];
}
}
With update func i've fetched pathes to proccess, and nsoperation subclass loads images. Works fine with 2000 images in fullhd - smoothly and without any lugs
I am filling a TableView from a text file. I want to enable the user to download an updated text file and replace the existing content of the TableView with the content of the downloaded file. I am able to download the file and replace the original file. If I close the application and open it again, it loads the updated file.
But the TableView doesn't change while the app is running. When I execute the method to load data from the file into the TableView, I can see, using NSLog, that the method is getting the original data from the file.
What am I doing incorrectly? How can I get the method to see the updated text file instead of the original text file?
Thanks.
#interface
#property (strong, nonatomic) NSArray *tableViewData;
#end
#implementation
/*
When user presses button, IBAction method
- downloads text file
- saves the downloaded file, replacing the original text file
- loads the text file into the TableView data (this is what doesn't work)
- sends a reload message to the TableView
*/
- (IBAction)buttonUpdateTextFile:(UIBarButtonItem *)sender
{
NSString *contentsOfTextFile = [self downloadTextFileFromURL:#"http://www.apple.com/index.html"];
[self saveContentsOfTextFile:contentsOfTextFile toFile:#"tableViewData.txt"];
[self loadDataFromFileWithFileName:#"tableViewData" fileExtension:#"txt"];
[self.tableView reloadData];
}
- (NSString *)downloadTextFileFromURL:(NSString *)textFileURLstring
{
NSURL *textFileURL = [NSURL URLWithString:textFileURLstring];
NSError *error = nil;
NSString *contentsOfTextFile = [NSString stringWithContentsOfURL:textFileURL encoding:NSUTF8StringEncoding error:&error];
return contentsOfTextFile;
}
- (void)saveContentsOfTextFile:(NSString *)contentsOfTextFile toFile:(NSString *)fileName
{
NSString *pathName = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *fileNameWithPath = [pathName stringByAppendingPathComponent:fileName];
if (![[NSFileManager defaultManager] fileExistsAtPath:fileNameWithPath]) {
[[NSFileManager defaultManager] createFileAtPath:fileNameWithPath contents:nil attributes:nil];
[[contentsOfTextFile dataUsingEncoding:NSUTF8StringEncoding] writeToFile:fileNameWithPath atomically:NO];
}
- (void)loadDataFromFileWithFileName:(NSString *)fileName fileExtension:(NSString *)fileExtension
{
NSString *path = [[NSBundle mainBundle] pathForResource:fileName
ofType:fileExtension];
NSString *content = [NSString stringWithContentsOfFile:path
encoding:NSUTF8StringEncoding
error:NULL];
NSString *remainingText = [content mutableCopy];
NSMutableArray *data = [[NSMutableArray alloc] init];
NSRange *substringRange;
while (![remainingText isEqualToString:#""]) {
substringRange = [remainingText rangeOfString:#"/n"];
if (substringRange.location == NSNotFound)
{
currentLine = remainingText;
remainingText = #"";
} else {
substringRange.length = substringRange.location;
substringRange.location = 0;
currentLine = [[remainingText substringWithRange:substringRange] mutableCopy];
// - strip line from remainingText
substringRange.location = substringRange.length + 1;
substringRange.length = remainingText.length - substringRange.length - 1;
remainingText = [[remainingText substringWithRange:substringRange] mutableCopy];
}
[data addObject:currentLine];
}
self.tableViewData = [data copy];
}
I think
self.tableViewData = [data copy];
may be the problem.
I would make data a "private" property of the class. Only init once and then manually add and remove objects to it. Don't use copy.
i have this object.
#interface SeccionItem : NSObject <NSCoding>
{
NSString * title;
NSString * texto;
NSArray * images;
}
#property (nonatomic,strong) NSString * title;
#property (nonatomic,strong) NSString * texto;
#property (nonatomic,strong) NSArray * images;
#end
With this implementation
#implementation SeccionItem
#synthesize title,texto,images;
- (void) encodeWithCoder:(NSCoder *)encoder {
[encoder encodeObject:title forKey:#"title"];
[encoder encodeObject:texto forKey:#"texto"];
[encoder encodeObject:images forKey:#"images"];
}
- (id)initWithCoder:(NSCoder *)decoder {
title = [decoder decodeObjectForKey:#"title"];
texto = [decoder decodeObjectForKey:#"texto"];
images = [decoder decodeObjectForKey:#"images"];
return self;
}
#end
I want to save an array filled with this objects to a file on disk.
Im doing this:
to write
[NSKeyedArchiver archiveRootObject:arr toFile:file];
to read
NSArray *entries = [NSKeyedUnarchiver unarchiveObjectWithFile:name];
return entries;
But the readed array is always empty, i dont know why, i have some questions.
What format should i use for file path? on toFile:?
The NSArray on the object is filled with NSData objects, so i can encode them?
Im really lost on this.
Take a look at the documentation of NSKeyedArchiver, especially the archiveWithRootObject:toFile: method.
The path is basically where the file should be stored including the file name. For example you can store your array in your app Documents folder with file name called Storage. The code snippet below is quite common:
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *docDir = [paths objectAtIndex: 0];
NSString* docFile = [docDir stringByAppendingPathComponent: #"Storage"];
The method NSSearchPathForDirectoriesInDomains is used instead of absolute path because Apple can be changing the Documents folder path as they want it.
You can use the docFile string above to be supplied to the toFile parameter of the archiveWithRootObject:toFile: method.
Use the following method to save data
-(NSString*)saveFilePath {
NSArray *pathArray = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *pathString = [[pathArray objectAtIndex:0] stringByAppendingPathComponent:#"data"];
//NSString *pathString = [[NSBundle mainBundle]pathForResource:#"Profile" ofType:#"plist"];
return pathString;
}
-(void)saveProfile {
SeccionItem *data = [[SeccionItem alloc]init]
data. title = #"title";
data. texto = #"fdgdf";
data.images = [NSArray arrayWithObjects:#"dfds", nil];
NSMutableData *pData = [[NSMutableData alloc]init];
NSString *path = [self saveFilePath];
NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc]initForWritingWithMutableData:pData];
[data encodeWithCoder:archiver];
[archiver finishEncoding];
[pData writeToFile:path atomically:YES];
}
Use the following method to load data
-(void)loadData {
NSString* path = [self saveFilePath];
//NSLog(path);
NSMutableData *pData = [[NSMutableData alloc]initWithContentsOfFile:path];
NSKeyedUnarchiver *unArchiver = [[NSKeyedUnarchiver alloc]initForReadingWithData:pData];
data = [[SeccionItem alloc]initWithCoder:unArchiver];
//NSLog(#"%#",data.firstName);
[unArchiver finishDecoding];
}
For those who are seeking the solution in swift, I was able to write and read dictionary to file system as follows :
Write:
let data = NSKeyedArchiver.archivedData(withRootObject: dictionary)
do {
try data.write(to: destinationPath)
} catch let error {
print("\(error.localizedDescription)")
}
Read:
do
{
let data = try Data.init(contentsOf: path)
// path e.g. file:///private/var/ .... /Documents/folder/filename
if let dict = NSKeyedUnarchiver.unarchiveObject(with: data){
return dict
}
}
catch let error
{
print("\(error.localizedDescription)")
}
I'm using Hpple to parse HTML and it seems that it doesn't recognize it is actually XML, which it should (XCode debugger shows this variable isXML = (BOOL) NO and it doesn't collect any data). How do I fix this?
This is my code (they're may be other bugs as well). the parse method/function is called first with [ListParser parse:#"http://www.fanfiction.net/book/Harry-Potter/" at:#"//div[#=\"class\"]"];:
#interface ListParser () //private
+ (NSArray*) getNodeListAt: (NSURL*) page inside: (NSString*) page;
+ (NSDictionary*) getNodeData: (TFHppleElement*) node;
+ (void) addMiniListData: (NSString*) list to: (NSMutableDictionary*) dict;
#end
#implementation ListParser
+ (NSArray*) getNodeListAt: (NSURL*) page inside: (NSString*) path { // "//div[#class"z-list"]"
NSData *data = [NSData dataWithContentsOfURL: page];
TFHpple *listparser = [TFHpple hppleWithHTMLData:data]; //WHERE CODE SEEMS TO STOP TO WORK
NSArray *done = [listparser searchWithXPathQuery: path];
return done;
}
+ (void) addMiniListData: (NSString*) list to: (NSMutableDictionary*) dict{
NSArray *parts = [list componentsSeparatedByString:#" - "];
for(NSString* p in parts){
NSArray* two = [p componentsSeparatedByString:#": "];
[dict setObject:[two objectAtIndex:1] forKey:[two objectAtIndex:0]];
}
}
+ (NSDictionary*) getNodeData: (TFHppleElement*) node{
NSMutableDictionary* data = [NSMutableDictionary dictionary];
[data setObject:[[[node firstChild] firstChild] objectForKey:#"href"] forKey:#"Image"];
[data setObject:[[node firstChild] text] forKey:#"Title"];
[data setObject:[[[[node firstChild] children] objectAtIndex:2] text] forKey:#"By"];
[data setObject:[[[[node firstChild] childrenWithClassName:#"z-indent"] objectAtIndex:0] text] forKey:#"Summery"];
[self addMiniListData:[[[[[[node firstChild] childrenWithClassName:#"z-indent"] objectAtIndex:0] childrenWithClassName:#"z-padtop2"] objectAtIndex:0] text] to: data];
return data;
}
+(NSArray*) parse: (NSString*) address at: (NSString*) path{
NSURL *url = [[NSURL alloc] initWithString:address];
NSArray* list = [self getNodeListAt:url inside:path];
NSMutableArray *data = [[NSMutableArray alloc] init];
for (TFHppleElement* e in list) {
[data addObject:[self getNodeData:e]];
}
return [[NSArray alloc] initWithArray: data];
}
#end
Here's a link to the tutorials I was following: http://www.raywenderlich.com/14172/how-to-parse-html-on-ios
If you need to parse XML with a TFHpple, you should tell it that you're doing so. You're calling +hppleWithHTMLData:. If you read the implementation of this method, you will see that it sets isXML to NO. Instead, use the hppleWithXMLData: method.
I am trying to load a plist into a UITableView. I am new to working with pLists and tableViews, but I know i need to use something along these lines. My problem is though that where "filePath" is, i don't actually know how to put in my pList?
list = [NSArray arrayWithContentsOfFile:filePath];
Any other suggestions with code how to to do this other than getting the file path would be greatly appreciated. Such as do i need to put anything in my .h file? Thanks.
Assuming you've already added a .plist to your project, I've created a class you can add to your project that will get and save information to a given .plist. It's a functioning singleton, so you can call it from anywhere.
First, create a new NSObject file called "GetAndSaveData", then post the following code into .h:
#interface GetAndSaveData : NSObject{
NSMutableDictionary *allData;
NSString *path;
}
+(GetAndSaveData *)sharedGetAndSave;
-(NSMutableArray *)arrayForKey:(NSString *)dataList;
-(void)setData:(NSMutableArray *)array ForKey:(NSString *)dataList;
#end
and the following code into .m:
static GetAndSaveData *sharedGetAndSave;
#implementation GetAndSaveData
-(id)init{
self = [super init];
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); //1
NSString *documentsDirectory = [paths objectAtIndex:0];
path = [documentsDirectory stringByAppendingPathComponent:#"data.plist"];
if (![fileManager fileExistsAtPath: path])
{
NSString *bundle = [[NSBundle mainBundle] pathForResource:#"data" ofType:#"plist"];
[fileManager copyItemAtPath:bundle toPath: path error:&error];
}
allData = [[NSMutableDictionary alloc] initWithContentsOfFile: path];
return self;
}
-(NSMutableArray *)arrayForKey:(NSString *)dataList{
NSMutableArray *array = [allData objectForKey:dataList];
return array;
}
-(void)setData:(NSMutableArray *)array ForKey:(NSString *)dataList{
[allData setObject:array forKey:dataList];
[allData writeToFile:path atomically:YES];
if(![allData writeToFile:path atomically:YES])
{
NSLog(#".plist writing was unsuccessful");
}
}
+(GetAndSaveData *)sharedGetAndSave{
if (!sharedGetAndSave) {
sharedGetAndSave = [[GetAndSaveData alloc] init];
}
return sharedGetAndSave;
}
+(id)allocWithZone:(NSZone *)zone{
if (!sharedGetAndSave) {
sharedGetAndSave = [super allocWithZone:zone];
return sharedGetAndSave;
} else {
return nil;
}
}
-(id)copyWithZone:(NSZone *)zone{
return self;
}
#end
You can change the functions up to get and save different types of data. You can use it in view controllers by importing the .h file, and doing the following:
myMutableArray = [[GetAndSaveData sharedGetAndSave]arrayForKey:myKey];