Associated objects inUIAlertView in iOS - ios

Associated objects are used for creating property in iOS and some cunning changes in iOS. Would anyone care to explain how is this doing any of these?
- (IBAction)doSomething:(id)sender {
UIAlertView *alert = [[UIAlertView alloc]
initWithTitle:#"Alert" message:nil
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:nil];
objc_setAssociatedObject(alert, &kRepresentedObject,
sender,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
[alert show];
}
- (void)alertView:(UIAlertView *)alertView
clickedButtonAtIndex:(NSInteger)buttonIndex {
UIButton *sender = objc_getAssociatedObject(alertView,
&kRepresentedObject);
self.buttonLabel.text = [[sender titleLabel] text];
}
The apple's definition does not help me understand either. "Sets an associated value for a given object using a given key and association policy."

As per my knowledge you can that we can add new property at runtime in existing class object.It allow objects to associate arbitrary values for keys at runtime.
Associated Objects—or Associative References, as they were originally
known—are a feature of the Objective-C 2.0 runtime, introduced in OS X
Snow Leopard (available in iOS 4). The term refers to the following
three C functions declared in , which allow objects to
associate arbitrary values for keys at runtime:
objc_setAssociatedObject
objc_getAssociatedObject
objc_removeAssociatedObjects
Why we use this ? as its allow us to add custom property to existing class and can utilize where it required and after that we will remove that property at runtime.
As per your Usage here you can say that there is no sender property in UIAlertView class and you haven't rights to change UIAlertView so by the use of associateObject you can add run time property which you needed while alert delegate will call.
objc_setAssociatedObject(alert, &kRepresentedObject,
sender,
OBJC_ASSOCIATION_RETAIN_NONATOMIC);
This will add it runtime and we can also remove it after its usage at runtime.
You can find more detail on this link : AssociatedObject
Hope this will helps to understand AssociatedObject concept at runtime.

Related

SweetAlert-iOS in Objective-C

I'm trying to use this great library https://github.com/codestergit/SweetAlert-iOS
I'm managed to use it in Objective-C (it's coded in Swift) but is not working. My code is this.
SweetAlert* alert = [[SweetAlert alloc] init];
[alert showAlert:#"Hello"];
Not only the alert is not shown, but the other methods the .Swift has like "showAlert with subtitile" and many more are not exposed.
Did anyone manage yo make it work?

iOS 7.1 app is crashing in showing alert view

I have used alertview many times but currently i have an issue. My app is working in all the version except it is crashing in iOS 7.1. Below is the log message.
[_UIBarBackgroundCustomImageContainer image]: message sent to deallocated instance 0x13b88840
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Title" #"Test" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
[alert show];
I don't understand why it is only crashing in iOS 7.1
Are you sure to be on main thread ?
You can test it like this : [NSThread isMainThread];
As requested by the OP I have just moved my comments to be an answer.
There are a few issues wrong with the following line:
[[UIAlertView alloc]initWithTitle:#"TestTitle" #"Test" delegate:self cancelButtonTitle:kActionOk otherButtonTitles:nil, nil];
just replace it with
[[UIAlertView alloc]initWithTitle:#"TestTitle" message:#"Test" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
As for what the issues are with that line, they are:
1) The method initWithTitle:delegate:cancelButtonTitle:otherButtonTitles: isn't a real instance method for UIAlertView so it shouldn't work in any iOS where as you have said it does work in iOS versions prior to 7. The method that you should be using is initWithTitle:message:delegate:cancelButtonTitle:otherButtonTitles: notice the extra parameter message: this is the main issue and should create a compiler error and if it got passed that should throw a runtime error of unrecognised selector.
2) The second is is that you have two nils being passed in for the last parameter for otherButtonTitle:, this parameter is nil terminated so as soon as it sees nil it will end what can be passed into that parameter so the second nil is pointless and never seen. This also may create a compiler error but would be in the shadows of the first issue (1)
For more information in regards to UIAlertView please the Apple Documentation on UIAlertView

Observe NSLog messages in Xcode

I'm debugging a 3rd party SDK which puts lot of useful information into the console.
I used to display some messages in tooltips (for our tester), which I'm receiving from SDK delegate.
But delegate methods don't include many details and sometimes it turns helpless, otherwise console includes much more helpful information (especially if the SDK's log level is set to DEBUG_ALL or something like that).
So, my question - is it possible to observe NSLog messages and to be notified in some way when they are printed to console? Of course I would like to have string message as a parameter?
I would like to display it on device/simulator screen, so that the tester doesn't have to run XCode or view the device's console.
I'm using iConsole for the same purpose. It's quite useful.
What SDK? If the SDK supports CocoaLumberjack, then I suggest installing that, and configuring the loggers to do what you want -- even route somewhere else.
CocoaLumberjack gives you a lot of power and configurability when it comes to logging.
If your SDK uses NSLog to print the details in the console, then you can use macros to redefine the NSLog.
#define NSLog(FORMAT, ...) ShowLogInAlert(FORMAT);
void ShowLogInAlert(NSString *format, ...){
//show the log in the alert here.
va_list ap;
va_start (ap, format);
format = [format stringByAppendingString:#"\n"];
NSString *msg = [[NSString alloc] initWithFormat:[NSString stringWithFormat:#"%#",format] arguments:ap];
// NSLog(#"%#", msg);
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:msg message:#"" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alert show];
va_end (ap);
}

ios 6.0 new addressbook ABAddressBookRequestAccessWithCompletion

I want to ask that how I can detect whether my AddressBook was first accessed by an app on ios6.0. I have learnt that no matter an app was reinstalled or not , the system only thinks that the first installation an first launch is the first time an app launched. the question is that I want to remind an user to allow the app access AddressBook with an UIAlertView,but this alertview will appear shortly after the system's alertview .How can I avoid this condition. Any help will be greatly appreciated.
You should basically ignore ABAddressBookRequestAccessWithCompletion. It is useless. If you want to know whether you have access to the database, call ABAddressBookGetAuthorizationStatus().
Further Discussion
ABAddressBookRequestAccessWithCompletion is said by the docs to request address book access from the user. But it doesn't. I will now demonstrate that ABAddressBookRequestAccessWithCompletion is useless. There are two situations:
(1) If this is a completely unknown new app, ABAddressBookRequestAccessWithCompletion is otiose: access will be requested from the user automatically when the app tries to access the address book, so there is no need for ABAddressBookRequestAccessWithCompletion.
(2) If the user has either denied or granted access, ABAddressBookRequestAccessWithCompletion is a no-op! Calling it does nothing; it does not put up the access request alert!
So ABAddressBookRequestAccessWithCompletion is just a bug and should be ignored.
A Major Correction
EDIT In iOS 6.1, this behavior appears to have changed. (I am assuming that my tests on iOS 6.0 were valid, but I have every reason to believe they were.) Now, however, in iOS 6.1, ABAddressBookCreateWithOptions never causes the authorization alert to appear. The only way to make it appear is with ABAddressBookRequestAccessWithCompletion! Thus this function is now essential; if ABAddressBookGetAuthorizationStatus that access is undetermined, you must call ABAddressBookRequestAccessWithCompletion or you won't get access.
I have solved it by this way.
__block BOOL accessGranted;
- (IBAction)accessAddressBook:(id)sender {
CFErrorRef error;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL,&error);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
// accessGranted = granted;
if (!accessGranted && !granted) {
UIAlertView * alertView = [[UIAlertView alloc]initWithTitle:#"Deny Access" message:#"Deny" delegate:self cancelButtonTitle:nil otherButtonTitles:#"cancel", nil];
[alertView show];
[alertView release];
}
});
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if ([alertView.message isEqualToString:#"use contact"] || alertView.message == #"use contact") {
accessGranted = YES;
}
}
The system already shows an alert when you call ABAddressBookRequestAccessWithCompletion()
just augment the system app with your own string.
You should have in your InfoPlist.strings:
"NSContactsUsageDescription" = "Tap 'OK' or this app is useless.";

Using standard Apple translations for Alert button?

Is this true? When you instantiate a UIAlertButton, you have to pass it an explicit title for the Cancel button, like so:
UIAlertView *av =
[[UIAlertView alloc]
initWithTitle:#"Error"
message:err.localizedDescription
delegate:nil
cancelButtonTitle:#"Cancel"
otherButtonTitles:nil];
That means that if you want a localized app (which of course you do), you have to localize the Cancel string too, even though Apple has obviously got a canonical translation already. Am I really forced to write something like this to handle it (or is this even OK)?
NSBundle* uikitBundle = [NSBundle bundleForClass:[UIButton class]];
UIAlertView *av =
[[UIAlertView alloc]
initWithTitle:NSLocalizedString(#"Error", #"Title for Alert box when error occurs")
message:err.localizedDescription
delegate:nil
cancelButtonTitle:NSLocalizedStringFromTableInBundle(#"Cancel", #"Localizable", uikitBundle, nil)
otherButtonTitles:nil];
This looks horrible to me, but the idea that I have to maintain my own translations of words mandated by Apple's HIG (like "Cancel" or "OK") seems equally absurd.
As you expect, that's not recommended as your code introduces an undocumented, unsupported dependency which could break your app if a future iOS update comes along that changes how Apple localizes their UIButton (not very likely, but who knows).
Really, "OK" and "Cancel" are not difficult things to translate. If you don't wish a translator to re-localize these for you as part of your app's localization work then you could retrieve these yourself from iOS (using your code) and copy the translation to your .strings file, so that you'll have a reliable copy of the translation from now on!

Resources