Cocoa: Problem passing a CGPoint with NSNotification and NSDictionary - iphone

I'm trying to fire a Notification in a method called setPosition in one class, that triggers setViewPointCenter in another class. However, I'm trying to send a CGPoint along with it. But Xcode isn't liking it one bit.
-(void)setPosition:(CGPoint)point
{
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:#"sp", point, nil];
[[NSNotificationCenter defaultCenter]
postNotificationName:#"SpriteDidSetPosition"
object:self
userInfo:dict];
[super setPosition:point];
}
Triggers this method in another class, but throws the indicated error
-(id) init{
// Usual stuff, blah blah blah...
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(setViewPointCenter:)
name:#"BownceSpriteDidSetPosition"
object:nil];
}
-(void) setViewPointCenter:(NSNotification *)notification
{
// ERROR: Invalid Initializer
CGPoint point = [[notification userInfo] valueForKey:#"sp"];
// more code here....
}
I've been digging around, and found this solution, but I still get an error.
-(void)setPosition:(CGPoint)point
{
// ERROR: Incompatile type for argument 1 of "Value With Point"
NSValue *pointAsObject = [NSValue valueWithPoint:point];
NSDictionary *dict = [[NSDictionary alloc]
initWithObjectsAndKeys:#"sp",
pointAsObject,
nil];
[[NSNotificationCenter defaultCenter]
postNotificationName:#"SpriteDidSetPosition"
object:self
userInfo:dict];
[super setPosition:point];
}
It's driving me nuts. And to confuse me even further, changing CGPoint to NSPoint like this
-(void)setPosition:(NSPoint)point
{
NSValue *pointAsObject = [NSValue valueWithPoint:point];
NSDictionary *dict = [[NSDictionary alloc] init];
[dict initWithObjectsAndKeys:#"sp", pointAsObject, nil];
[[NSNotificationCenter defaultCenter]
postNotificationName:#"SpriteDidSetPosition"
object:self
userInfo:dict];
[super setPosition:CGPointMake(point.x, point.y)];
}
Get's rid of the error in setPosition, but I'm still screwed in setViewPointCenter. And as I understand it, CGPoint and NSPoint should equal the same thing, but it doesn't look like they do.
Does anyone have a working example of how to pass a CGPoint in a Dictionary? I can't figure it out.
This is for the iPhone, incase that makes a difference.

Try using +[NSValue valueWithCGPoint].

I'd use the NSStringFromCGPoint() function to convert it to a string, and then use the CGPointFromString() function to convert it back.

You could encapsulate the x and y values from the CGPoint into NSNumber objects using +numberWithFloat: and then add the two resulting NSNumber objects into the dictionary. You can then reconstruct the CGPoint on the other side using:
CGPoint myPoint;
myPoint.x = [myNumberObject floatValue];
myPoint.y = [myNumberObject2 floatValue];
The reason it didn't work in the first try was that CGPoint isn't an object, it's a C struct.

Its been too long time after #Ben Gottlieb have given an answer, his answer is well, but for future I'm keeping an example for reference.
// In example, I want to send CGPoint with notification
[[NSNotificationCenter defaultCenter] postNotificationName:#"MyNotification" object:#{#"someKeyToHoldCGPoint":[NSValue valueWithCGPoint:CGPointMake(10, 10)]}];
- (void) getPoints:(NSNotification *)notification {
//get the dictionary object from notification
NSDictionary *p = (NSDictionary *)notification.object;
//get the NSValue object from dictionary p
NSValue *value = [p valueForKey:#"someKeyToHoldCGPoint"];
//convert the value to CGPoint
CGPoint points = [value CGPointValue];
//check if we've the correct value
NSLog(#"%#",NSStringFromCGPoint(points));
}
It should log, (10,10).

I haven't read up on GC and NSPoints, but what data-types can NSDictionary hold? Check the docs, maybe you should cast it to NSData.

Related

iphone dev getting video thumbnail (frame) from MPMoviePlayerController

every one i am trying to get the video frame or thumbnail from a video url but not succeeding in it, here is my code
- (void)viewDidLoad {
thumbnailimg = [[UIImageView alloc]init];
movie = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:#"http://www.youtube.com/watch?v=ec9KXrpYvzk"]];
//UIImage *singleFrameImage = [movie thumbnailImageAtTime:10
//timeOption:MPMovieTimeOptionExact];
//thumbnailimg.image = singleFrameImage;
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc addObserver:self selector:#selector(handleThumbnailImageRequestFinishNotification:)
name:MPMoviePlayerThumbnailImageRequestDidFinishNotification
object:movie];
NSNumber * time =[NSNumber numberWithInt:10];
NSArray *times = [NSArray arrayWithObjects:time,nil];
[movie requestThumbnailImagesAtTimes:times timeOption:MPMovieTimeOptionExact];
[super viewDidLoad];
}
-(void)handleThumbnailImageRequestFinishNotification:(NSNotification*)note
{
NSDictionary *userinfo = [note userInfo];
NSMutableDictionary *event = [NSMutableDictionary dictionary];
NSError* value = [userinfo objectForKey:MPMoviePlayerThumbnailErrorKey];
if (value!=nil)
{
[event setObject:[value description] forKey:#"error"];
}
else
{
UIImage *image = [userinfo valueForKey:MPMoviePlayerThumbnailImageKey];
thumbnailimg.image = image;
}
[event setObject:[userinfo valueForKey:MPMoviePlayerThumbnailTimeKey] forKey:#"time"];
}
even the handleThumbnailImageRequestFinishNotification is not firing, plz. tell me what i am doing wrong and how to correct it, thanx in advance, Regards Saad
It's not possible to read videos from YouTube with a MPMoviePlayerController try to use an other video (from a m3u8 playlist or MP4 file).
Just wanted to tell that times should be provided as float, not int.
Replacing:
NSNumber * time =[NSNumber numberWithInt:10];
with:
NSNumber * time =[NSNumber numberWithFloat:10.0f];
Will maybe fix something.
Similar answer: https://stackoverflow.com/a/17870972

Pass object with NSNotificationCenter to other view

I am trying to pass an object from my main view class to other notification receiver in another class.
I want to pass an object named country, that loads all the cities from an SOAP Request in the Main Controller and i want to send it to my next view.
country = [[Country alloc] init];
Country header:
#interface Country : NSObject
{
NSString *name;
NSMutableArray *cities;
}
#property (nonatomic,retain) NSString *name;
- (void)addCity:(Cities *)city;
- (NSArray *)getCities;
- (int)citiesCount;
#end
I found a way to pass data with NSNotificatios is using a NSDictionary in UserInfo. But its not possible to send the whole object instead of converting to an NSDictionary? Or what's the best way to transfer it? Im stuck trying to figure out how to pass the objects.
Actually i got working this simple NSNotification on my App.
NSNotification in the Main View Controller implementation:
//---Call the next View---
DetailViewController *detail = [self.storyboardinstantiateViewControllerWithIdentifier:#"Detail"];
[self.navigationController pushViewController:detail animated:YES];
//--Transfer Data to2View
[[NSNotificationCenter defaultCenter] postNotificationName:#"citiesListComplete" object:nil];
NSNotification in 2View Controller implementation:
// Check if MSG is RECEIVE
- (void)checkMSG:(NSNotification *)note {
NSLog(#"Received Notification");
}
- (void)viewDidLoad
{
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(checkMSG:)
name:#"citiesListComplete" object:nil];
Oooooo, so close. I have a feeling you do not understand what an NSDictionary is though.
Post your notification with this:
Country *country = [[[Country alloc] init] autorelease];
//Populate the country object however you want
NSDictionary *dictionary = [NSDictionary dictionaryWithObject:country forKey:#"Country"];
[[NSNotificationCenter defaultCenter] postNotificationName:#"citiesListComplete" object:nil userInfo:dictionary];
then get the country object like this:
- (void)checkMSG:(NSNotification *)note {
Country *country = [[note userInfo] valueForKey:#"Country"];
NSLog(#"Received Notification - Country = %#", country);
}
You don't need to convert your object into a NSDictionary. Instead, you need to send a NSDictionary with your object. This allows you to send lots of information, all based on keys in the NSDictionary, with your NSNotification.
For Swift
You can pass dictionary with using the below code
NSNotificationCenter.defaultCenter().postNotificationName(aName: String, object anObject: AnyObject?, userInfo aUserInfo: [NSObject : AnyObject]?)
for example
NSNotificationCenter.defaultCenter().postNotificationName("OrderCancelled", object: nil, userInfo: ["success":true])
And read this dictionary from
func updated(notification: NSNotification){
notification.userInfo?["success"] as! Bool
}

iPhone Development: nil userInfo when receiving a notification

I post the notifications like this in an operation:
DownloadStatus * status = [[DownloadStatus alloc] init];
[status setMessage: #"Download started"];
[status setStarted];
[status setCompleteSize: [filesize intValue]];
[userInfo setValue:status forKey:#"state"];
[[NSNotificationCenter defaultCenter]
postNotificationName:[targetURL absoluteString]
object:nil userInfo:userInfo];
[status release];
DownloadStatus is an object that contains some information abou the download that is being currently downloaded. userInfo is a property of the object that has been initialized in the init part and is kept for the complete duration of the operation. It is created so:
NSDictionary * userInfo = [NSDictionary dictionaryWithObject:targetURL
forKey:#"state"];
"targetURL" is a NSString, I use this just to make sure everything is working fine. When I receive the event - I registered like this:
[[NSNotificationCenter defaultCenter]
addObserver:self selector:#selector(downloadStatusUpdate:)
name:videoUrl
object:nil];
Here "videoUrl" is a string that contains the url being downloaded, so that I will receive notification about an url I'm waiting to see downloaded.
The selector is implemented like this:
- (void) downloadStatusUpdate:(NSNotification*) note {
NSDictionary * ui = note.userInfo; // Tried also [note userInfo]
if ( ui == nil ) {
DLog(#"Received an update message without userInfo!");
return;
}
DownloadStatus * state = [[ui allValues] objectAtIndex:0];
if ( state == nil ) {
DLog(#"Received notification without state!");
return;
}
DLog(#"Status message: %#", state.message);
[state release], state = nil;
[ui release], ui = nil; }
But this selector always receives a null userInfo. What am I doing wrong?
MrWHO
One way or another, you seem to be initialising your userInfo object incorrectly. The line as given:
NSDictionary * userInfo = [NSDictionary dictionaryWithObject:targetURL
forKey:#"state"];
Would create an autoreleased NSDictionary and store it to a local variable. The value would not be propagated up to your member variable.
Supposing that's a snippet, followed by e.g.
self.userInfo = userInfo;
to assign the local to the member, retaining it at the same time, then your code should generate an exception at this line:
[userInfo setValue:status forKey:#"state"];
Since it attempts to mutate an immutable object. It's therefore much more likely that the value of userInfo isn't stored and you're messaging nil at that point.
So, I would think that — assuming you have userInfo declared as a 'retain' type property, you want to replace:
NSDictionary * userInfo = [NSDictionary dictionaryWithObject:targetURL
forKey:#"state"];
With:
self.userInfo = [NSMutableDictionary dictionaryWithObject:targetURL
forKey:#"state"];

How to pass userInfo in NSNotification?

I am trying to send some data using NSNotification but get stuck. Here is my code:
// Posting Notification
NSDictionary *orientationData;
if(iFromInterfaceOrientation == UIInterfaceOrientationLandscapeRight) {
orientationData = [NSDictionary dictionaryWithObject:#"Right"
forKey:#"Orientation"];
}
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
[notificationCenter postNotificationName:#"Abhinav"
object:nil
userInfo:orientationData];
// Adding observer
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(orientationChanged)
name:#"Abhinav"
object:nil];
Now how to fetch this userInfo dictionary in my selector orientationChanged?
You get an NSNotification object passed to your function. This includes the name, object and user info that you provided to the NSNotificationCenter.
- (void)orientationChanged:(NSNotification *)notification
{
NSDictionary *dict = [notification userInfo];
}
Your selector must have : to accept parameters.
e.g.
#selector(orientationChanged:)
then in the method declaration it can accept the NSNotification parameter.
You are posting the notification correctly.
Please modify the Notification Observer like following.
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(orientationChanged:)
name:#"Abhinav" object:nil];
- (void)orientationChanged:(NSNotification *)notification
{
NSDictionary *dict = [notification userInfo];
}
I hope, this solution will work for you..
In swift
To get userinfo object
let dict = notification.userInfo
print(dict)

iphone gps cllocation and making variables globally accessible

I'm pretty new to iPhone development and have been trying to work out how to include GPS information into an app I'm working on.
I've gone through the HelloThere tutorial, which is a great start
http://www.mobileorchard.com/hello-there-a-corelocation-tutorial/
And had no problems getting this to run on my iPhone. I then took the example and have since been trying to incorporate the GPS info into a much larger and more complicated app. The larger application has an existing function which will send a post request to the server, and I'd like to simply provide the location data, specifically the coordinate.latitude and coordinate.longitude to this function, if possible without altering it.
This is pretty trivial in the other languages I've worked with but it's turned out to be quite challenging in objective C.
Basically, as per the tutorial I have gotten to the point where I'm logging the location info,
//GPS stuff
- (void)locationUpdate:(CLLocation *)location {
//locationLabel.text = [location description];
locationString = [location description];
locationLabel.text = locationString;
locLat = [NSString stringWithFormat:#"%lf", location.coordinate.latitude];
locLong = [NSString stringWithFormat:#"%lf", location.coordinate.longitude];
}
but I can't figure out how I can then make the locLat and locLong variables available to other parts of the application. Pretty lame but I'm still a bit lost with objective C.
There are many ways to do this. The quick and dirty way (and some will frown upon it) is to just declare those as globals in this file and use extern to access them from other files.
Better is to make those #properties of the class, and provide a getter so you can access those from another class or part of the app. That does assume that this class will be available for other classes to access later on.
You also can use delegate to get information. And...
Thinking a bit more, I would probably store data like this someplace else, and will use this routine to update the value in that location (by using a setter of that class), so this method here would just get the location and then store it elsewhere.
You might want to read Scott Knaster's book on Objective C and Mac development for a primer on Obj C.
Here's how I recommend doing it:
Store lat/long in a dictionary and fire them off as strings bundled in a notification. Setup an observer in the application delegate and have the callback function store the lat/long in class properties of the application delegate and/or store them in the application defaults.
In your class where you acquire the coordinates:
- (void)locationUpdate:(CLLocation *)location {
NSString *locationString, *locLat, *locLong;
locationString = [location description];
locLat = [NSString stringWithFormat:#"%lf", location.coordinate.latitude];
locLong = [NSString stringWithFormat:#"%lf", location.coordinate.longitude];
NSDictionary *locationDictionary = [NSDictionary dictionaryWithObjectsAndKeys:locationString, #"description",
locLat, #"latitude", locLong, #"longitude", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:#"updateSearchLocation"
object:self userInfo:locationDictionary];
}
In your application delegate class:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Listen for search coordinates broadcast
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(setCoordinates:)
name:#"updateSearchLocation" object:nil];
}
- (void)setCoordinates:(id)sender {
self.latitude = [[sender userInfo] objectForKey:#"latitude"];
self.longitude = [[sender userInfo] objectForKey:#"longitude"];
NSLog(#"location = %#", [[sender userInfo] objectForKey:#"description"]);
}
Dont forget to setup the class properties in the application delegate header file as NSString. You can then access the coordinates by calling directly from the application delegate:
YourAppDelegateClassName *appDelegate = [[UIApplication sharedApplication] delegate];
NSLog(#"lat = %#, long = %#", appDelegate.latitude, appDelegate.longitude);
Or you can access them anywhere from the user defaults:
[[NSUserDefaults standardUserDefaults] objectForKey:#"latitude"];
[[NSUserDefaults standardUserDefaults] objectForKey:#"longitude"];
I hope that helps.