Is this the right way to create / destroy string in loop? - objective-c

Just curious if this is the way to do this, just want to make sure its not leaking, although I would think I am only modifying the string contents.
NSMutableString *newPath = [[NSMutableString alloc] init];
for(fileName in [manager enumeratorAtPath:rootPath]){
if ([[fileName pathExtension] isEqual:#"exr"]) {
[fileArray addObject:fileName];
// THIS BIT
[newPath setString:rootPath];
[newPath appendString:#"/"];
[newPath appendString:fileName];
// HERE
attrDir = [manager attributesOfItemAtPath:newPath error:&myError];
fileSize = [attrDir objectForKey: #"NSFileSize"];
NSLog(#"File: /%# Size: %#", fileName, fileSize);
}
}
[newPath release];
gary

This looks fine leak-wise. If you're running Xcode 3.2 you can Build->Build & Analyzer to get Clang to check this sort of thing.
Remember you only have to release things you alloc, new, copy or retain.
Consider using stringByAppendingPathComponent, rather than hardcoding the #"/" path separator. NSString has a number of methods like this specifically for working with paths.
NSString* fullPath = [rootPath stringByAppendingPathComponent:fileName];

There's nothing wrong with it, although it could be better to use initWithFormat and release:
NSString *newPath = [[NSString alloc] initWithFormat:#"%#/%#",rootPath,fileName];
// do your thing
[newPath release];

There is absolutely nothing wrong with your code, it is correct memory management.
But it can be done with even less code and memory management needed:
for(fileName in [manager enumeratorAtPath:rootPath]){
if ([[fileName pathExtension] isEqualToString:#"exr"]) {
[fileArray addObject:fileName];
NSString* newPath = [rootPath stringByAppendingPathComponent:fileName];
attrDir = [manager attributesOfItemAtPath:newPath error:&myError];
fileSize = [attrDir objectForKey: #"NSFileSize"];
NSLog(#"File: /%# Size: %#", fileName, fileSize);
}
}

Related

To see more than pointers in an array (objective C)

If i enumerate an array i get
<myArray: 0x71b26b0>
<myArray: 0x71b2830>
<myArray: 0x71b2900>
I could take it that myData is behind the pointers listed, but if I wanted to explicitly see (log) the contents at each address, how to do that?
I have tried the &myData to no avail
--
for the benefit of uchuugaka:
-(void)loadObservedItems{
NSString *path = [self observationFilePath];
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
NSData *data = [[NSData alloc] initWithContentsOfFile:path];
NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:data];
myArray = [unarchiver decodeObjectForKey:#"ObserveKey"];
[unarchiver finishDecoding];
} else {
myArray = [[NSMutableArray alloc] initWithCapacity:10];
}
NSLog(#" %#",myArray);
}
Add to MyClass.m:
-(NSString*)description {
NSMutableDictionary* descDict = [NSMutableDictionary dictionary];
[descDict addObject:someField forKey:#"someField"]
[descDict addObject:anotherField forKey:#"anotherField"];
[descDict addObject:yetAnotherField forKey:#"yetAnotherField"];
return [descDict description];
}
Then just use NSLog(#"myObject is %#", myObject);. Just like the big guys.
Slightly more sophisticated is to (within the method) pre-pend your class name and the object address to the result string, but that's usually unnecessary for simple debugging.
But I think you can do that like this:
return [NSString stringWithFormat:#"%# : %#", [super description], [descDict description]];

Parsing a .csv file from a server with Objective-C

I have looked for an answer of a long time and still not found one so I thought I'd ask the question myself.
In my iPad app, I need to have the capability of parsing a .csv file in order to populate a table. I am using http://michael.stapelberg.de/cCSVParse to parse the csv files. However, I have only been successful in parsing local files. I have been trying to access a file from a server but am getting nowhere.
Here is my code to parse a local .csv file:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1)
{
//UITextField *reply = [alertView textFieldAtIndex:buttonIndex];
NSString *fileName = input.text;
NSLog(#"fileName %#", fileName);
CSVParser *parser = [CSVParser new];
if ([fileName length] != 0)
{
NSString *pathAsString = [[NSBundle mainBundle]pathForResource:fileName ofType:#"csv"];
NSLog(#"%#", pathAsString);
if (pathAsString != nil)
{
[parser openFile:pathAsString];
NSMutableArray *csvContent = [parser parseFile];
NSLog(#"%#", csvContent);
[parser closeFile];
NSMutableArray *heading = [csvContent objectAtIndex:0];
[csvContent removeObjectAtIndex:0];
NSLog(#"%#", heading);
AppDelegate *ap = [AppDelegate sharedAppDelegate];
NSManagedObjectContext *context = [ap managedObjectContext];
NSString *currentHeader = [heading objectAtIndex:0];
NSString *currentValueInfo = [heading objectAtIndex:1];
NSManagedObject *newObject = [NSEntityDescription insertNewObjectForEntityForName:#"Field" inManagedObjectContext:context];
[newObject setValue:#"MIS" forKey:#"header"];
[newObject setValue:currentHeader forKey:#"fieldName"];
for (NSArray *current in csvContent)
{
NSManagedObject *newField = [NSEntityDescription insertNewObjectForEntityForName:#"Field" inManagedObjectContext:context];
[newField setValue:currentHeader forKey:#"header"];
[newField setValue:currentValueInfo forKey:#"valueInfo"];
NSLog(#"%#", [current objectAtIndex:0]);
[newField setValue:[current objectAtIndex:0] forKey:#"fieldName"];
[newField setValue:[NSNumber numberWithDouble:[[current objectAtIndex:1] doubleValue]] forKey:#"value"];
}
NSError *error;
if (![context save:&error])
{
NSLog(#"Couldn't save: %#", [error localizedDescription]);
}
[self storeArray];
[self.tableView reloadData];
}
}
}
input.text = nil;
}
Forgive the weird beginning and ending brace indentation. :/
Anyway, so that is my code to take input from a user and access a file locally which I'm sure you guys have realized already. Now I want to know how to get the path of a file in my server.
Also if you guys see anything else wrong such as writing style and other bad habits please tell me as I'm new to iOS.
Thank you so much in advance! If you didn't understand my question please clarify as I'm bad at explaining myself at times! :)
As I am guessing you are trying to get data from a server's .csv file and want to show that data in table view list.
so I suggest you try to get that .csv file data in NSData and then work on that.
NSData *responseData = [NSData dataWithContentsOfURL:[NSURL URLWithString:#"serverUrl"]];
NSString *csvResponseString = [[[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding] autorelease];
NSLog(#"responseString--->%#",csvResponseString);
Now try to use nsstring's method (componentsSeparatedByString) with coma (')
arrSepratedData = [[responseString componentsSeparatedByString:#","];
Now use this arr for UITableView data populate.

How to convert NSUrl to NSString?

After AVAssetExportSession has complete export video.
I have plan to garb Video Path to upload via Youtube.
but [GDataUtilities MIMETypeForFileAtPath:path defaultMIMEType:#"video/mp4"];
it only accept NSString.
Is it possible to convert NSUrl in to NSString for video file path.
i have try to use NSString *path = [ExportoutputURL absoluteString];
but it crash.
Here is the Code
- (void)exportDidFinish:(AVAssetExportSession*)session {
ExportoutputURL = session.outputURL;
_exporting = NO;
NSIndexPath *exportCellIndexPath = [NSIndexPath indexPathForRow:2 inSection:kProjectSection];
ExportCell *cell = (ExportCell*)[self.tableView cellForRowAtIndexPath:exportCellIndexPath];
cell.progressView.progress = 1.0;
[cell setProgressViewHidden:YES animated:YES];
[self updateCell:cell forRowAtIndexPath:exportCellIndexPath];
ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];
if ([library videoAtPathIsCompatibleWithSavedPhotosAlbum:ExportoutputURL]) {
[library writeVideoAtPathToSavedPhotosAlbum:ExportoutputURL
completionBlock:^(NSURL *assetURL, NSError *error){
dispatch_async(dispatch_get_main_queue(), ^{
if (error) {
NSLog(#"writeVideoToAssestsLibrary failed: %#", error);
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:[error localizedDescription]
message:[error localizedRecoverySuggestion]
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
[alertView show];
[alertView release];
}
else {
_showSavedVideoToAssestsLibrary = YES;
ExportCell *cell = (ExportCell*)[self.tableView cellForRowAtIndexPath:exportCellIndexPath];
[cell setDetailTextLabelHidden:NO animated:YES];
[self updateCell:cell forRowAtIndexPath:exportCellIndexPath];
NSArray *modes = [[[NSArray alloc] initWithObjects:NSDefaultRunLoopMode, UITrackingRunLoopMode, nil] autorelease];
[self performSelector:#selector(hideCameraRollText) withObject:nil afterDelay:5.0 inModes:modes];
}
});
}];
}
[library release];
}
- (void)uploadVideoFile {
NSString *devKey = DEVELOPER_KEY;
GDataServiceGoogleYouTube *service = [self youTubeService];
[service setYouTubeDeveloperKey:devKey];
NSURL *url = [GDataServiceGoogleYouTube youTubeUploadURLForUserID:kGDataServiceDefaultUser];
// load the file data
NSString *path = [ExportoutputURL absoluteString];//[[NSBundle mainBundle] pathForResource:#"video_2451" ofType:#"mp4"];//[mFilePathField stringValue];
NSFileHandle *fileHandle = [NSFileHandle fileHandleForReadingAtPath:path];
NSString *filename = [path lastPathComponent];
// gather all the metadata needed for the mediaGroup
NSString *titleStr = #"Upload Test";//[mTitleField stringValue];
GDataMediaTitle *title = [GDataMediaTitle textConstructWithString:titleStr];
NSString *categoryStr = #"Entertainment";//[[mCategoryPopup selectedItem] representedObject];
GDataMediaCategory *category = [GDataMediaCategory mediaCategoryWithString:categoryStr];
[category setScheme:kGDataSchemeYouTubeCategory];
NSString *descStr = #"GData Description";//[mDescriptionField stringValue];
GDataMediaDescription *desc = [GDataMediaDescription textConstructWithString:descStr];
NSString *keywordsStr = #"RAGOpoR Demo";//[mKeywordsField stringValue];
GDataMediaKeywords *keywords = [GDataMediaKeywords keywordsWithString:keywordsStr];
BOOL isPrivate = NO;//([mPrivateCheckbox state] == NSOnState);
GDataYouTubeMediaGroup *mediaGroup = [GDataYouTubeMediaGroup mediaGroup];
[mediaGroup setMediaTitle:title];
[mediaGroup setMediaDescription:desc];
[mediaGroup addMediaCategory:category];
[mediaGroup setMediaKeywords:keywords];
[mediaGroup setIsPrivate:isPrivate];
NSString *mimeType = [GDataUtilities MIMETypeForFileAtPath:path
defaultMIMEType:#"video/mp4"];
// create the upload entry with the mediaGroup and the file
GDataEntryYouTubeUpload *entry;
entry = [GDataEntryYouTubeUpload uploadEntryWithMediaGroup:mediaGroup
fileHandle:fileHandle
MIMEType:mimeType
slug:filename];
SEL progressSel = #selector(ticket:hasDeliveredByteCount:ofTotalByteCount:);
[service setServiceUploadProgressSelector:progressSel];
GDataServiceTicket *ticket;
ticket = [service fetchEntryByInsertingEntry:entry
forFeedURL:url
delegate:self
didFinishSelector:#selector(uploadTicket:finishedWithEntry:error:)];
[self setUploadTicket:ticket];
GTMHTTPUploadFetcher *uploadFetcher = (GTMHTTPUploadFetcher *)[ticket objectFetcher];
}
Error EXC_BAD_ACCESS at
NSString *path = [ExportoutputURL absoluteString];
Is it possible to convert NSUrl in to NSString for video file path.
Yes. Send it an absoluteString message.
i have try to use NSString *path = [ExportoutputURL absoluteString]; but it crash.
If you want a path, send the URL a path message. A string representing a URL is generally not a valid path; if you want a path, ask it for one.
As for the crash, it does not mean absoluteString is wrong. Sending absoluteString to an NSURL object is the correct way to get an NSString object that represents the URL. The problem is somewhere else.
Error EXC_BAD_ACCESS at
NSString *path = [ExportoutputURL absoluteString];
This probably means that ExportoutputURL points to something that is not nil but is also not a valid object. It might have pointed to an NSURL object at some point, but it doesn't now.
My guess would be that the problem is this:
ExportoutputURL = session.outputURL;
You assign the URL to the ExportoutputURL instance variable, but you don't retain the object or make your own copy. Therefore, you don't own this object, which means you are not keeping it alive. It may die at any time, most probably after this method (exportDidFinish:) returns.
The crash is because you call uploadVideoFile later, after the URL object has already died. You still have a pointer to it, but that object no longer exists, so sending a message to it—any message—causes a crash.
There are three simple solutions:
Retain the URL object when you assign it to your instance variable.
Make your own copy of the URL object and assign that to the instance variable.
Declare ExportoutputURL as a property, with either the strong keyword or the copy keyword, and assign the object to the property, not the instance variable. That will call the property's setter, which, if you synthesize it or implement it correctly, will retain or copy the URL for you.
Either way, you will own the object, and that will keep it alive until you release it. Accordingly, you will need to release it when you are done with it (in dealloc, if not earlier), so that you don't leak it.
This all assumes that you are not using ARC. If you are using Xcode 4.2 or later, and can require iOS 4 or later, you should migrate your project to ARC, as it makes so many things much simpler. You would not need to retain or copy this object if you were using ARC, which means that migrating to ARC now is a fourth solution (but certainly a larger-scale one).
Use either absolutePath or path as mentioned by Miek and Nepster. Expanding on their answers, the difference between lies in the prefix.
NSString* string1 = [url absoluteString]; // #"file:///Users/jackbrown/Music/song name.mp3"
NSString* string2 = [url path]; // #"/Users/jackbrown/Music/song name.mp3"`
NSString *path = [[NSString alloc] initWithString:[url path]]; ?
Use this. I think it will help you.
In Objective c
NSString *testString = testUrl.absoluteString;
In Swift
var testString : String = testUrl.absoluteString
Simply you can do it like this.
NSString *myString = [myURL absoluteString];

Objective-C Bad exception dropbox

I've got a question. Where is the reason for EXC_BAD_ACCESS in the following code ?
-(void)restClient:(DBRestClient *)client loadedMetadata:(DBMetadata *)metadata {
if(metadata.isDirectory) {
db_Path = metadata.path;
int i = 0;
NSString *fileName = [[NSString alloc] init];
for(DBMetadata *file in metadata.contents) {
fileName = [NSString stringWithFormat:#"%#", file.filename];
[db_MetaFileNames addObject:file.filename];
i++;
}
[self createMetaListArray];
[fileName release];
}
}
-(void)createMetaListArray {
fileNamesAtDirectory = db_MetaFileNames;
for (int i=0; i < [fileNamesAtDirectory count]; i++) {
NSString *filePathWithName = db_directory;
[filePathWithName stringByAppendingFormat:
[fileNamesAtDirectory objectAtIndex:i]];
[filePathsAtDirectory addObject:filePathWithName];
[filePathWithName release];
}
}
Can Anyone here help me ?
Here:
NSString *fileName = [[NSString alloc] init];
for(DBMetadata *file in metadata.contents) {
fileName = [NSString stringWithFormat:#"%#", file.filename];
The NSString on the first line gets overwritten with the new values on the third line. The original value leaks.
This means that:
}
[self createMetaListArray];
[fileName release];
The release on the last line releases not the fileName that you alloc/init above, but the assignment inside the loop. You don't alloc/copy/retain that, so you're not "in charge" of releasing it.
You have a similar misunderstanding in the second function.
[filePathWithName stringByAppendingFormat:[fileNamesAtDirectory objectAtIndex:i]];
This does not amend filePathWithName. It returns a new string.
I suggest you read up on Cocoa's memory management rules -- you're missing some fundamentals. Understanding those will make your life a lot easier.

Easy way to get size of folder (ObjC/Cocoa)?

Right now I'm using this code to get the size of a folder:
NSArray *contents;
NSEnumerator *enumerator;
NSString *path;
contents = [[NSFileManager defaultManager] subpathsAtPath:folderPath];
enumerator = [contents objectEnumerator];
while (path = [enumerator nextObject]) {
NSDictionary *fattrib = [[NSFileManager defaultManager] fileAttributesAtPath:[folderPath stringByAppendingPathComponent:path] traverseLink:YES];
fileSize +=[fattrib fileSize];
}
[contents release];
[path release];
The problem is that its highly innacurate. It either adds a few megabytes or deducts a few megabytes from the actual size. For example I got the file size of an .app bundle and this method reported 16.2MB, whereas the actual thing is 15.8.
What's the best way to get the size of a folder?
Thanks
I needed to do this today myself, and I've found that the code in this post on the Cocoa-dev list is super fast and matches what Finder says to the byte. (don't forget to OR in the kFSCatInfoRsrcSizes flag so you get resource fork sizes, too!)
If you need more explanation on how to use it, just leave a comment and I'll edit this post. =)
The documentation for fileSize states it does not include the size of a resource fork. You may need to use the Carbon File Manager API to reliably calculate directory sizes.
I just wanted to second Dave DeLong's suggestion about the post on Cocoa-dev, but add a cautionary note to be sure to read all the posts in the thread. There is one by Rosyna that's particularly worth noting. In my case I followed that advice (changing max items per fetch to 40) and saw a speed jump as well as the end to a nasty crashing bug.
hope this will help
- (unsigned long long) fastFolderSizeAtFSRef:(NSString *)theFilePath
{
unsigned long long totalSize = 0;
NSFileManager *fileManager = [NSFileManager defaultManager];
BOOL isdirectory;
NSError *error;
if ([fileManager fileExistsAtPath:theFilePath])
{
NSMutableArray * directoryContents = [[fileManager contentsOfDirectoryAtPath:theFilePath error:&error] mutableCopy];
for (NSString *fileName in directoryContents)
{
if (([fileName rangeOfString:#".DS_Store"].location != NSNotFound) )
continue;
NSString *path = [theFilePath stringByAppendingPathComponent:fileName];
if([fileManager fileExistsAtPath:path isDirectory:&isdirectory] && isdirectory )
{
totalSize = totalSize + [self fastFolderSizeAtFSRef:path];
}
else
{
unsigned long long fileSize = [[fileManager attributesOfItemAtPath:path error:&error] fileSize];
totalSize = totalSize + fileSize;
}
}
}
return totalSize;
}
This is typically how it is done. 2 possibilities:
Check your byte -> megabyte conversion routines. Also, do you want megabytes or mebibytes? (It probably depends on what you're comparing it to.)
Try passing NO for the traverseLink parameter. There might very well be a symlink in the bundle pointing to something else that the routine you're comparing it to won't account for. You'll either count something in the bundle twice, or you'll include something outside the bundle entirely (most likely the former).
I know that this is an old topic. But for anyone out there looking for answers on how to do this,
[[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir];
if (isDir) {
NSPipe *pipe = [NSPipe pipe];
NSTask *t = [[[NSTask alloc] init] autorelease];
[t setLaunchPath:#"/usr/bin/du"];
[t setArguments:[NSArray arrayWithObjects:#"-k", #"-d", #"0", path, nil]];
[t setStandardOutput:pipe];
[t setStandardError:[NSPipe pipe]];
[t launch];
[t waitUntilExit];
NSString *sizeString = [[[NSString alloc] initWithData:[[pipe fileHandleForReading] availableData] encoding:NSASCIIStringEncoding] autorelease];
sizeString = [[sizeString componentsSeparatedByString:#" "] objectAtIndex:0];
bytes = [sizeString longLongValue]*1024;
}
else {
bytes = [[[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil] fileSize];
}
It will use terminal to determine a size for folders in bytes. And it will use Cocoa's built in NSFileManager to get the size of files. It's very fast, and gets the exact size that finder reports.
This code is as extension(category) to the NSFileManager class. It sums the sizes of all folder content.
Note that error treatment could be enhanced.
#interface NSFileManager(Util)
- (NSNumber *)sizeForFolderAtPath:(NSString *) source error:(NSError **)error;
#end
#implementation NSFileManager(Util)
- (NSNumber *)sizeForFolderAtPath:(NSString *) source error:(NSError **)error
{
NSArray * contents;
unsigned long long size = 0;
NSEnumerator * enumerator;
NSString * path;
BOOL isDirectory;
// Determine Paths to Add
if ([self fileExistsAtPath:source isDirectory:&isDirectory] && isDirectory)
{
contents = [self subpathsAtPath:source];
}
else
{
contents = [NSArray array];
}
// Add Size Of All Paths
enumerator = [contents objectEnumerator];
while (path = [enumerator nextObject])
{
NSDictionary * fattrs = [self attributesOfItemAtPath: [ source stringByAppendingPathComponent:path ] error:error];
size += [[fattrs objectForKey:NSFileSize] unsignedLongLongValue];
}
// Return Total Size in Bytes
return [ NSNumber numberWithUnsignedLongLong:size];
}
#end