I am really new to Xcode iOS development.
I am implementing search with "auto-complete".(Asynchronously sending request to the server for each letter user has inserted and by this connection, I am fetching requested data from the server).
this part works pretty fine :)
My issue is to represent the search result in the table view , I googled a lot
but I couldn't find any good example that would help me.
when the tableView draws for first time everything is fine , but when I fetch another request:
(once the second key is pressed the request returns new data and i want to draw it in the table,without the previous data).
My application crashes with the exception "incorrect selector sent to instance 0x..."
I am storing the fetched data in NSArray *FetchedData;
afterwards I changed:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection: (NSInteger)section
{
return [FetchedData count];
}
And in other function (I think I have to change something here but I don't know what).
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
cell.cellName.text = (NSString*)[FetchedData objectAtIndex:indexPath.row];
return cell;
}
After I getting the FetchedData I call the function:
[self.tableView reloadData];
but in the function above I am crashing after I trying to represent the next fetched data
that is different from the previous (it can even be empty)
I think I might need to delete all the previous cells,
but I don't know how to do so .(I tried some codes from google and from this site ,but I lack basic knowledge,I keep getting all the possible exceptions).
Please can some one give me a decent example with basic explanations ?I would very much appreciate it
Thanks.
You need to register your tableViewCell class somewhere (viewDidLoad),
[self.tableView registerClass:[CustomTableViewCellClass class] forCellReuseIdentifier:#"CellResuseIdentifier"];
and then in,
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath
{
CustomTableViewCellClass *cell = [self.tableView dequeueReusableCellWithIdentifier:#"CellReuseIdentifier"];
cell.cellName.text = (NSString*)[FetchedData objectAtIndex:indexPath.row];
return cell;
}
After you have fetched your data, call
[self.tableView reloadData];
Related
im working on a Game in Unity and want to Safes the User data in Firebase Realtime Database (Will just call it Firebase from now on).
I came up with the idea to create a GameObject, attach a Script (https://github.com/xBarkeeper/2DRun/blob/main/Assets/MainMenu/Scripts/MonoUser.cs) to it and load the Data in the Start scene. The Script had the ValueChanged Method from FireBase in it, so every time data in Firebase changed, it also get updated in the GameObject.
My Plan was to pass this GameObject through my entire Game, so i don't habe to matter about the Userdata anymore.
No I have two Problems with it:
When I move the Object from one Scene to another, the ValueChanged Method is not working anymore. (Not listening to the FireBase)
When I have a other GameObject that is using FireBase, it works completely fine until I use setDataBaseValues or ContinueWithOnMainThread. Both of them first runs when I stop my unity run. But then work successfully.
I don't really know what Code I should attach to this question.
For Example to Problem 2:
Debug.Log("Log 1");
DatabaseReference databaseReference = FirebaseDatabase.DefaultInstance.RootReference;
Debug.Log("Log 2");
this.userName = userName;
FirebaseDatabase.DefaultInstance
.GetReference(userName)
.GetValueAsync().ContinueWithOnMainThread(task =>
{
if (task.IsFaulted)
{
Debug.Log("Log 3");
}
else if (task.IsCompleted)
{
DataSnapshot snapshot = task.Result;
Debug.Log("Log 4");
this.uuid = snapshot.Child("uuid").GetValue(true).ToString();
Debug.Log("Log 5");
}
});
Log 2 is called directly. Log 4 is printed when I end my Game.
Also tried have a Scene loaded through my entire Game with the GameObject attached. But in the moment I load a new Scene, it also don't listen to the ValuesChanged Method anymore.
Isn't it possible to send a FireBase Object between Scenes with a working ValuesChanged?
Do I really need to create a FireBase Object in each scene, although then the data must always be downloaded again?
And why the setDatabaseValues Thread starts first on stoping my Unity Game?
For problem 1: is the gameObject marked as "DontDestroyOnLoad"?
When do you register the OnValueChanged () method?
Before doing anything, do you initialize Firebase Database?
For problem 2: use this code by substituting the line before Debug.Log ("Log 5”);
this.uuid = System.Convert.ToString(snapshot.Child("uuid").GetValue(true));
I usually use "Value" instead of "GetValue()", but it should be the same thing.
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if ([HKHealthStore isHealthDataAvailable]){
NSSet *writeDataTypes = [self dataTypesToWrite];
NSSet *readDataTypes = [self dataTypesToRead];
[self.healthStore requestAuthorizationToShareTypes:writeDataTypes readTypes:readDataTypes completion:^(BOOL success, NSError *error) {
NSLog(#"%s",__func__);
if (!success) {
NSLog(#"You didn't allow HealthKit to access these read/write data types. In your app, try to handle this error gracefully when a user decides not to provide access. The error was: %#. If you're using a simulator, try it on a device.", error);
return;
}
dispatch_async(dispatch_get_main_queue(), ^{
// Update the user interface based on the current user's health information.
NSLog(#"=========================== %s",__func__);
});
}];
}
}
requestAuthorizationToShareTypes does not calling back completion method.
I had a similar issue with the permissions box not appearing and hadn't set up the HKHealthStore properly, putting this beforehand fixed it for me
self.healthStore = [[HKHealthStore alloc] init];
Here is a sample implementation that returns types instead of strings as described in the comment section.
-(NSSet*)datatypesToWrite {
NSArray *quantityTypes =
#[HKQuantityTypeIdentifierHeartRate,
HKQuantityTypeIdentifierBodyTemperature,
HKQuantityTypeIdentifierBloodPressureSystolic,
HKQuantityTypeIdentifierBloodPressureDiastolic,
HKQuantityTypeIdentifierRespiratoryRate];
NSMutableArray *hkTypes = [[NSMutableArray alloc] init];
for (NSString *identifier in quantityTypes) {
HKQuantityType *quantType =
[HKObjectType quantityTypeForIdentifier:identifier];
[hkTypes addObject:quantType];
}
// Make sure the types are of the correct style (Quantity, Category, Etc.)
HKCategoryType *catType =
[HKObjectType categoryTypeForIdentifier:HKCategoryTypeIdentifierSleepAnalysis];
[hkTypes addObject:catType];
return [[NSSet alloc] initWithArray:hkTypes];
}
Each time you request new types for the first time the modal permissions dialog will show up (but it won't show up again if you re-prompt for permissions not granted). Apple's guidelines are to prompt for everything you might need, but it feels a bit against best practices to me to request 12 types up front if I know somebody only asked to save into a few of them.
our application shows interstitial iAds after each played level.
At the moment a level finishes, we create the ad:
_interstitial = [[ADInterstitialAd alloc] init];
_interstitial.delegate = self;
and the delegate implements the following callback methods:
- (void)interstitialAdDidUnload:(ADInterstitialAd *)interstitialAd
{
[self finish];
}
- (void)interstitialAd:(ADInterstitialAd *)interstitialAd didFailWithError:(NSError *)error
{
[self finish];
}
- (void)interstitialAdDidLoad:(ADInterstitialAd *)interstitialAd
{
[_interstitial presentFromViewController:self];
}
- (void)interstitialAdActionDidFinish:(ADInterstitialAd *)interstitialAd
{
[self finish];
}
whereas the finish method cleans up things and forwards the user to the main menu.
from the moment the ad object is created until the finish method is called, a spinning wheel is displayed on the screen.
Now the thing is that if no ad is loaded (for example if no internet connection is available) none of the callback functions ever gets called, so we also add a NSTimer when creating the Ad and check back after 10 seconds, like this:
_interstitial = [[ADInterstitialAd alloc] init];
_interstitial.delegate = self;
_timer = [NSTimer scheduledTimerWithTimeInterval:10
target:self
selector:#selector(checkForAds:)
userInfo:nil
repeats:false];
-(void)checkForAds:(NSTimer *)timer
{
[_timer invalidate];
if(!_interstitial.loaded)
[self finish];
}
but this seems very unclean - and also it leads to a 10 seconds spinning wheel delay after each level if no internet connection is available for example (or if the connection is very bad).
so, my questions:
what's the proper way to deal with this? I feel a timer here is not the right thing.
I'm currently considering to create the Ad object before the level starts, and then after the level finishes immediately check the _interstitial.loaded property and show the ad in this case or skip over it otherwise, without using a timer. The problem is that a level session can take quite long (between 1 and 60 minutes I'd say) and I read that ads can expire, however there is no indication in the documentation how long it usually takes until ads expire and what happens in this case. Will the _interstitial.loaded property return false if the ad expired in the meantime in the background? is some callback function called when the ad expires? Is it a viable approach to create the ad object before a level starts (that is, 1-60 minutes before the ad actually gets displayed) and later just check if _interstitial.loaded is true and in this case display the ad?
The error we're getting is something like this:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_CDSnapshot_Widget_ unlockObjectStore]: unrecognized selector sent to instance 0x1c5a4350'
sometimes the Widget class is sent that selector, sometimes it's __NSCFString, sometimes the crash is this:
[NSManagedObjectContext unlockObjectStore]: message sent to deallocated instance 0x1ec658c0
I think I've narrowed down where the issue is occurring, but I have no idea why this code would be causing it.
Here's an example structure of our data access classes:
// DataController.m
static NSPersistentStoreCoordinator *_persistentStoreCoordinator;
static NSManagedObjectModel *_managedObjectModel;
static NSManagedObjectContext *_mainManagedObjectContext;
#implementation DataController
- (NSManagedObjectContext *) privateManagedObjectContext {
return [DataController buildManagedObjectContextForConcurrencyType:NSPrivateQueueConcurrencyType];
}
- (NSManagedObjectContext *) defaultManagedObjectContext {
return [self managedObjectContextForConcurrencyType: self.defaultConcurrencyType];
}
- (NSManagedObjectContext *) managedObjectContextForConcurrencyType: (NSManagedObjectContextConcurrencyType) type {
if (type == NSMainQueueConcurrencyType)
return [self mainManagedObjectContext];
else if (type == NSPrivateQueueConcurrencyType)
return [self privateManagedObjectContext];
return nil;
}
// calling _dataController.defaultManagedObjectContext from within the Widgets class
// essentially calls this method for a new context using NSPrivateQueueConcurrencyType as
// the type parameter
+ (NSManagedObjectContext *) buildManagedObjectContextForConcurrencyType: (NSManagedObjectContextConcurrencyType) type {
NSManagedObjectContext *context = [[NSManagedObjectContext alloc] initWithConcurrencyType: type];
[context setUndoManager: nil];
[context setMergePolicy: NSMergeByPropertyObjectTrumpMergePolicy];
[context setPersistentStoreCoordinator: _persistentStoreCoordinator];
return context;
}
#end
and our widgets class
// Widgets.m
static DataController *_dataController;
#implementation Widgets
+ (void) initialize {
_dataController = [[DataController alloc] init];
}
+ (NSArray *)certainWidgets {
return [self certainWidgetsInManagedObjectContext:_dataController.defaultManagedObjectContext];
}
+ (NSArray *) certainWidgetsInManagedObjectContext: (NSManagedObjectContext *) context {
// boiler plate CoreData fetching code
}
#end
This is an example of code used to fetch widgets
dispatch_async(dispatch_get_global_queue(0, 0), ^{
for (Widget *w in [Widgets certainWidgets]) {
if ([w.isValid intValue]) {
// do something extraoridarily fantastic with the widget
}
}
});
This only happens in Xcode 4.6, Release mode (not in Debug). We're not seeing anything in the Xcode 4.6 release notes that would give us a clue as to what's happening.
I suspect the issue has to do with how we've structured our data access class (DataController) coupled with the fact that we're using class methods to handle all data access within the Widgets class. The reason for my suspicion is that when we remove the class methods from the Widgets class and make them instance methods instead, get rid of the +initialize method, and set up an NSManagedObjectContext for each instance of the Widgets class, the problem seems to go away.
Just to clarify, I think I've fixed the issue, but I'm not comfortable pushing out the fix until I understand why the above mentioned changes fix it. It looks like there's some sort of memory issue or bad programming paradigm that we're not catching onto. Any pointers?
Turns out this is a bug related to CLang optimizations. We've found a few other people experiencing the same problem. Turning all optimizations off seems to fix the issue.
It happens, for us, when creating a static data management instance, spawning a new thread, and using that static instance to create a managed object context.
Our fix will be to rethink our data management paradigm.
If you're using this screen over your app, or it appears several time & crashes on second one than check your memory management over this screen. It may be the case, when you're holding in memory several copies of screen. Check notification centre removal observer for example.
BLUF: Google Analytics iOS v2 beta 4 misses tracking my first UIViewController that is loaded while hitting successfully on subsequent UIViewControllers (subclassed with GAITrackedViewController)
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// Optional: automatically send uncaught exceptions to Google Analytics.
[GAI sharedInstance].trackUncaughtExceptions = YES;
// Optional: set Google Analytics dispatch interval to e.g. 20 seconds.
[GAI sharedInstance].dispatchInterval = 0;
// Optional: set debug to YES for extra debugging information.
[GAI sharedInstance].debug = YES;
// Create tracker instance.
[[GAI sharedInstance] trackerWithTrackingId:#"UA-########-1"]; // id<GAITracker> tracker =
return YES;
}
MainViewController.m
- (void)viewDidLoad
{
NSLog(#"viewDidLoad");
[super viewDidLoad];
self.trackedViewName = #"First Screen";
//[[GAI sharedInstance] dispatch];
...
}
I do not call dispatch manually on the working UIViewController's, and I have tried both calling and not calling on the non-working. But it is a mystery. No logs are generated if I don't call it manually. When I do call dispatch manually I receive the following:
GoogleAnalytics 2.0b4 -[GAIDispatcher initiateDispatch:retryNumber:]
(GAIDispatcher.m:481) DEBUG: No pending hits.
Thanks in advance!
Turns out that you should really make sure that if you override any methods, you should make sure to call super on them as well...
I had written my own viewDidAppear method but had not called [super viewDidAppear:animated];. I guess that is where GoogleAnalytics does their magic. Hopefully this will help someone else not do this as well.
in my Case , I did call super method , but it did not work at some pages .
and I just change the order and let GA before the super method , It did work now .
- (void)viewDidAppear:(BOOL)animated {
self.screenName = #"mainMenu";
[super viewDidAppear:animated];
}
Contrary to Shu Zhang answer: super should be called first and then you should add other code:
- (void)viewDidLoad
{
[super viewDidLoad];
self.screenName = #"YourViewControllerName";
//your implementation here
}
- (void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
///your implementation here...
}