I am trying to get the date a video was taken and populate a TextView with it in Xcode. I have chosen the video and then gotten the date from the AVMetadataItem creationDate. I can print it out as a NSLog but I want to convert it into a String or NSData.
Here is my code in objective-c
in .h
#property(nonatomic, readonly, nullable) AVMetadataItem *creationDate;
and in .m
NSURL * movieURL = [info valueForKey:UIImagePickerControllerMediaURL] ;
AVURLAsset *anAsset = [[AVURLAsset alloc] initWithURL:movieURL options:nil];
NSLog(#"creationDate:%#",anAsset.creationDate.value);
in the log I get creationDate:Tue Jan 26 09:44:39 2021 which is the date I took the video.
My problem is now converting it to a usable form.
When I try
NSString = anAsset.creationDate.value;
I get a warning
Initializing 'NSString *_strong' with an expression of incompatible type 'id<NSObject,NSCopying> _Nullable'
I basically get this same warning no matter what I try.
Can someone help me get this working?
Related
I'm a novice ObjC programmer (started learning last week); I'm having some unexpected results trying to get the lat and long from the centre of an MKMapView.
I have the following method that gets called when the map changes region:
- (void)mapView:(MKMapView*)mapView regionDidChangeAnimated:(BOOL)animated {
NSLog(#"------> %#", mapView);
latLabel.text = [[NSString alloc] initWithFormat:#"%#", [mapView centerCoordinate]];
}
In the log I'm not getting (null), I'm getting the printout of an MKMapView object; but on the very next line I get an unhandled EXC_BAD_ACCESS.
Any help appreciated, and I'd be happy to offer more info if it's requested.
Thanks.
CLLocationCoordinate2D is not an Objective-C object, it's a C structure. You can't directly convert it to an NSString like that.
Try:
CLLocationCoordinate2D center = [mapView centerCoordinate];
latLabel.text = [NSString stringWithFormat:#"(%f, %f)", center.latitude, center.longitude];
Edit: Since you're new to Objective-C, thought you might like some insight into how this problem occurs and why the error message is so non-descriptive.
[NSString stringWithFormat:...] takes a format string and an arbitrary number of parameters. It then parses the format string and fills in the parameters as they're needed.
The %# token in the format string designates an Objective-C object; i.e. an NSObject * or subclass thereof. NSObject defines the description method that provides an NSString * description of the object. stringWithFormat: calls description on the argument provided for the %# token to fill it in the format string.
The result of this is a call is made to objc_msgSend with your CLLocationCoordinate2D struct to make the description call because NSString assumes you've provided the right kind of parameter. Then the crash occurs because objc_msgSend treats the struct as if it's an NSObject * pointer and tries to access memory at a bad location. Hence the EXC_BAD_ACCESS.
Disclaimer: This is based on my understanding of Objective-C after only a couple of years, so if I'm wrong about anything, feel free to correct me.
I got this code and XCode warns me of "incompatible pointer types initializing NSString *__strong with an expression of type UITextField".
NSString *name = (UITextField *)searchText.text;
but this one is fine
NSString *name2 = [(UITextField *)searchText text];
and this one is fine too
NSString *name3 = [(UITextField *)searchText.text mutableCopy];
I have two questions:
I am confused with obj.* and [obj *]
Why is the "mutableCopy" correct is this case?
I don't know how to search in Apple developer documentation for these questions.
In the first version, due to operator precedence, you're casting searchText.text to a UITextField*, what you want to do is probably to cast searchText;
NSString *name = ((UITextField *)searchText).text;
In the second version you don't have the dot, so the compiler understands your cast to be casting searchText to UITextField and send the text message to it. In other words, exactly right.
The last case is a bit tricky since it involves both runtime and compile time. As I understand it;
You cast searchText.text to a UITextField*. The runtime still knows that the object is an NSString and the mutableCopy message that exists on both will go to the correct method [NSString mutableCopy] anyway and create/return a mutable copy of the NSString so runtime it works out ok.
Since mutableCopy returns id (referencing a NSMutableString), the assignment to an NSString is ok by the compiler (id can be assigned to anything), so compile time it's ok.
A question, what is searchText originally? That the last version compiled without warning indicates that it's already an UITextField*, or at least a type that can take the text message. If so, you should be able to just do;
NSString *name3 = [searchText.text mutableCopy];
In the second and third examples, the cast just operates on searchText. So with these you are sending a message to a UITextField object.
In the first one, the cast applies to the whole of searchText.text. Assigning a UITextField object to a NSString variables is not what you want. The code you're looking for is:
NSString *name = ((UITextField *)searchText).text;
The mutableCopy message returns a copy of your string as a NSMutableString object, which can be assigned to a NSString as NSMutableString derives from it. In this case using the 'copy' message is just as good.
Hope that helps.
I'm using Stig Brautaset's JSON framework serialize some objects, including NSDates (which are not directly supported).
I decided to use NSDate's description as the JSONFragment representation of a date (I don't care about the minor loss of precision incurred in doing so).
To extend Stig Brautaset's JSON framework to include NSDates, I defined a category:
#interface NSDate (NSDate_JSON) <JSONInitializer>
-(NSString *) JSONFragment;
#end
To recreate an NSDate (and other classes) from JSON, I defined a protocol with the following initializer:
#protocol JSONInitializer <NSObject>
-(id) initWithJSONRepresentation: (NSString *) aJSONRepresentation;
#end
I'm having issues with this initializer. In NSDate's case, it just calls initWithString:, and that's were I get into trouble: it always returns nil. This is the implementation:
#import "NSDate+JSON.h"
#implementation NSDate (NSDate_JSON)
-(NSString *) JSONFragment{
NSString *strRepr = [self description];
return [strRepr JSONFragment];
}
-(id) initWithJSONRepresentation:(NSString *)aJSONRepresentation{
return [self initWithString: aJSONRepresentation]; //returns nil!
}
#end
I'm not sure what's going on. Besides, the compiler warns me that the initWithString: method in initWithJSONRepresentation: could not be found.
Anybody knows what might be going on?
The full source code for a test case is available here.
You should always use an NSDateFormatter when attempting to convert a string into a date or vice versa. -initWithString: does exist on the Mac, but not on iOS. It requires the string to be in an extremely precise format. Using a date formatter is by far the superior solution.
And as a side note, your code would break if Apple ever decided to change the format of -[NSDate description].
Your test program is:
NSDate *d1 = [[[NSDate alloc] init] autorelease];
NSString *repr = [d1 JSONFragment];
NSDate *dd = [[[NSDate alloc] initWithString:[d1 description]] autorelease ];
NSDate *d2 = [[[NSDate alloc] initWithJSONRepresentation:repr] autorelease];
Your -JSONFragment category method is:
-(NSString *) JSONFragment{
NSString *strRepr = [self description];
return [strRepr JSONFragment];
}
What’s happening in this method is that you obtain a string representation of that date using -description, and then a JSON representation of that string using -JSONFragment.
In SBJSON, -JSONFragment returns the representation of a given object as JSON data. The JSON specification requires that strings are quoted. In your program:
NSString *repr = [d1 JSONFragment];
repr contains a string like #"\"2011-04-29 10:20:30 -0600\"". Because of the quotes, that string is not a valid string to be used with -[NSDate initWithString:].
If you change:
NSString *repr = [d1 JSONFragment];
to:
NSString *repr = [[d1 JSONFragment] JSONFragmentValue];
so that SBJSON parses that fragment and returns a string without the quotes, it should work.
The reason initWithString: can't be found is that unless you're importing Foundation and didn't show us here, your code can't see NSDate.h, so it doesn't know that initWithString: exists.
Dave's quite right about relying on description and using an NSDateFormatter instead. It doesn't seem likely that description will change, but there's no guarantee that it will continue to be valid input for initWithString: which has a strict input requirement:
A string that specifies a date and time value in the international string representation format — YYYY-MM-DD HH:MM:SS ±HHMM, where ±HHMM is a time zone offset in hours and minutes from GMT (for example, “2001-03-24 10:45:32 +0600”).
You must specify all fields of the format string, including the time zone offset, which must have a plus or minus sign prefix.
If your string differs in any way (including, as has become apparent, having quotes in it), you'll get nil.
I am getting confused with how to handle Integers in Objective C.
If I define the following:
NSInteger i = 6;
NSLog(#"%d", i);
I expect it to print 6 to the console.
however I have an NSInteger within an object which is obviously reference by a pointer so I get very difference results.
For example:
#interface Section : NSObject {
NSInteger Id;
}
#property (nonatomic, assign) NSInteger Id;
Please assume this has been synthesized in the implementation.
I create the object set its value and access it again as follows:
Section *section = [[Section alloc] init];
section.Id = 6;
NSMutableArray *sections = [[NSMutableArray alloc] init];
[sections addobject:section];
Section *sectionB = [setions objectAtIndex:0];
NSLog(#"%d", sectionB.Id);
This has the strange effect of printing the memory address ie a number like 5447889. Why can I not just get the value?
I have tried using:
NSInteger sid = [[section Id]integerValue];
But I then get the warning Invalid receiver type 'NSInteger' and sometime get an error Program received signal: “EXC_BAD_ACCESS”.
I would really like to know how to handle Integers, or any values for that matter properly.
Many Thanks
It looks like you're accessing uninitialized memory; 5447889 doesn't look like a pointer value—pointers are usually word-aligned, and 5447889 isn't word aligned.
Maybe you could cut and paste your actual code. This has typos such as addobject instead of addObject and setions instead of sections.
Does it work if you keep things simple and do NSLog(#"%d", section.Id) to skip messing with the array?
Regarding the strange values, see Dominic Cooney's answer.
Regarding the EXC_BAD_ACCESS: [[section Id]integerValue]; doesn't work because it then tries to interpret the NSInteger as an object and tries to send the message integerValue to it, which can't work. It's an integral number, not an object.
Think I found the answer to my own question. Setting the value of an NSInteger to a value of say 6 is fine. The problem I have is I am setting it to the value returned from a Json string using the following:
NSInteger i = [jsonResult objectForKey:#"Id"];
which should be:
NSInteger i = [[jsonResult objectForKey:#"Id"] integerValue];
I have not tested this but makes sense based on what DarkDust said about integerValue taking an object and not an Integer.
Thanks for your input.
I have in the .h file :
NSString *dataHML;
NSString *dataHML2;
NSString *dataHML3;
NSString *dataHML4;
NSString *dataHML5;
NSString *dataHML6;
NSString *dataHMLtotal;
in the .m file I merge them with :
NSString *dataHtmlTotal = [NSString stringWithFormat:#"%#%#%#%#%#%#", dataHtml, dataHtml2, dataHtml3, dataHtml4,dataHtml5,dataHtml6];
But unfortunately it crashes at some point because of this.
Could anyone give me a other solution and post it please, because I already tried nsuserdefault or a nsarray, but without I couldn't get it working.
If you really do have 6 variables numerically named like that, you could be better off with an array.
NSMutableArray *dataHMLStrings = [NSMutableArray array];
[dataHMLStrings addObject:#"String1"];
[dataHMLStrings addObject:#"String2"];
.
.
.
[dataHMLStrings addObject:#"String100"]; // or however many you have.
NSString *dataHMLTotal = [dataHMLStrings componentsJoinedByString:#""];
You can give the componentsJoinedByString: method a different string (I passed an empty string here because you didn't want anything to appear between each dataHML string).
Please make sure your strings are all allocated and initialized (neither points of which you mention in your question.) If you do not do so then you run the risk of manipulating data at the location of the garbage pointers, and your application will very likely crash.