-
Content Count
278 -
Joined
-
Last visited
-
Days Won
30
Everything posted by vfbb
-
Common code base for VCL and FMX control code
vfbb replied to Girish Patil's topic in Cross-platform
I suggest you to create 2 different packages, with the same units, but need to have 2 different packages, one for FMX and one for VCL. After create packages, add in the project options of each package, in the "Conditional defines" something like USING_VCL for the vcl package and USING_FMX for the fmx package.In code of your .pas just use: {$IFDEF USING_VCL} ... {$ENDIF} or {$IFDEF USING_FMX} ... {$ENDIF} -
lookupcombobox Delphi - lookupCombobox - values from relatioship
vfbb replied to Isaac Badru's topic in Delphi IDE and APIs
Depois que as suas tabelas estiverem exatamente da forma como te falei, você poderá usar o seguinte código: var LCountriesIds: TArray<Integer>; LCitiesIds: TArray<Integer>; // Load the cities after country combobox change procedure TForm1.ComboBox1Change(Sender: TObject); begin ComboBox2.Items.Clear; SetLength(LCitiesIds, 0); if ComboBox1.ItemIndex = -1 then Exit; FDQuery1.SQL.Text := 'SELECT city.city_id, city.city_name FROM city WHERE city.country_id=:country_id ORDER BY city.city_name ASC;'; FDQuery1.ParamByName('country_id').AsInteger := LCountriesIds[ComboBox1.ItemIndex]; FDQuery1.Open; try while not FDQuery1.Eof do begin LCitiesIds := LCitiesIds + [FDQuery1.FieldByName('city_id').AsInteger]; ComboBox2.Items.Add(FDQuery1.FieldByName('city_name').AsString); FDQuery1.Next; end; finally FDQuery1.Close; end; end; // Load all countries after form show procedure TForm1.FormShow(Sender: TObject); begin ComboBox1.Items.Clear; SetLength(LCountriesIds, 0); FDQuery1.SQL.Text := 'SELECT country.country_id, country.country_name FROM country ORDER BY country.country_name ASC;'; FDQuery1.Open; try while not FDQuery1.Eof do begin LCountriesIds := LCountriesIds + [FDQuery1.FieldByName('country_id').AsInteger]; ComboBox1.Items.Add(FDQuery1.FieldByName('country_name').AsString); FDQuery1.Next; end; finally FDQuery1.Close; end; ComboBox1Change(nil); end; Entender este simples código é primordial para fazer qualquer query. -
You can not change an signed iOS, MacOS or Android app, if the app is not yours. But if you have the source, the app is your, you have many options to save the resources strings, you can save in particular files for it. When we are talking about resources strings for translation, this will allow the store to make smallest packages of your app, because it will not delivery the unnecessary data to the user. For example, a French language will not be included in a user that use English language ... However, this languages files isn’t usually big, and I personally prefer to make a cross platform solution, languages in the source code. Other solution is storing it in a SQLite.
-
lookupcombobox Delphi - lookupCombobox - values from relatioship
vfbb replied to Isaac Badru's topic in Delphi IDE and APIs
Suas tabelas estão erradas, veja novamente como teria que ser: É sempre melhor executar essas queries dentro do código, você terá mais opções fazendo isso. -
lookupcombobox Delphi - lookupCombobox - values from relatioship
vfbb replied to Isaac Badru's topic in Delphi IDE and APIs
You need 2 tables with this fields city city_id country_id city_name country country_id country_name Get all countries SELECT * FROM country ORDER BY country.country_name ASC; Get all cities with their countries SELECT * FROM city LEFT JOIN country ON city.country_id=country.country_id ORDER BY city.city_name ASC; Get all cities of a specific country (change the XXX to the country number) SELECT * FROM city WHERE city.country_id=XXX ORDER BY city.city_name ASC; -
What is the real purpose? Are the apps from third parties? Perhaps there is a much simpler solution than changing different platform binaries, explain it better.
-
Just search in the web "remove unused css" you will find many tools. Recently, I used the Google Chrome without any extension, just open the DevTools > Sources > Coverage. You will see a report with all unused css codes and javascripts.
-
For random AV, I would say you have a multithreaded application without correct synchronization.
-
Do you really need it at run-time? If not, you will find many tools to do this in the web.
-
The same here. For it to occur less often, avoid use Build, just use Compile.
-
Difference between "Developement" and "Application Store"
vfbb replied to microtronx's topic in Cross-platform
Compile with Android 64 with AAB Bundles enabled and selected the Application Store configuration. But before it, check the Libraries (jar files) of the Android 64 bits, some jar file may be missing. Note: when you compile the AAB, to make the Android 32 and Android 64 packages, the delphi will only consider the jar files from Android64 libraries... I had the same problem, because my Android 32 had the google vision jars but after made the AAP Bundles, in the Android 32 bits the jar files weren’t there. -
Dictionaries, Hashing and Performance
vfbb replied to Clément's topic in Algorithms, Data Structures and Class Design
It depends on the hash algorithm being used but in general it will not make a difference. For the dictionary implemented in delphi, the best capacity is always twice the number of items for known collections and 0 for unknown collections.- 53 replies
-
- tdictionary
- tstringlist
-
(and 2 more)
Tagged with:
-
Dictionaries, Hashing and Performance
vfbb replied to Clément's topic in Algorithms, Data Structures and Class Design
It is not an issue, it is the cost benefit of higher performance x less memory. But the optimization of creating it with the capacity is valid considering that the performance increases is on average 30%, both for small collections and for large ones. uses System.SysUtils, System.Generics.Collections, System.Diagnostics, FMX.Dialogs; procedure TestWithInitialCapacity; var I, J, LNewId: Integer; LDictionary: TDictionary<Integer, Boolean>; LStopwatch: TStopwatch; begin LStopwatch := TStopwatch.StartNew; for I := 0 to 10000 do begin LDictionary := TDictionary<Integer, Boolean>.Create(200); for J := 0 to 100 do begin repeat LNewId := Random(High(Integer)); until not LDictionary.ContainsKey(LNewId); LDictionary.Add(LNewId, True); end; FreeAndNil(LDictionary); end; showmessage(Format('Test with initial capacity: %g', [LStopwatch.Elapsed.TotalMilliseconds])); end; procedure TestWithoutInitialCapacity; var I, J, LNewId: Integer; LDictionary: TDictionary<Integer, Boolean>; LStopwatch: TStopwatch; begin LStopwatch := TStopwatch.StartNew; for I := 0 to 10000 do begin LDictionary := TDictionary<Integer, Boolean>.Create; for J := 0 to 100 do begin repeat LNewId := Random(High(Integer)); until not LDictionary.ContainsKey(LNewId); LDictionary.Add(LNewId, True); end; FreeAndNil(LDictionary); end; showmessage(Format('Test without initial capacity: %g', [LStopwatch.Elapsed.TotalMilliseconds])); end;- 53 replies
-
- tdictionary
- tstringlist
-
(and 2 more)
Tagged with:
-
Dictionaries, Hashing and Performance
vfbb replied to Clément's topic in Algorithms, Data Structures and Class Design
Exactly! The Dictionary is only O(1) in the best case, as there can be many collisions of the key hashes, and this creates a loop that can reach O (n * 3/4) in the worst case, although it is very difficult. But what makes losing more performance are the grows that can occur as teams are added because the implementation maintain the count 50% -75% of the capacity, which I consider high value. But to avoid the many grows, and allow fewer collisions, just create it with the desired capacity. For example, for a collection of 100 items, I simply start with a capacity of 200. LDicionary := TDictionary<TKey, TValue>.Create(200); Remember, when you call Clear from the dictionary, it also removes the capacity, so you better recreate it instead of Clear.- 53 replies
-
- tdictionary
- tstringlist
-
(and 2 more)
Tagged with:
-
@Dave Nottage Hi Dave, I tested and works perfectly!! Thanks you so much, you are the man!! Just to register here the complete solution. (I preferred to patch the delphi source files because I already have others patchs in that files) iOS - Handle incoming url (custom schemes or universal links) In the file iOSapi.Foundation.pas put the code: // Dave Nottage code (https://www.delphiworlds.com/) NSUserActivityPersistentIdentifier = NSString; TNSUserActivityBlockMethod1 = procedure(inputStream: NSInputStream; outputStream: NSOutputStream; error: NSError) of object; TNSUserActivityBlockMethod2 = procedure of object; NSUserActivityClass = interface(NSObjectClass) ['{412EAEBF-5927-4D01-B83F-69D3B5DFE7B5}'] {class} procedure deleteAllSavedUserActivitiesWithCompletionHandler(handler: TNSUserActivityBlockMethod2); cdecl; [MethodName('deleteSavedUserActivitiesWithPersistentIdentifiers:completionHandler:')] {class} procedure deleteSavedUserActivitiesWithPersistentIdentifiers(persistentIdentifiers: NSArray; handler: TNSUserActivityBlockMethod2); cdecl; end; NSUserActivity = interface(NSObject) ['{B8C2F6C9-31FE-4282-B7CA-98C96E163033}'] function activityType: NSString; cdecl; procedure addUserInfoEntriesFromDictionary(otherDictionary: NSDictionary); cdecl; procedure becomeCurrent; cdecl; function delegate: Pointer; cdecl; function expirationDate: NSDate; cdecl; procedure getContinuationStreamsWithCompletionHandler(completionHandler: TNSUserActivityBlockMethod1); cdecl; function initWithActivityType(activityType: NSString): Pointer; cdecl; procedure invalidate; cdecl; function isEligibleForHandoff: Boolean; cdecl; function isEligibleForPrediction: Boolean; cdecl; function isEligibleForPublicIndexing: Boolean; cdecl; function isEligibleForSearch: Boolean; cdecl; function keywords: NSSet; cdecl; function needsSave: Boolean; cdecl; function persistentIdentifier: NSUserActivityPersistentIdentifier; cdecl; function referrerURL: NSURL; cdecl; function requiredUserInfoKeys: NSSet; cdecl; procedure resignCurrent; cdecl; procedure setDelegate(delegate: Pointer); cdecl; procedure setEligibleForHandoff(eligibleForHandoff: Boolean); cdecl; procedure setEligibleForPrediction(eligibleForPrediction: Boolean); cdecl; procedure setEligibleForPublicIndexing(eligibleForPublicIndexing: Boolean); cdecl; procedure setEligibleForSearch(eligibleForSearch: Boolean); cdecl; procedure setExpirationDate(expirationDate: NSDate); cdecl; procedure setKeywords(keywords: NSSet); cdecl; procedure setNeedsSave(needsSave: Boolean); cdecl; procedure setPersistentIdentifier(persistentIdentifier: NSUserActivityPersistentIdentifier); cdecl; procedure setReferrerURL(referrerURL: NSURL); cdecl; procedure setRequiredUserInfoKeys(requiredUserInfoKeys: NSSet); cdecl; procedure setSupportsContinuationStreams(supportsContinuationStreams: Boolean); cdecl; procedure setTargetContentIdentifier(targetContentIdentifier: NSString); cdecl; procedure setTitle(title: NSString); cdecl; procedure setUserInfo(userInfo: NSDictionary); cdecl; procedure setWebpageURL(webpageURL: NSURL); cdecl; function supportsContinuationStreams: Boolean; cdecl; function targetContentIdentifier: NSString; cdecl; function title: NSString; cdecl; function userInfo: NSDictionary; cdecl; function webpageURL: NSURL; cdecl; end; TNSUserActivity = class(TOCGenericImport<NSUserActivityClass, NSUserActivity>) end; ... function NSUserActivityTypeBrowsingWeb: NSString; ... implementation ... function NSUserActivityTypeBrowsingWeb: NSString; begin result := CocoaNSStringConst(FoundationFwk, 'NSUserActivityTypeBrowsingWeb'); end; In the file FMX.Platform.iOS.pas, in the TApplicationDelegate class, in the private section, put the code: class function applicationContinueUserActivityRestorationHandler(self: id; _cmd: SEL; application: PUIApplication; userActivity: Pointer; restorationHandler: Pointer; restorableObjects: Pointer): Boolean; cdecl; static; In the file FMX.Platform.iOS.pas, in the implementation of the method TApplicationDelegate.CreateDelegateMetaClass, before the line "objc_registerClassPair(DelegateClass);", put the code: class_addMethod(DelegateClass, sel_getUid('application:continueUserActivity:restorationHandler:'), @applicationContinueUserActivityRestorationHandler, 'B@:@@@@'); In the file FMX.Platform.iOS.pas, in the TApplicationDelegate implementation, put the code: class function TApplicationDelegate.applicationContinueUserActivityRestorationHandler( self: id; _cmd: SEL; application: PUIApplication; userActivity, restorationHandler, restorableObjects: Pointer): Boolean; var LUserActivity: NSUserActivity; LURLString: string; begin Result := False; if Assigned(userActivity) then begin LUserActivity := TNSUserActivity.Wrap(userActivity); if NSStrToStr(LUserActivity.activityType) = NSStrToStr(NSUserActivityTypeBrowsingWeb) then begin if Assigned(LUserActivity.webpageURL) then LURLString := NSStrToStr(LUserActivity.webpageURL.absoluteString) else LURLString := string.Empty; Result := PlatformCocoaTouch.HandleApplicationEvent(TApplicationEvent.OpenURL, TiOSOpenApplicationContext.Create(string.Empty, LURLString, nil)); end; end; end; Usage uses System.Messaging, FMX.Platform, FMX.Platform.iOS, FMX.Dialogs; constructor TipUrlHandler.Create; begin inherited Create; TMessageManager.DefaultManager.SubscribeToMessage(TApplicationEventMessage, ApplicationEventMessageHandler); end; destructor TipUrlHandler.Destroy; begin TMessageManager.DefaultManager.Unsubscribe(TApplicationEventMessage, ApplicationEventMessageHandler, True); inherited; end; procedure TipUrlHandler.ApplicationEventMessageHandler(const ASender: TObject; const AMessage: TMessage); begin case TApplicationEventData(TApplicationEventMessage(AMessage).Value).Event of TApplicationEvent.OpenUrl: begin Showmessage(TiOSOpenApplicationContext(TApplicationEventData(TApplicationEventMessage(AMessage).Value).Context).URL); end; else end; end;
- 9 replies
-
- ios
- firemonkey
-
(and 6 more)
Tagged with:
-
Out of memory I really like to use Grijjy Cloud Logger. You can monitor all objects in your program in real time, and each time you update this list it will indicate the growth (in number of instances and memory) of each class. Best of all, this can be done in both debug mode and release mode. Use this only in the development environment as there will be a small loss of performance. Move to 64 bits I advise you to start writing code with 64-bit support as soon as possible, this is the future, because although microsoft is not forcing this migration yet, several others have already done it, such as Android, iOS and OSX which today only allow 64 bits. It is a trend even from Embarcadero itself since it added support for Linux only 64 bits. But, of course, keep support for 32-bit too, as there may be users with 32-bit windows still and also because the Win32 debugger is better than Win64. 😉
-
I have a base data class that is used for multithreaded data classess in my project. I made an implementation to reduce thousands of lines of code, which theoretically should work, but even with some successful tests, I am afraid to release a version to the end user without being sure. function TipCustomData.GetSafeValue(var AField: string): string; begin Lock; // Enter critical section try Result := AField; finally Unlock; // Leave critical section end; end; procedure TipCustomData.SetSafeValue(var AField: string; const AValue: string); begin BeginUpdate; // Enter critical section try if AField <> AValue then begin AField := AValue; Change; end; finally EndUpdate; // Leave critical section triggering change event end; end; In the code above, the most intuitive in these cases would be to use the field pointer, but as "var" parameters internally it is already passed as a pointer (regardless of type), so both implementations should work in the same theoretical way (correct me if i'm wrong). Of course, I only access the parameters within the critical section. The implementation of my multithreaded data class, descendant of this, would be for example like this: type TipUser = class(TipCustomData) private FName: string; function GetName: string; procedure SetName(const AValue: string); public property Name: string read GetName write SetName; end; function TipUser.GetName: string; begin Result := GetSafeValue(FName); end; function TipUser.SetName(const AValue: string); begin Result := SetSafeValue(FName, AValue); end; So the question is, is this cleaner implementation that could exist of a multithreaded data class, is it really thread-safe? Sorry for my bad english. 😉
-
FYI: Graph showing iOS crashes with recent Delphi versions
vfbb replied to Hans♫'s topic in Cross-platform
@Hans♫ in the iTunes you can download each user crash report file and view the call stack to identify the problem. You will need to symbolize the crash file using the dSYM file of the version of your app thats crashed. Read about: -
Exploring the .crash files generated by the iOS symbolizing it to identify the call stack https://github.com/viniciusfbb/fmx_tutorials/blob/master/delphi_ios_exploring_app_crashes/README.md
-
Yes, the BeginUpdate call Lock internally, and the EndUpdate call Unlock. The same critical section. Just one critical section per object. Yes, my Change event is completely asynchronous, similar to the fmx messaging system (subscribe / unsubscribe), but it uses X threads to send these messages from one thread to another. I don't like the term "big risk" or "low risk" of deadlock. A good design has to be done with the chance of zero deadlock, locking the object just to copy the data to the local var of the thread or else locking only to write local var of the thread in the object (without executing anything inside locking). Example: procedure TipThread.Execute var LName: string; LId: Cardinal; begin // Read copying to local var LUser.Lock; try LName := LUser.Name; LId := LUser.Id; finally LUser.Unlock; end; // Run your code... // Write from local var LUser.BeginUpdate; try LUser.Name := LName; LUser.Id := LId; finally LUser.EndUpdate; end; end; This will never cause a deadlock.